normalize() producing different results

Started by
5 comments, last by Bacterius 10 years, 2 months ago

I've come across something weird in HLSL. Well, maybe it's not that weird, but it was unexpected for me. There's probably a simple explanation. Anyway...

when I do this in my normal mapping shader:

float3 normal = normalize(2.0f*tex2D(TextureSamplerN, PSIn.TexCoords) - 1.0f);

...I get a different result to if I do this:

float3 normal = 2.0f*tex2D(TextureSamplerN, PSIn.TexCoords) - 1.0f;
normal = normalize(normal);

It seems like the latter one produces the correct result when I run my program, but I have no idea why they're different. Any ideas?

Thanks!

Advertisement

In the first snippet you normalize a float4 and then throw away the fourth component, while in the second snippet you throw away the fourth component and then normalize.

The result of the first snippet is not unit length (unless the sampled fourth component is exactly 0.5).

Like Mona mentioned, in both cases you're implicitly truncating a float4 to a float3. This is generally considered bad practice, since it can lead to non-obvious bugs due to dropping data. In fact the compiler will actually warn you when it happens. If your intention is to truncate, I would recommend using a swizzle like this:

float3 normal = normalize(2.0f * tex2D(TextureSamplerN, PSIn.TexCoords).xyz - 1.0f);

This makes the truncation explicit, and in your particular case also prevents the bug that you're encountering.

Ahh, so simple :) Thanks!

Is it ever meaningful to normalize a float4 anyway? Apart from the perspective division I can't think of a situation where you'd want to do that rather than normalize the underlying float3.

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”

Is it ever meaningful to normalize a float4 anyway? Apart from the perspective division I can't think of a situation where you'd want to do that rather than normalize the underlying float3.

For normalizing a vector (or turning a position into a vector), you'd use a float3, for normalizing a quaternion you'd use a float4.

Often in graphics you want to normalize a bunch of weights -- if you've got 4 and your weighting system is based on Euclidean distance, you might find normalizing a float4 handy too biggrin.png

Though usually normalizing weights looks more like weights /= dot(weights, (float4)1)...


For normalizing a vector (or turning a position into a vector), you'd use a float3, for normalizing a quaternion you'd use a float4.

Often in graphics you want to normalize a bunch of weights -- if you've got 4 and your weighting system is based on Euclidean distance, you might find normalizing a float4 handy too
Though usually normalizing weights looks more like weights /= dot(weights, (float4)1)...

I hadn't thought of quaternions, good point!

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”

This topic is closed to new replies.

Advertisement