- Home /
manual MVP projection gives different results then WorldToViewportPoint
I'm trying to manually perform an MVP transformation for a single point. I think (hope) I have it sort of figured out, except for one quirk: my Z coordinate in Viewport space is off.
Here is the code:
var pos = Vector3.zero;
var pos_homogeneous_coordinates = new Vector4(pos.x, pos.y, pos.z, 1);
var pos_local = cam.transform.localToWorldMatrix.inverse * pos_homogeneous_coordinates;
pos_local.z *= -1; // unity uses a left-handed coordinate system for the projection
var pos_in_clip_space = cam.projectionMatrix * pos_local;
var pos_in_NDC = (pos_in_clip_space / pos_in_clip_space.w);
var pos_in_viewport_space = (Vector3) ((pos_in_NDC + new Vector4(1,1,1,0)) / 2f);
print(pos_in_viewport_space);
print(cam.WorldToViewportPoint(pos));
where cam
is the camera. The result of this in my case is:
And I would expect them to be identical. Also, my code seems to produce strange results in edge cases or when the position is outside the clipping area. E.g. using pos = cam.transform.position
:
My question simply is where I am going wrong, as I don't see it. Any pointers or help is highly appreciated =)
out of curiosity, do you still have the offset if you use the non-jittered projection matrix ?
Yes, the same situation occurs. Actually I figured out why my the z-values differ: WorldToViewportPoint(...).z
is NOT the normalized distance in viewport space. Ins$$anonymous$$d it is the distance between the viewport plane to the point in the scale of the world frame. I can see why the devs made that decision; however, for me that was a bit unexpected.
The only thing I haven't figured out yet is why my normalization gets funny when the distance approaches cam.nearClipPlane
. After transfor$$anonymous$$g to NDC, I would expect a constant z=1
; which is the case for most values, just not around cam.nearClipPlane
. Any ideas?
Answer by FirefoxMetzger · Aug 13, 2018 at 01:30 PM
The strange behavior is actually not very strange at all. After consulting the documentation of WorldToViewportPoint
(again) I found
Viewport space is normalized and relative to the camera. The bottom-left of the camera is (0,0); the top-right is (1,1). The z position is in world units from the camera.
After further investigation, I also found that this distance is measured as the normal distance between the point and the projection plane.
In other words, both ways are correct. Unity gives an absolute difference, I return the normalized distance (which may be a lot less meaningful since it usually is 1
.
Regarding the strange behavior around cam.transform.position
I picked the most unfortunate point to look at. When z --> 0
(distance between camera and point), w --> 0
; thus, at the camera's origin one would divide by 0 which is not a good idea.
Your answer

Follow this Question
Related Questions
Unity/SteamVR changing coordinate system based on camera view 1 Answer
How to match 3dsmax camera perspective with unity 0 Answers
Projecting Oblique Screen Coords to Straight World Coords 1 Answer
Comparing Orthographic and Perspective Cameras 1 Answer
What Camera Perspective does Clash Royale use? (/w image) 3 Answers