Problem in vertex rotation

Hi all :slight_smile:

I got a piece of shader code that make object rotation around it’s origin.
Here it is:
Shader “rotate” {
** Properties {**
** _MainTex (“Base (RGB)”, 2D) = “white” {}**
** }**
** SubShader {**
** Tags { “RenderType”=“Opaque” }**
** LOD 200**

CGPROGRAM
** #pragma surface surf Lambert vertex:vertex_program**
#include “UnityCG.cginc”
** sampler2D MainTex;**
** float4x4 rotate(float3 r, float4 d) // r=rotations axes**
** {**
** float cx, cy, cz, sx, sy, sz;**
** sincos(r.x, sx, cx);**
** sincos(r.y, sy, cy);**
** sincos(r.z, sz, cz); **
__ return float4x4( cy*cz, -sz, sy, d.x,
_
__ sz, cxcz, -sx, d.y,__
__ -sy, sx, cx
cy, d.z,__
** 0, 0, 0, d.w ); **
** }**
void vertex_program(inout appdata_full v)
{
** float4x4 rot_mat;**

** rot_mat = rotate(float3(0,_Time.y/3,_Time.x),float4(0,0,0,1));**

** float4 a = v.vertex;**
** float4 b = mul(rot_mat, a);**
** v.vertex = b;**

}
** struct Input {**
** float2 uv_MainTex;**
** };**
** void surf (Input IN, inout SurfaceOutput o)**
** {**
** half4 c = tex2D (_MainTex, IN.uv_MainTex);**
** o.Albedo = c.rgb;**
** o.Alpha = c.a;**
** }**

ENDCG

** }**
}

It works pretty fine when i only rotate on 1 axis ( X or Y or Z ). The problem comes when i want to rotate
the vertex on 2 or 3 axes. It completely messes up the model projection. I suspect, as i’m a matrix math gimp
that the projection parameters in the 4x4 matrix have somthing to do with this.
Maybe someone knowing matrix maths could tell me more please ?
I found nothing about matrices in shaders nor vertex rotations here or on the web…

Maybe if this one works it would help a bit the community ? :wink:

What’s going wrong with those rotations ?

Thanks for your answers !

Your observation is correct, this particular code works best if the rotation is around one of the axes, where x, y, and z of r specify the angles for these rotations. Otherwise it’s a first-order approximation to a combined rotation of rotations around the x, y, and z axes (using the coordinates of r as Euler angles), which assumes that the three angles are close to zero (and therefore products of any two sines of two angles can be neglected). However, this shader uses the matrix for large angles, which doesn’t make any sense to me and can cause all kinds of problems. (This happens when you use stuff outside the specifications! :wink: )

Errrrr… OK.

Well, see Wikipedia for rotation matrices of different conventions for Euler angles: http://en.wikipedia.org/wiki/Euler_angles#Relationship_to_other_representations

Also see Wikipedia for the rotation matrix for a rotation about any axis: http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle

You are welcome.

Oh thanks a lot Martin for all those infos !

As i understand, the ‘rotate’ function is designed for doing a 1 axis rotation only. but matrices
can achieve any rotation on any axis, provided you always keep the same rotation order. Like
X then Y then Z or X then Z then Y etc…

I thought that the problem was coming from the reference i was starting up calculations with…
When entering the vertex_program, do you know what is the reference of v.vertex ? world ?
object ? camera ? projected ? unprojected ? It seems to me that it’s in object ref, but when
rotating 2 or more axis, some crappy projection factors seem to appear. Meaning to me they
are hidden somewhere in the rotation matrix. though i understand most matrix maths ( years ago
i build a whole hierarchical 3D model engine ) i’m still not sure of the reference i’m in…
it’s always important when using matrices to know in which space they evolve, and wether or not
it’s homogeneous… so many questions…

Thanks a lot also for the wiki links :slight_smile: i already knew and saw them but it’s always usefull to
take a look at all thos again. Do you think the “Rotation matrix from axis and angle” from your
second wiki link would do this better ? or maybe quaternions ?
Honestly i don’t have the courage to dive again in all those algebra thingies. Maybe there are
some more comprehensive and less academic tutos about objects rotation in shaders, somewhere
on the web ?

regards and thanks for your help ! :slight_smile:

That’s what’s called Euler angles. It’s most often used to specify the rotation of vehicles (such as airplanes) by roll, pitch and yaw. The (equivalent) alternative is to rotate just once around any axis. In both cases you can compute a single rotation matrix.

v.vertex is in object coordinates (except if you specify uniform scalings but that’s another story).

Depends on how you want to specify rotations: by roll, pitch and yaw or by an axis and an angle?

Quaternions are useful in general but probably not in vertex programs.

It really depends on what you are trying to accomplish. If you just want to specify an arbitrary rotation axis and an rotation angle, the best would be to replace the

return float4x4( cy*cz, -sz, sy, d.x,
sz, cx*cz, -sx, d.y,
-sy, sx, cx*cy, d.z,
0, 0, 0, d.w );

by the corresponding rotation matrix (plus translation in the last column) as described in the Wikipedia article.

(But, of course, the more efficient standard way is to compute the rotation matrix in a script and set the rotation matrix in a uniform of the shader. Thus, you don’t have to compute the rotation matrix for each vertex.)

1 Like

Hello Martin.

ok ok ! Many thanks for all those clues ! It’s so good for a noob like me to be able to talk
with someone really knowing those things :wink:
First of all, what i need if an Euler rotation in Z,Y,Z order that i want.
I confess (many) years ago, i fell in the same trap as i do today with matrix calculations.
And as an old man, i don’t remember of the way i took for the solution, but i know it was
yaw pitch and roll as it was for aicraft simulators.
Finally i replaced my ‘only 1 axis at a time’ matrix with this one:

return float4x4(cy*cz,		-cy*sz,		sy,	d.x,
	        cx*sz+cz*sx*sy,	cx*cz-sx*sy*sz,	-cy*sx,	d.y,
	        sx*sz-cx*cz*sy,	cx*sy*sz+cz*sx,	cx*cy,	d.z,
	        0,              0,		0,	1);

And it does the thing pretty well :smile:
Now i got to also rotate normal to get a correct lighning and that’s all.

Thanks a lot for all you help Martin :smile:
And have a nice day !

Edit: Just one last question:
Do you think that matrix building inside shader is heavier than in a script
executed by the CPU ? I got say… 50 models each with 300 vertex to display
at a time. Till now it runs on the cpu through a C# script. I thought that setting
this up in a shader would lower CPU charge, and bruden a bit the GPU…
What do you think about this ?

1 Like

Actually, looking at the code again, I’m now confused about whether you are actually specifying the transposed matrix … but then, as I explained in another posting, I probably will never learn working with matrices in Cg. :slight_smile:

With only 300 vertices you might reach a break-even but I would still assume that it would be faster to have the matrix building inside a C# script: the vertex shader is executed once for each vertex (i.e. 300 times per model) while the script would be executed only once for each model. Thus, unless your GPU is 300 times faster than C# code (which it might actually be), doing the matrix building inside the shader won’t help performance.

Cheers this helped me work out something similar.