Search Unity

Need help transforming world position to screen position for gun optics HUD.

Discussion in 'General Graphics' started by jogus84, Mar 25, 2017.

  1. jogus84

    jogus84

    Joined:
    Feb 8, 2015
    Posts:
    13
    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.

    1. Estimate elevation required to reach desired range. (This is performed numerically using the bisection method since I'm modelling drag and similar effects).

    2. 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 =>
    Code (CSharp):
    1. var y = tan(e) * range;
    3. Construct a projection matrix that matches the current optics for the gun.
    Code (CSharp):
    1. var perspective = Matrix4x4.Perspective(fov, aspect, nearClip, farClip);
    4. Construct the world position point using the range and y component from (2) and transform by the perspective matrix from (3).
    Code (CSharp):
    1. var projectedY = perspective.MultiplyPoint(new Vector3(0f, y, range)).y;
    5. 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.
    Code (CSharp):
    1. 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?
     
    Last edited: Mar 25, 2017
  2. jogus84

    jogus84

    Joined:
    Feb 8, 2015
    Posts:
    13
    FYI, found a solution.

    In (4):
    Code (CSharp):
    1. var projectedY = perspective.MultiplyPoint(new Vector3(0f, y, range)).y;
    I must add the relative offset for my muzzle position, I'm not sure why but if I do it seems to work out.
    Code (CSharp):
    1. var projectedY = perspective.MultiplyPoint(new Vector3(0f, y + gun_height, range)).y;
    Since I'm already calculating the range using a calculated elevation value that has already considered the relative gun height I can't understand why I must use this height in the 4th step once more. Maybe someone can enlighten me?