Trying to pass a matrix 4x4 from c# to shader fail, why?

Hello

I’m trying to pass a custom world matrix 4x4 from c# to a shader using set matrix and setTRS, but it doesn’t work as expected, I looked for similar implementation on the forum and can’t find thread done any differently.

The function is from a class called within the start() of a monobehavior

//initialization
Matrix4x4 positionMatrix = Matrix4x4.identity;

//code inside the init function that does a bunch of stuff and pass to shader
//debug world matrix in shader
positionMatrix.SetTRS(
new Vector3(32,0,32), //position
Quaternion.Euler(
0,
0,
0
), //rotation
new Vector3(64,1,64) //scale
);
Debug.Log(positionMatrix);

directPass.SetMatrix("_PosMat", positionMatrix);
//end debug

The log look correct, I don’t really know what’s going on, the shader just stop functionning except if the setTRS is commented.

Anybody has idea of what’s going on?

Here the shader code relevant snippet

 CGPROGRAM
            #pragma vertex vertexProgram
            #pragma fragment fragmentProcessing
            #include "UnityCG.cginc"
            #include "ShaderTools.cginc"

            struct meshData
            {
                float4 vertex    : POSITION;
                float2 uv        : TEXCOORD1;
                fixed4 color    : COLOR;
                fixed3 normal   : NORMAL;
            };

            struct rasterData
            {
                //float2 uv        : TEXCOORD0;
                float4 vertex    : POSITION;
                float4 wpos     : TEXCOORD1;
                fixed4 color    : COLOR;
                fixed3 wnormals : NORMAL;
            };

            float4x4 _PosMat;


            rasterData vertexProgram (meshData input)
            {
                rasterData output;
               
                // output.wpos = mul(unity_ObjectToWorld, input.vertex);    //world position
                output.wpos     = mul ( _PosMat, input.vertex );//world position

                output.vertex = unwrap(input.uv, input.vertex.w);     //screen position
                //output.vertex = UnityObjectToClipPos(input.vertex);      //screen position
                output.wnormals =UnityObjectToWorldNormal(input.normal); //normal to world normal

                output.color = float4(input.uv, 0,1);// v.color;
                return output;
            }
           
            sampler2D _Atlas;
            float4    _MainLight;
            float4    _Origin;

My hypothesis is that matrix 4x4 don’t work in start() before the unity render has been initialize, BUT I think it’s unlikely, passing other data works just fine (though, unlike matrix4x4 they have equivalent parameter block, even though I’m not using the parameter block), also the matrix as identity works correctly, it’s just after the TRS that it fails. Is there a BUG in setTRS to setMatrix?

I don’t quite get what this shader is supposed to doing. Why do you even create that wpos variable? It is not used anywhere. The only coordinate that matters to the shader is the POSITION value and it should be in clipspace of the camera after your vertex shader. We don’t know what that “unwrap” method does, but currently your matrix has no function at all. You seem to construct the position from the UV coordinates, somehow. Note that the perspective divide / homogeneous divide is happening after the fragment shader. After the fragment shader the POSITON value should be in clip space. The GPU divided by w and ends up in normalized device coordinates (-1 to 1).

So, since we don’t know what you’re doing in your fragment shader we can not tell you what’s wrong, since your wpos is not used in the provided code snippets at all.

The shader is quite long, and it used to work previously with unity_ObjectToWorld, so the issue isn’t with the shader, it’s just that passing the matrix4x4 broke the material somehow, which is just a manual way to do the same thing that unity_ObjectToWorld do automatically for you.

Check if you don’t need to transpose the matrix along the way.

But is that your only change? We can see that there is this line commented:

which is the usual correct way of transforming the local space coordinate to clip space. Keep in mind this is the actual position of the vertex and this is usually the only relevant thing. Of course we don’t know if you do anything fancy / unusual in the fragment shader. Also we still don’t know what the “unwrap” method does. So what does this do? unwrap(input.uv, input.vertex.w);. Note that vertex.w is usually always just 1.0, at least when we talk about the shader input

Yes, unity use the transformed object matrix applied to the matrix and the scale export of the vertex, if I use the default identity alone (no transformation) I get the original non transformed position (ie not multiply by 100 by default from unity and not oriented like the object in the scene). I’m basically passing a matrix that emulate that on my own, so it should do the same thing than unity.

It just use the UV position as screen position, because I render to a texture, the original did the usual vertex position, but I was rendering to screen, both had a separated wpos variable, so the code flow is separated and shouldn’t be different in these two case. What the next of the shader does is that it use wpos to hash a position and sample an atlas accordingly, then does thing with the texture data. If wpos is faulty (doesn’t have the proper position, scale and orientation) the spatial hash fail to create relevant data, and thus the rest of teh code fail since it is feed from wpos hashing.

ANYWAY

I don’t know why and how, it somehow fixed itself and now work, just sending the wrong matrix data, as it hash properly, so now I have just teh matrix to fix. That’s the second time something just stop working, then start working again in unity :roll_eyes: I have no idea what happened…

That has never happend to me ever in over 10 years using Unity :slight_smile: I had some gotcha moments, but they all turned out being my fault or some misunderstanding on my part. In all that time Unity has only crashed about 2-3 times (without any reason). Though, those who complain about frequent crashes often times use a lot (third party) packages where chances are much higher that something goes wrong. I also never had any issue that “resolved” itself by a restart of the editor. I often times have my PC as well as Unity running for weeks and I don’t have any problems ^^.

Spoke too soon…

Did nothing, computer was left open, I just did stuff irl, then I came back just press play and it’s back …

Have you actually tried exposing the position, rotation (probably euler angles) and scale in an inspector and update / recreate your matrix in Update? That way you can tweak the values at runtime to see what’s happening. Also we see that you’re creating the material on the fly. Are you sure this is never overwritten or destroyed or something else messing with it?

Well if it’s pink I guess that it won’t matter much, since no modification are done. Also it happen in start() there is no update, I’ll be trying to create a project just for that to see if there is side effect interfering or if it’s normal behavior.

Bunny83

me it happens to me that unity 2021 crashes, often because of the fact that I misname my script, either I have the console error, or it crashes, small bug. Like what sometimes it can come from elsewhere.

it means your shader either does not compile at all or is not supported by your hardware and doesn’t have a fallback. This can have various reasons. Shaders are limited by how many instructions and interpolated variables they can have. Also of course certain used features may only exist when you have a hardware that supports those features.

Then it would work I other case like passing unity own variable or vanilla identity matrix. If I comment the custom matrix4x4 without changing the shader, it works. That’s why I’m puzzled. That must happen before the shader execution.

It’s either a side effect I don’t see.

I close all programs and desinstalled a bunch, then kill process after rebooting, and it works … :eyes:
But I have a new impossible problem.