0

I start with a normal sphere which I need to deform into an oval-looking shape. I do this by stretching one axis, which in my code will be the y axis.

mat4 ToOvalMat = mat4(vec4(1., 0., 0., 0.),
                      vec4(0., 1.5, 0., 0.),
                      vec4(0., 0., 1., 0.),
                      vec4(0., 0., 0., 1.));

I stretch it by 1.5 multiplied by an input called a. It works well for my intentions, but I still need to figure out a good way to fix the normals and get proper shadows, as they are still tied to the original sphere.

After hunting for an answer on Google I stumpled upon GPU Gems - Deformers, which related to the normals but I don't quite understand the concepts explained. The Jacobian Matrix seems like it would be able to solve my normals problem but I am not so sure and would like some kind of help or feedback regarding my calculation, as it is hard to see from the render in my given test program.

Since I am stretching in the y dimension I have a normal unit matrix of size 4, where I just replace the y 1 with 1.5a. This would be my Jacobian Matrix, if I understood the text properly. Inversing and then transposing this matrix would then be what I would multiply my normals with. Can I also use this on my ShadowMatrix?

Normal = (transpose(inverse(ToOvalMat)) * vec4(VertexNormal, 0.)).xyz;
Normal = normalize((ViewMatrix * WorldMatrix * vec4(Normal, 0.)).xyz);

I am getting some artifacts with these calculations and they are not completely selling it for me in regards to believability, which makes me feel like something is off with my matrices or something. And I completely guessed with the ShadowMatrix as I have not yet looked into it enough yet since I've been stuck on the normals up until now.

Simon
  • 470
  • 1
  • 7
  • 22

1 Answers1

0

I'm not sure about the shadow matrix part. For the normals, calculating the inverse/transposed in the vertex shader is very wasteful. This means that the matrix is potentially calculated for each vertex. If you're fortunate that might get optimized away, but I'd rather not count on it myself.

The cleaner approach IMHO is to pass a separate normal transformation matrix into the shader, and use it to transform the normals. This can be a 3x3 matrix (see my answer here for some more background: OpenGL ES 2.0 an Android: What dimensions should the normalMatrix have?).

You will then calculate the inverse/transpose in your own code on the CPU. For non-uniform scaling, the inverse is a scaling matrix that contains the inverse of the scaling factors, and transposing it does nothing. For your example:

mat3 ToOvalNormalMat = mat3(vec3(1.0f, 0.0f, 0.0f),
                            vec3(0.0f, 1.0f / 1.5f, 0.0f),
                            vec3(0.0f, 0.0f, 1.0f));

See normal matrix for non uniform scaling for more detail about how the normal matrix for non-uniform scaling is calculated.

Community
  • 1
  • 1
Reto Koradi
  • 53,228
  • 8
  • 93
  • 133
  • I know that for this example the transpose does nothing and so inverting the y coord can be done simply by doing what you show, yes. But I'd like to know for a more general answer and I'm trying to learn the process of it when other deformations may occur :) – Simon Apr 23 '15 at 12:25
  • The process is somewhat explained in the answer linked in the last paragraph. You have to calculate the inverse matrix, and then transpose it. Well, there's actually a simpler way. Maybe I should see if I can fit that into one of the answers. – Reto Koradi Apr 23 '15 at 15:47