How to set Matrix as a Property?

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

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()

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.

Shader "Test Shader"
{
    Properties
    {
        _Adjust ("Adjust", Float) = 1.0
    }

    SubShader
    {
        Tags { "RenderType"="Opaque"    }
        LOD 200

        CGPROGRAM
        #pragma surface surf Test

        uniform float4x4 _mymatrix;
        uniform float _Adjust = 1.0;

        half4 LightingTest(SurfaceOutput s, half3 lightDir, half atten)
        {
            half4 c;

            half4 N = half4(s.Normal, 1.0);

            float3 rgb;
            rgb.x = dot(N, mul(_mymatrix, N));
            rgb.y = dot(N, mul(_mymatrix, N));
            rgb.z = dot(N, mul(_mymatrix, N));

            c.rgb = rgb * _Adjust;
            c.a = s.Alpha;
            return c;
        }

        struct Input {
            float2 uv_MainTex;
        };

        void surf (Input IN, inout SurfaceOutput o) {
            half4 c = half4(1, 1, 1, 1);
            o.Albedo = c.rgb;
            o.Alpha = c.a;
        }
    ENDCG
    }
    FallBack "Diffuse"
}

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?

...

public class ObjectBlur : MonoBehaviour {
	...
	protected void LateUpdate() {
		Vector4 currentPosition = transform.position;
		currentPosition.w = 1f;
		// Calculate ModelView matrices
		Matrix4x4 _mv = CameraInfo.ViewMatrix*transform.localToWorldMatrix;
		Matrix4x4 _mvPrev = CameraInfo.PrevViewMatrix*m_prevModelMatrix;
		// Give material the matrices it needs
[COLOR="red"]		m_stretchMaterial.SetMatrix("_mv", _mv);
		m_stretchMaterial.SetMatrix("_mvPrev", _mvPrev);
		m_stretchMaterial.SetMatrix("_mvInvTrans", _mv.transpose.inverse);
		m_stretchMaterial.SetMatrix("_mvpPrev", CameraInfo.PrevViewProjMatrix*m_prevModelMatrix);[/COLOR]
		// Record our previous transform
		m_prevModelMatrix = transform.localToWorldMatrix;
	}
	
	...
}

And in the shader:

Shader "Hidden/Motion Vectors" {
	SubShader {
		Tags { "RenderType"="Moving" }
		Pass {
			Fog { Mode Off }
			CGPROGRAM
				#pragma vertex vert
				#pragma fragment frag
				#pragma fragmentoption ARB_fog_exp2
				#pragma fragmentoption ARB_precision_hint_fastest
				#include "UnityCG.cginc"
				
				...
				
[COLOR="red"]				uniform float4x4 _mv;
				uniform float4x4 _mvPrev;
				uniform float4x4 _mvInvTrans;
				uniform float4x4 _mvpPrev;[/COLOR]
				
				...
			ENDCG
		}
	}
	...
}

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.

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.

1 Like

Again, many thanks Daniel, right again. Where did you get all your shader wisdom?

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.

oh god damn nice! I’ve searched like a hundred years to find a solution for this.
Works fine ty!

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