Hi. How would I go about computing the results of UnityObjectToClipPos(foo).w
in c# for a given camera and world-space vertex?
I understand w acts as some sort of scale factor, and is used by the shader for the transformation out of homogeneous coordinates somewhere prior to the rasterization phase of a shader. For my use case it would save a lot of computational power to compute the w value for a few set points prior to the execution of the shader, rather than needing to compute those values for every vertex.
Thanks!
Just the same way that the shader does it. You just put your vertex through the MVP matrix. Since you said you have already a worldspace coordinate and not like a shader which is given local space coordinates you only have to put that position through the “VP” matrix which can be calculated like this:
Matrix4x4 VP = camera.projectionMatrix * camera.worldToCameraMatrix;
In case you want to pass in local space coordinates the MVP matrix is calculated like this for the local space of “obj”:
Matrix4x4 MVP = VP * obj.transform.localToWorldMatrix;
// or directly like this:
Matrix4x4 MVP = camera.projectionMatrix * camera.worldToCameraMatrix * obj.transform.localToWorldMatrix;
To transfer a worldspace position into clipspace you would do:
Vector3 worldPos; // given
Vector4 clipPos = VP.MultiplyPoint(worldPos);
Instead of using “MultiplyPoint” you can also multiply directly on the right but you have to use a Vector4 in homogeneous coordinates. So make sure your w is set to 1 for positions and 0 for directions.
Vector4 worldPos = new Vector4(x, y, z, 1f);
Vector4 clipPos = VP * worldPos;
When using local space coordinates it works the same way, just use the MVP matrix of an object and of course multiply by a local space position of that object.
If you want some deeper understanding of matrices and the projection matrix, have a look at my matrix crash course
edit
I forget to note that what you get back from the multiplication is the not yet normalized vector. The homogeneous divide has to be done by yourself. However since you’re interested in the w, there you have it. Usually you would do this afterwards:
clipPos *= 1f/clipPos.w;
This will make w 1 again and adjust the other components accordingly.