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:
Vertex and fragment shader:
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.
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
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.