Search Unity

Passed matrix lose values

Discussion in 'Shaders' started by imaewyn, Jun 21, 2017.

  1. imaewyn

    imaewyn

    Joined:
    Apr 23, 2016
    Posts:
    211
    Hello. I'm trying to pass float4x4 to shader and it works but only until I have no changes in shader code....Why?
    F.E.
    This method pass some matrix in shader
    Code (CSharp):
    1.    
    2. public void PassData()
    3. {
    4.         Matrix4x4 matrix = new Matrix4x4()
    5.         {
    6.             m00 = 13,
    7.             m01 = -124,
    8.             m10 = 12,
    9.             m11 = 11
    10.         };
    11.  
    12.         this.GetComponent<MeshRenderer>().material.SetMatrix("_RotMatrix0", matrix);
    13. }
    14.  
    this is part of shader code
    Code (CSharp):
    1.  
    2. uniform float4x4 _RotMatrix0;
    3. void surf (Input IN, inout SurfaceOutputStandard o)
    4.  {        
    5.             float2 uv = mul(_RotMatrix0, float4(IN.uv_MainTex.xy, 0, 0)).xy;
    6.             fixed4 c = tex2D(_MainTex, uv);
    7.             o.Albedo = c.rgb;
    8.  }
    9.  
    When I set matrix from c# code I open shader and make any changes f. e. I click space button on my keyboard. After that I save shader and return to game view...and my matrix not working...

     
  2. imaewyn

    imaewyn

    Joined:
    Apr 23, 2016
    Posts:
    211
    any ideas?
     
  3. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,339
    Uniform parameters that aren't defined as a shader property are not serialized. In other words any value not in the Properties block of the shader won't be saved on the material, and properties that aren't saved get flushed when the shader updates.

    In editor you may need to apply the value on script update if you want it to "stick", though for this case I would suggest maybe defining the matrix as a Vector property on the material, and converting the float4 in shader to a float2x2 since that's all that's all you need. If you don't want the property to show up in the inspector you can use the [HideInInspector] attribute before the property definition.
     
  4. imaewyn

    imaewyn

    Joined:
    Apr 23, 2016
    Posts:
    211
    Thank you) I think float2x2 will be not enough for rotation matrix (around point).
    I decided to use Shader.SetGlobaMatrix, seems it works.
    Also I would like to know about static variables. Maybe calculate static matrix inside shader will be not bad too?
    If I want to define 4-5 matrices for different angles which way I should use?
     
  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,339
    For rotating around a point in 2D you would need at least a float3x3, but if you're only doing rotation, uniform scale, and position you'd still only need a float4 to pass enough values to construct a float3x3 with zero computation in the shader.
    Code (CSharp):
    1.  
    2. Material.SetVector("_RotMatrix0", new Vector4(posX, posY, rotCos, rotSin));
    3.  
    4. ...
    5.  
    6. float3x3 rotMat = float3x3(
    7.   _RotMatrix0.z, _RotMatrix0.w, _RotMatrix0.x,
    8.   _RotMatrix0.w, -_RotMatrix0.z, _RotMatrix0.y,
    9.   0, 0, 1
    10. );
    11.  
    12. uv = mul(float3(uv, 1), rotMat).xy;
    13.  
    Your example code is only passing a float2x2, so you're not doing any translation, but you are doing a lot of skewing and scaling.
     
  6. imaewyn

    imaewyn

    Joined:
    Apr 23, 2016
    Posts:
    211
    Thank you, I know. It was just example which shows my situation with losing data after saving shader)) Actually I use Matrix4x4.TRS for set to shader and it rotates uv exactly how I want.
    With float4 good Idea, but what about static variables and Shader.SetGlobaMatrix, which I asked in previous post
     
    Last edited: Jun 24, 2017
  7. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,339
    Depends on what you mean by static. If you mean you assign them inline in the shader or use #define, you can do that. Modern GPUs are also really fast at handling uniform conditionals (ie an if or series of if statements testing a material property), so you could have a number of matrices you switch between dynamically for very little cost over a matrix sent to the shader in a uniform. For older hardware that can't do conditionals you could use #ifdef and #pragma multi_compile or #pragma shader_feature and switch between keywords from script or using a [KeywordEnum] attribute.

    Those options are good as alternatives to passing a matrix from script.

    What you shouldn't do is define a variable in the shader with a static variable as it will either have no effect or make your shader slower depending on the hardware you're using.

    Really it all depends on exactly what you need / want. It might even make more sense to use a few pre-set meshes or additional vertex streams depending on what you're doing.