Hi I’m confused regarding world to screen transformations.
I’m trying to render a HUD that shows various markers to aid the player when elevating the gun for a certain distance, much like how the gun sights in WW2 tanks worked.
My current method “almost” works, but there are small errors a couple of pixels, this error also seem to increase as the range (elevation) increases. My current implementation works like this.
-
Estimate elevation required to reach desired range. (This is performed numerically using the bisection method since I’m modelling drag and similar effects).
-
Given the elevation required in the previous step, calculate the y component of the world position the gun would be aligned to if elevated to that elevation. Here I’m simply using basic trigonometry by tan(e) = opposite/adjacent =>
var y = tan(e) * range;
- Construct a projection matrix that matches the current optics for the gun.
var perspective = Matrix4x4.Perspective(fov, aspect, nearClip, farClip);
- Construct the world position point using the range and y component from (2) and transform by the perspective matrix from (3).
var projectedY = perspective.MultiplyPoint(new Vector3(0f, y, range)).y;
- Use the calculated projectedY, since we want 0 elevation in center off screen, and need to “raise” the gun inorder to fire further, we inverse the sign. We must also transform the projected coordinate from [-1, 1] space to [0, 1] normalized screen space.
var pixelOffsetY = (1f + projectedY) * 0.5f * Screen.height;
Using the above steps for my test case and using 500m and 1000m markers, the 500m marker will be off by roughly -150m and the 1000m marker will be off by roughly -400m.
So if I position the 500m or 1000m marker at center of the screen, the resulting elevation is NOT the one calculated from (2).
Why is that?