Vertex shaders and various coordinate systems, different ways of normal traf

This topic is 4885 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

Hi all, now I have seen many shaders and I can hardly find two which do normal transformation in the same way. As far as I know, the normal should be rotated with the object (that is, multiplied by the upper 3x3 part of the World matrix of the object), and normalized. This is exatly what is done in here: http://www.toymaker.info/Games/html/vertex_shaders.html
float3 N = normalize(mul(Norm, (float3x3)WorldView)); // normal (view space)


Others do it by multiplying with the inverted, transposed world matrix, eg. here: http://www.gamedev.net/columns/hardcore/dxshader2/page3.asp
; transform normal
dp3 r1.x, v3, c[INVERSE_WORLD_MATRIX]
dp3 r1.y, v3, c[INVERSE_WORLD_MATRIX_1]
dp3 r1.z, v3, c[INVERSE_WORLD_MATRIX_2]

; renormalize it
dp3 r1.w, r1, r1
rsq r1.w, r1.w
mul r1, r1, r1.w


(I beleive this is the same but I don't have the book Real-time Rendering for an explanation) Thenk, here comes another from the same author: http://www.gamasutra.com/features/20030418/engel_pfv.htm
float4x4 matWorldViewProj;
float4x4 matWorld;
float4 vecLightDir;

struct VS_OUTPUT
{
float4 Pos : POSITION;
float3 Light : TEXCOORD0;
float3 Norm : TEXCOORD1;
};

VS_OUTPUT VS(float4 Pos : POSITION, float3 Normal : NORMAL)
{
VS_OUTPUT Out = (VS_OUTPUT)0;
Out.Pos = mul(Pos, matWorldViewProj); // transform Position
Out.Light = vecLightDir; // output light vector
Out.Norm = normalize(mul(Normal, matWorld)); // transform       Normal and normalize it
return Out;
}


He simply multiplies the Normal with the World matrix! Why? The other thing that causes a confusion in my mind is this: how should I decide the coordinate system into which I transform everything and do my computations there. Some use the global coord system (that is, they multiply position with World), others use View space (they multiply with WorldView), others use tangent space... To make more confusion, some RenderMonkey samples assume that my mesh is in the origo so they don't use the Wolrd matrix at all! I would be very happy if someone could clear up these things. Thanks, kp

Share on other sites
Rule #1: "for an operation involving two vectors, both vectors should be in the same space".

Rule #2: "for the best performance, use whichever space requires the least overall computation effort, it doesn't matter which".

Those are the two main rules to follow; quite often example/tutorial code doesn't follow the second rule for reasons of keeping the code easy to understand.

The light direction and/or position for a scene is usually stored in world space, and the normal vectors for your untransformed model are usually in model space (aka object space). Simple Lambertian diffuse lighting requires a dot product between a light direction vector and a normal; because of rule #1, either the light needs to be transformed into the same space as the normal OR the normal needs to be transformed into the same space as the light.

Consider a mesh with 1000 vertices and a single directional light being used in a simple L.N:

- to transform the normal into the same space as the light, we must transform 1000 normals to get them from object space into world space (i.e. transform by the world matrix).

- to transform the light into the same space as the object, we must transform 1 light into object space (i.e. transform by the inverse of the world matrix)

1000 computations vs 1 computation for a simple diffuse light means in this case, lighting in object space is more efficient; but doing it world space is more understandable if its in a tutorial.

If the top left 3x3 part of a matrix ONLY contains rotations and no non-uniform scales or skews, the the inverse of that top left 3x3 part is the SAME as the transpose of that top left 3x3 part. Both cancel each other and the inverse transpose ends up as just the top left 3x3 part of the world matrix again!

The "inverse transpose" for transforming normals is only necessary if the top left 3x3 part of the matrix contains scales or skews; I don't have the time to go through the maths for that now unfortunately (end of lunch break, back to work).

But basically, if you *know* ahead of time that your world matrix doesn't contain skews or non-uniform scaling, then you don't need to transform normals with the inverse transpose; if you don't know, then you do need to transform by it. Most of the time you DO know (or can ensure your artists create content that doesn't scale/skew).

Share on other sites
Hi and thanks for your help!

Now I cas understand some things. But: if I do the transformation in the vertex shader then it doesn't matter whether I transform light or normals, since the vertex shader will run 1000 times anyway unless I do the transformation before passing it to the shader.. maybe this is what you told me? :)

And I still don;t understand the last shader, since it multiplies the normal with thw whole World matrix, thus it applies translation too! It will crash that vector, right?

kp

Share on other sites
Quote:
 Original post by kovacspNow I cas understand some things. But: if I do the transformation in the vertex shader then it doesn't matter whether I transform light or normals, since the vertex shader will run 1000 times anyway unless I do the transformation before passing it to the shader.. maybe this is what you told me? :)

Yes, the idea is one vector * matrix transformation using the CPU to transform the light vector into object space saves you having to do 1000 vector * matrix transformations in the vertex shader.

Quote:
 And I still don;t understand the last shader, since it multiplies the normal with thw whole World matrix, thus it applies translation too! It will crash that vector, right?

Correct, a normal should only be rotated, it shouldn't have translation applied to it. However in the sample code for the article you linked, the object is only ever rotated using a trackball; no translations are performed on it so the translation part of the matrix is always 0,0,0. Transforming a vector by a 4x4 matrix where it's translation part is 0,0,0 is identical to transforming by the top left 3x3 part of that matrix.

Share on other sites
thank you again!

now everything is ok :)

kp

1. 1
2. 2
Rutin
16
3. 3
4. 4
5. 5

• 26
• 11
• 9
• 9
• 11
• Forum Statistics

• Total Topics
633710
• Total Posts
3013482
×