Search Unity

How to set Matrix as a Property?

Discussion in 'Shaders' started by SpookyCat, Nov 23, 2010.

  1. SpookyCat

    SpookyCat

    Joined:
    Jan 25, 2010
    Posts:
    3,765
    I need to be able to change a matrix in a surface shader I am using, the Matrix, as usual, is a float4x4 but GetMatrix says Material doesn't have a matrix property, so I am assuming somehow you need to add it to the properties Group but there doesn't seem to be support for matrices there, Vector and Float but not matrices. How does one go about exposing the Matrix in the shader so I can use GetMatrix and SetMatrix?
    Thanks
    Chris
     
  2. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,355
    Matrices aren't supported by the Properties block, so they aren't supported in the Material inspector. You can still use Get/SetMatrix() to fill out float4x4 uniforms in your Cg blocks, or any matrices you use as parameters to fixed function commands. As this example code shows, you don't need a definition in Properties to be able to call SetMatrix(): manual for Material.SetMatrix()
     
  3. SpookyCat

    SpookyCat

    Joined:
    Jan 25, 2010
    Posts:
    3,765
    Again thanks Daniel for the help, but as in the Surface Shader from the other problem I was having I do have a a float4x4 declared in the shader and now (with your help) I fill in the data from inside the shader and all works but I need to do this outside the shader from code but when I call GetMatrix("red") Unity gives the error Material doesn't have a matrix property 'red'.

    Could this be because the matrix is in a SurfaceShader and not a normal shader at all? For the shader below I use Matrix4x4 tm = mat.GetMatrix("_mymatrix"); but Unity says _mymatrix doesnt exist, if I try and get Adjust with float adj = mat.GetFloat("_Adjust"); then that works fine. But if I take Adjust out of properties then I can no longer get _Adjust with getfloat it says it doesn't exist.

    Code (csharp):
    1. Shader "Test Shader"
    2. {
    3.     Properties
    4.     {
    5.         _Adjust ("Adjust", Float) = 1.0
    6.     }
    7.  
    8.     SubShader
    9.     {
    10.         Tags { "RenderType"="Opaque"    }
    11.         LOD 200
    12.  
    13.         CGPROGRAM
    14.         #pragma surface surf Test
    15.  
    16.         uniform float4x4 _mymatrix;
    17.         uniform float _Adjust = 1.0;
    18.  
    19.         half4 LightingTest(SurfaceOutput s, half3 lightDir, half atten)
    20.         {
    21.             half4 c;
    22.  
    23.             half4 N = half4(s.Normal, 1.0);
    24.  
    25.             float3 rgb;
    26.             rgb.x = dot(N, mul(_mymatrix, N));
    27.             rgb.y = dot(N, mul(_mymatrix, N));
    28.             rgb.z = dot(N, mul(_mymatrix, N));
    29.  
    30.             c.rgb = rgb * _Adjust;
    31.             c.a = s.Alpha;
    32.             return c;
    33.         }
    34.  
    35.         struct Input {
    36.             float2 uv_MainTex;
    37.         };
    38.  
    39.         void surf (Input IN, inout SurfaceOutput o) {
    40.             half4 c = half4(1, 1, 1, 1);
    41.             o.Albedo = c.rgb;
    42.             o.Alpha = c.a;
    43.         }
    44.     ENDCG
    45.     }
    46.     FallBack "Diffuse"
    47. }
    48.  
     
    Last edited: Nov 23, 2010
  4. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,355
    That could be the problem. I haven't tried to use a matrix in a surface shader yet. Just to be sure, though, you're doing something like this?

    Code (csharp):
    1.  
    2. ...
    3.  
    4. public class ObjectBlur : MonoBehaviour {
    5.     ...
    6.     protected void LateUpdate() {
    7.         Vector4 currentPosition = transform.position;
    8.         currentPosition.w = 1f;
    9.         // Calculate ModelView matrices
    10.         Matrix4x4 _mv = CameraInfo.ViewMatrix*transform.localToWorldMatrix;
    11.         Matrix4x4 _mvPrev = CameraInfo.PrevViewMatrix*m_prevModelMatrix;
    12.         // Give material the matrices it needs
    13. [COLOR="red"]       m_stretchMaterial.SetMatrix("_mv", _mv);
    14.         m_stretchMaterial.SetMatrix("_mvPrev", _mvPrev);
    15.         m_stretchMaterial.SetMatrix("_mvInvTrans", _mv.transpose.inverse);
    16.         m_stretchMaterial.SetMatrix("_mvpPrev", CameraInfo.PrevViewProjMatrix*m_prevModelMatrix);[/COLOR]
    17.         // Record our previous transform
    18.         m_prevModelMatrix = transform.localToWorldMatrix;
    19.     }
    20.    
    21.     ...
    22. }
    And in the shader:
    Code (csharp):
    1. Shader "Hidden/Motion Vectors" {
    2.     SubShader {
    3.         Tags { "RenderType"="Moving" }
    4.         Pass {
    5.             Fog { Mode Off }
    6.             CGPROGRAM
    7.                 #pragma vertex vert
    8.                 #pragma fragment frag
    9.                 #pragma fragmentoption ARB_fog_exp2
    10.                 #pragma fragmentoption ARB_precision_hint_fastest
    11.                 #include "UnityCG.cginc"
    12.                
    13.                 ...
    14.                
    15. [COLOR="red"]               uniform float4x4 _mv;
    16.                 uniform float4x4 _mvPrev;
    17.                 uniform float4x4 _mvInvTrans;
    18.                 uniform float4x4 _mvpPrev;[/COLOR]
    19.                
    20.                 ...
    21.             ENDCG
    22.         }
    23.     }
    24.     ...
    25. }
     
  5. SpookyCat

    SpookyCat

    Joined:
    Jan 25, 2010
    Posts:
    3,765
    Sorry Daniel did an update above. The shader is above and all Iam trying to do at the moment is just use GetMatrix but it says matrix doesnt exist but works fine on the float variable.
     
  6. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,355
    Perhaps a quick explanation of the relationship between Materials and Shaders might help:

    Materials are basically a reference to a shader, and a dictionary of property names to values. When you set a Material to use a specific shader, it will immediately add keys to its dictionary for all the exposed properties in the shader. It won't look at the content of the shader beyond the Properties block, though, so it won't contain values for matrices by default.

    If you're just using GetMatrix(), there won't be anything stored for you to get. If you set a matrix first, though, then it should be added to the dictionary and work for retrieval later.
     
    AndriiVolkov likes this.
  7. SpookyCat

    SpookyCat

    Joined:
    Jan 25, 2010
    Posts:
    3,765
    Again, many thanks Daniel, right again. Where did you get all your shader wisdom?
     
  8. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,355
    Mostly messing about and reading everything I can. I figured out that particular relationship by looking at Materials using the debug mode of the inspector. There you can see that Materials don't actually ever forget their keys. This is useful when you switch from one shader to another, where both share a set of property names. It's a little weird, though, because if you switch between two completely different shaders, all your property values will be saved. This means that if you switch shaders a lot, a Material will accumulate an arbitrary number of property names and values in its dictionary. In practice, though, the benefits of Materials always remembering things outweigh the potential for a (hilarious) memory leak.
     
  9. marius-treu

    marius-treu

    Joined:
    Aug 22, 2012
    Posts:
    25
    oh god damn nice! I've searched like a hundred years to find a solution for this.
    Works fine ty!
     
  10. antislash

    antislash

    Joined:
    Apr 23, 2015
    Posts:
    646
    maybe using 3 "vector" properties?

    i used in properties
    _Matrix1 ("matrix", vector) = (1,1,1,1)
    _Matrix2 ("matrix", vector) = (1,1,1,1)
    _Matrix3 ("matrix", vector) = (1,1,1,1)

    and this in a rotation matrix

    _Matrix1.x , _Matrix1.y, _Matrix1.z,
    _Matrix2.x , _Matrix2.y, _Matrix2.z,
    _Matrix3.x , _Matrix3.y, _Matrix3.z);

    it worked
     
    Last edited: Jun 6, 2015