Different result when using unity_ObjectToWorld in Surface shader and Vertex and fragment shader

I’m using unity_ObjectToWorld to convert local space position of vertex to world space position. But in surface shader, and ind Vertex And Fragment shader, the result is different.
The experiment is simple: render color of pixel base on it world space position.
My expected behaviour is that the color of object is change when i drag object around ( because world space position is change).
If i use vertex and fragment shader, the behaviour is same as expected.
But when i use it in surface shader, the color of object is not change when i moved object around.
Can anyone help me to explain this situation?
Here is the code in surface shader and in the vertex and fragment shader:
Surface shader:
7192660--863233--upload_2021-5-31_17-25-22.png
Vertex and fragment shader:

7192660--863230--upload_2021-5-31_17-24-18.png

7192660--863227--upload_2021-5-31_17-23-47.png

In one you’re doing: mul(unity_ObjectToWorld, v.vertex.xyz)

In the other you’re doing: mul(unity_ObjectToWorld, v.vertex)

unity_ObjectToWorld is a float4x4 and v.vertex is a float4 value, so these will produce different results.

A 3D transform matrix is a 4x4 matrix where the first 3x3 is the rotation and scale, and the fourth column is the translation. If you multiply a float4x4 transform matrix with a float3, only the first “3x3” of the matrix is applied (actually 3x4, but for a 3D transform matrix the last row doesn’t do anything). You need to use a float4 value with a w of 1.0, which the v.vertex.w always is.

Try using: mul(unity_ObjectToWorld, v.vertex) or mul(unity_ObjectToWorld, float4(v.vertex.xyz, 1.0)) in both.

2 Likes

Thank you very much for your detailed answer! I didn’t know that unity automatically take 3x3 matrix from 4x4 matrix when multiple with Vector3 :smile:

Nothing to do with Unity. That’s just generally how matrix math works. If you have a mismatch in dimensions between a matrix and a vector, you either have to lop off part of the matrix/vector, or increase the smaller one by appending zeros which produces the same result. Some programming languages will throw an error, but HLSL and GLSL will generally just make it work by adding zeros. For GLSL it depends on the device though as GLSL compilers can be unique to each device and some compilers are very strict about values needing to match. Since Unity’s cross compiler sends all shaders through Microsoft’s very lenient HLSL FXC compiler first, those mismatches get cleaned up for you before any GLSL compiler sees them.

1 Like