Search Unity

Rotating mesh in vertex shader

Discussion in 'Shaders' started by 00christian00, Oct 25, 2017.

  1. 00christian00

    00christian00

    Joined:
    Jul 22, 2012
    Posts:
    1,035
    I am trying to rotate a mesh with vertex shader.
    I found this snippet and I am using it to rotate the mesh:
    And in the vertex shader I do this, where v is the input struct and o is the output:
    Problem is it is rotating around the world axis and not the mesh pivot. Why is it so if I am doing it before doing the UnityObjectToClipPos? I should be in object space. What am I missing?
     
  2. brownboot67

    brownboot67

    Joined:
    Jan 5, 2013
    Posts:
    375
    Is your mesh dynamically batched or part of a canvas?
     
    00christian00 likes this.
  3. 00christian00

    00christian00

    Joined:
    Jul 22, 2012
    Posts:
    1,035
    Thanks! That was the problem, it was dynamically batched.

    For completeness, in case somebody is looking to do the same, to disable dynamic batching only for some objects and not globally you can add a tag in the shader "DisableBatching" = "True" .
     
    asdzxcv777, puzzlekings and FeastSC2 like this.
  4. puzzlekings

    puzzlekings

    Joined:
    Sep 6, 2012
    Posts:
    404
    @00christian00 this is really interesting - any chance you could post your shader code up here, as I'm not sure how to put the rest of this together to rotate the mesh?
     
    00christian00 likes this.
  5. 00christian00

    00christian00

    Joined:
    Jul 22, 2012
    Posts:
    1,035
    I'm not a shader expert to give advice, but anyway here is it. If you need to move automatically you multiply angle per _Time.y at row 49. In that case you will have angle per seconds as input.

    Code (CSharp):
    1. Shader "DiffuseRotate"
    2. {
    3.     Properties
    4.     {
    5.         [NoScaleOffset] _MainTex ("Texture", 2D) = "white" {}
    6.         _Angle ("Angle", float) = 1
    7.     }
    8.     SubShader
    9.     {
    10.         Tags {"LightMode"="ForwardBase"}
    11.         Tags { "RenderType"="Opaque" "DisableBatching" = "True"  }
    12.  
    13.         Pass
    14.         {
    15.  
    16.            
    17.             CGPROGRAM
    18.             #pragma vertex vert
    19.             #pragma fragment frag
    20.             #include "UnityCG.cginc"
    21.             #include "Lighting.cginc"
    22.  
    23.             // compile shader into multiple variants, with and without shadows
    24.             // (we don't care about any lightmaps yet, so skip these variants)
    25.             #pragma multi_compile_fwdbase nolightmap nodirlightmap nodynlightmap novertexlight
    26.             // shadow helper functions and macros
    27.             #include "AutoLight.cginc"
    28.         uniform float _Angle;
    29.             struct v2f
    30.             {
    31.                 float2 uv : TEXCOORD0;
    32.                 SHADOW_COORDS(1) // put shadows data into TEXCOORD1
    33.                 fixed3 diff : COLOR0;
    34.                 fixed3 ambient : COLOR1;
    35.                 float4 pos : SV_POSITION;
    36.             };
    37.             float4 RotateAroundYInDegrees (float4 vertex, float degrees)
    38.                  {
    39.                      float alpha = degrees * UNITY_PI / 180.0;
    40.                      float sina, cosa;
    41.                      sincos(alpha, sina, cosa);
    42.                      float2x2 m = float2x2(cosa, -sina, sina, cosa);
    43.                      return float4(mul(m, vertex.xz), vertex.yw).xzyw;
    44.                  }
    45.        
    46.             v2f vert (appdata_base v)
    47.             {
    48.                 v2f o;
    49.                 v.vertex = RotateAroundYInDegrees(v.vertex, _Angle);
    50.                 o.pos = UnityObjectToClipPos(v.vertex);
    51.                 o.uv = v.texcoord;
    52.                 half3 worldNormal = UnityObjectToWorldNormal(v.normal);
    53.                 half nl = max(0, dot(worldNormal, _WorldSpaceLightPos0.xyz));
    54.                 o.diff = nl * _LightColor0.rgb;
    55.                 o.ambient = ShadeSH9(half4(worldNormal,1));
    56.                 // compute shadows data
    57.                 TRANSFER_SHADOW(o)
    58.                 return o;
    59.             }
    60.  
    61.             sampler2D _MainTex;
    62.  
    63.             fixed4 frag (v2f i) : SV_Target
    64.             {
    65.                 fixed4 col = tex2D(_MainTex, i.uv);
    66.                 // compute shadow attenuation (1.0 = fully lit, 0.0 = fully shadowed)
    67.                 fixed shadow = SHADOW_ATTENUATION(i);
    68.                 // darken light's illumination with shadow, keep ambient intact
    69.                 fixed3 lighting = i.diff * shadow + i.ambient;
    70.                 col.rgb *= lighting;
    71.                 return col;
    72.             }
    73.             ENDCG
    74.         }
    75.  
    76.         // shadow casting support
    77.         UsePass "Legacy Shaders/VertexLit/SHADOWCASTER"
    78.  
    79.     }
    80.  
    81. }
     
    dyupa, Martin_Luna and puzzlekings like this.
  6. puzzlekings

    puzzlekings

    Joined:
    Sep 6, 2012
    Posts:
    404
    @00christian00 - that's awesome and many thanks - will check it out as soon as I can!
     
    00christian00 likes this.
  7. NathanJSmith

    NathanJSmith

    Joined:
    May 11, 2018
    Posts:
    57
    Pump!
    Hi @00christian00 , Did you figure how to do this? I'm having the same problem.
    I think the first thing to do is figure out how to get the pivot point of each mesh in particles.
    Thanks.
     
    Last edited: Oct 4, 2018
  8. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    Particles are a different beast. By default particle systems are always batched meshes regardless of if you have disable batching in your shader. Particle systems simply had no other way of working.

    Recently they added custom data streams, which includes the option to pass the particle’s position to each particle in the form of data stored in the mesh UVs. They also added support for instanced particles which give you this data even more readily. You’ll want to look at how the “Particles/Standard Unlit” shader works.
     
    NathanJSmith likes this.
  9. 00christian00

    00christian00

    Joined:
    Jul 22, 2012
    Posts:
    1,035
    Doesn't the shader I posted works for you?
    I didn't work on it anymore.
     
  10. NathanJSmith

    NathanJSmith

    Joined:
    May 11, 2018
    Posts:
    57
    Not exactly, I'm looking for a way to rotate the particle mesh around its pivot like your first post mention
    The problem can be visualized like this

    ----------
    I see there is a Center Vertex stream, I guess this is the Center of each mesh particle

    If this is the center of the mesh, then this is the pivot I want to rotate around. But for now just assume this is the center of the mesh, how can I rotate around this center?
    Here is my approach:
    I generate the rotation matrix.
    Code (CSharp):
    1. float3x3 YRotationMatrix(float degrees, float3 pivot)
    2.             {
    3.                 float alpha = degrees * UNITY_PI / 180.0;
    4.                 float s = sin(alpha);
    5.                 float c = cos(alpha);
    6.                //But how can I insert the pivot???
    7.                 return float3x3(
    8.                     c, 0, -s,
    9.                     0, 1, 0,
    10.                     s, 0, c);
    11.             }
    12.  
    13. appdata_t vert (appdata_t v)
    14. {
    15. float4 pos =  v.vertex;
    16. //v.texcoord1.yzw is the pivot
    17. pos.xyz = mul(YRotationMatrix(180,v.texcoord1.yzw), pos.xyz);
     
    Last edited: Oct 4, 2018
  11. NathanJSmith

    NathanJSmith

    Joined:
    May 11, 2018
    Posts:
    57
    Hi Nathan, Have you ever thought about move the center (vertex) to the root (0,0,0) then rotate the vertex, then move it back?
     
  12. NathanJSmith

    NathanJSmith

    Joined:
    May 11, 2018
    Posts:
    57
    Thank Nathan, I finally figure it out. And my guess is right: Center Vertex stream is the Center of each mesh particle
    Code (CSharp):
    1.  
    2.           float3x3 YRotationMatrix(float degrees)
    3.             {
    4.                 float alpha = degrees * UNITY_PI / 180.0;
    5.                 float sina, cosa;
    6.                 sincos(alpha, sina, cosa);
    7.                 return float3x3(
    8.                     cosa, 0, -sina,
    9.                     0, 1, 0,
    10.                     sina, 0, cosa);
    11.             }
    12.  
    13.             appdata_t vert (appdata_t v)
    14.             {
    15.                 float4 pos = v.vertex;
    16.                 float3 pivot = v.texcoord1.yzw; //Vertex Stream Center
    17.  
    18.                //Move to root
    19.                pos.xyz -= pivot;
    20.              
    21.                //Rotate
    22.                pos.xyz = mul(YRotationMatrix(180), pos.xyz);
    23.              
    24.                //Move it back
    25.                pos.xyz += pivot;
    26.  
    27.                 //Done! now return the result
    28.                 appdata_t o;
    29.                 o.vertex = UnityObjectToClipPos(pos);
    30.  
    31.                 return o;
    32.             }
    Problem solved! :D
     
    Last edited: Oct 4, 2018
  13. 00christian00

    00christian00

    Joined:
    Jul 22, 2012
    Posts:
    1,035
    That issue was solved disabling batching for that shader. The code I posted should have been working.
    Code (CSharp):
    1. Tags { "RenderType"="Opaque" "DisableBatching" = "True"  }
    I think this way is more performant than using vertex stream, since you are not wasting bandwidth between cpu and shader.
     
  14. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    Except, as I stated above, this tag is ignored by particle systems. They are always batched unless you're using a shader with particle system specific instancing code.
     
  15. Carterryan1990

    Carterryan1990

    Joined:
    Dec 29, 2016
    Posts:
    79
    Awsome man! Good job! Would you mind posting the full code? Having troubles my self lol
     
  16. NathanJSmith

    NathanJSmith

    Joined:
    May 11, 2018
    Posts:
    57
    Carterryan1990 likes this.
  17. Carterryan1990

    Carterryan1990

    Joined:
    Dec 29, 2016
    Posts:
    79