Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

While rendering a cube to the gbuffer (diffuse, normal, depth) I noticed something odd when applying rotations. I build a world matrix for the cube as follows:

Yaw = Yaw % MathUtil.PI2;
Pitch = Pitch % MathUtil.PI2;
Roll = Roll % MathUtil.PI2;

Matrix4 s = Matrix4.Scale(Scale);
Matrix4 t = Matrix4.CreateTranslation(Position);

Matrix4 rotY = Matrix4.CreateRotationY(Yaw);
Matrix4 rotX = Matrix4.CreateRotationX(Pitch);
Matrix4 rotZ = Matrix4.CreateRotationZ(Roll);

return s * rotY * rotX * rotZ * t;

If I render the cube with scale 1, position 0,0,0 and no rotations my normals are rendered properly. Applying scale/position does not change this fact.

Normals with no transformation

However, when I apply rotations the normals screw up in some cases.

Nothing wrong in these settings:

  • Yaw = Pi/2
  • Yaw = Pi
  • Pitch = Pi/2
  • Pitch = Pi
  • Yaw = Pi && Pitch = Pi

But when I apply these rotations:

  • Yaw = Pi/2 && Pitch = Pi/2

This happens:

Normals with transformation Yaw = Pi/2 && Pitch = Pi/2

For some reason the normals aren't rotated correctly. I rotate them like this in the vertex shader using the world matrix described above:

mat3 WorldMatrix3x3 = mat3(WorldMatrix);
normalWS = vertexNormal_modelspace * WorldMatrix3x3;

And store them in the fragment shader:

rtt_normal.xyz = normalWS * 0.5 + 0.5;

I display the normal buffer on the screen like this:

color = vec4(abs(texture(gbufferTexture, UV).rgb * 2.0 - 1.0), 1);

What am I missing here?

share|improve this question
add comment

1 Answer

up vote 1 down vote accepted

PI/2 is the magic number that causes gimbal lock. A Euler rotation of that value will disrupt subsequent rotations about another axis, because they have overlain each other. You need to replace

Matrix4 rotY = Matrix4.CreateRotationY(Yaw);
Matrix4 rotX = Matrix4.CreateRotationX(Pitch);
Matrix4 rotZ = Matrix4.CreateRotationZ(Roll);
return s * rotY * rotX * rotZ * t;

With something that doesn't suffer from the same problem.

Matrix4 rot = Matrix4.CreateFromAxisAngle(axis, angle)
return s * rot * t;
share|improve this answer
    
Thanks a lot for the great answer and the link. –  Korijn May 26 '13 at 17:49
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.