Search Unity

  1. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice

Problem in vertex rotation

Discussion in 'Shaders' started by pitibonom, Sep 5, 2011.

  1. pitibonom

    pitibonom

    Joined:
    Aug 17, 2010
    Posts:
    174
    Hi all :)

    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, cx*cz, -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 ? ;)

    What's going wrong with those rotations ?

    Thanks for your answers !
     
    Last edited: Sep 5, 2011
  2. Martin-Kraus

    Martin-Kraus

    Joined:
    Feb 18, 2011
    Posts:
    617
    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! ;) )

    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.
     
  3. pitibonom

    pitibonom

    Joined:
    Aug 17, 2010
    Posts:
    174
    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 :) 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 ! :)
     
    Last edited: Sep 6, 2011
  4. Martin-Kraus

    Martin-Kraus

    Joined:
    Feb 18, 2011
    Posts:
    617
    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
    Code (csharp):
    1.  
    2. return float4x4( cy*cz, -sz, sy, d.x,
    3. sz, cx*cz, -sx, d.y,
    4. -sy, sx, cx*cy, d.z,
    5. 0, 0, 0, d.w );
    6.  
    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.)
     
    Last edited: Sep 6, 2011
    image28 likes this.
  5. pitibonom

    pitibonom

    Joined:
    Aug 17, 2010
    Posts:
    174
    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 ;)
    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:
    Code (csharp):
    1.  
    2. return float4x4(cy*cz,      -cy*sz,     sy, d.x,
    3.             cx*sz+cz*sx*sy, cx*cz-sx*sy*sz, -cy*sx, d.y,
    4.             sx*sz-cx*cz*sy, cx*sy*sz+cz*sx, cx*cy,  d.z,
    5.             0,              0,      01);
    6.  
    And it does the thing pretty well :D
    Now i got to also rotate normal to get a correct lighning and that's all.

    Thanks a lot for all you help Martin :D
    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 ?
     
    Last edited: Sep 6, 2011
    image28 likes this.
  6. Martin-Kraus

    Martin-Kraus

    Joined:
    Feb 18, 2011
    Posts:
    617
    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. :)

    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.
     
  7. image28

    image28

    Joined:
    Jul 17, 2013
    Posts:
    457
    Cheers this helped me work out something similar.
     
unityunity