Open hybridherbst opened 1 year ago
Filed as internal issue #USD-8602
Thanks, @hybridherbst , that sounds like a good generalization to us!
Cool!
I think an interesting detail question would be what the expected math for scaled normals is in USD land (and if there's any convention for it).
E.g. this is what Unity's ShaderGraph uses:
void Unity_NormalStrength_float(float3 In, float Strength, out float3 Out)
{
Out = float3(In.rg * Strength, lerp(1, In.b, saturate(Strength)));
}
But this is in MaterialX:
vec3 B = normalize(cross(N, T));
value.xy *= normal_scale;
value = T * value.x + B * value.y + N * value.z;
So if I'm not mistaken, the result of applying the same normal scale would differ in all scales but 0 and 1... And also looks like normal_scale in MaterialX is ignored in object space in all implementations 👀, interesting.
I like bias == -scale / 2 as a starting spot.
To be a little less restrictive, you might want to include cases where bias == 0 and scale == 1, which can happen with some (quite old style) normal maps for the Z component. That is, they map 0 to 1 input to 0 to 1 output. See the second test case in https://github.com/usd-wg/assets/tree/main/test_assets/NormalsTextureBiasAndScale - happily rare today (no one deeply cares about adding a bit of precision to the Z component, which this allows).
Basically, you could use the rule for normal maps of "if the range 0-1 as input maps to -1 to +1 as output, or some subset of that range such as 0 to 1, then don't give a warning." Assume the user knows what they're doing - they wouldn't set these values otherwise.
Or, to be more restrictive, at least allow only the variant bias=1 and scale=-2 as a reasonable alternate setting for the Y component. This is needed for DirectX-style normal maps - see this section. It's a special, but common enough, case. Any other settings are somewhat less likely, though could be used as a poor-man's way to scale the heights (sort of) of the bumps.
As for my testing, just bias = -scale / 2
won't do – the result will be normalized by applications, and then
normalize(map * 2 - 1) == normalize(map * 0.02 - 0.01)
so in usdview all objects look all the same in the first test (but the one with normals scaled to 0):
while in the second one, which keeps Z at 1, it looks as expected in usdview (at least normals are scaled, as said not sure about the correct math):
Ground truth (Unity):
Hey all, just to jump in and clarify: does the first screenshot above indicate that our rendering is doing the wrong thing with scaled normals? IIRC we apply bias and scale, normalize, transform from tangent space to eye space, and then normalize again.
And is there a synopsis of what scale/bias combos we want to warn about vs accept?
@tcauchois I believe the rendering in usdview is correct – the first screenshot is effectively from a "bad file" where Y is scaled as well, so after normalization all of them look the same. The first black cube is effectively "garbage in, garbage out", – it's basically normals being scaled to 0 and then normalized.
My understanding is that scale/bias have to be chosen and verified in a way that the resulting vector
So I think something along the lines of:
Description of Issue
usdchecker currently always warns when normal scale and bias are not scale=(2,2,2,1) and bias=(-1,-1,-1,0). However, that prevents assets from passing that use scaled normals – e.g. scale=(0.5,0.5,0.5,1) and bias=(-0.25,-0.25,-0.25,0).
I think what usdchecker should check instead is that the data is symmetric, that is,
bias == -scale / 2
.(The math should be a bit different to make sure that results have unit length, so scale=(0,0,0,1) needs bias=(0,1,0,0), but you get the idea)
Steps to Reproduce
Download Needle-MadeWithNeedle-20230818-164137.zipBetter file: Needle-MadeWithNeedle-20230821-083855.usdz.zip
Run through usdchecker
Expected: passes, all normals are symmetric
Actual: complains that e.g. "has non-standard inputs:scale and inputs:bias values"