Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Problem with Reconstructing Position From Depth Buffer

Discussion in 'Shaders' started by Chimera3D, Feb 10, 2015.

  1. Chimera3D

    Chimera3D

    Joined:
    Jan 27, 2012
    Posts:
    73
    After trying several methods that all had some sort of limitation or problem I found a method of reconstructing world positions from a depth buffer that works but is only accurate when the camera x and z rotation is set to zero, but it's the most flexible method I've found so far (can be applied to non-post processing shaders). Here's the reconstruction function:

    Code (CSharp):
    1. float3 DepthToWorld(float2 screenPos, float depth)
    2.             {
    3.                 float3 cameraPos = _WorldSpaceCameraPos;
    4.                 float3 localX = _FrustumCorners[1] - _FrustumCorners[0];
    5.                 float3 localY = _FrustumCorners[3] - _FrustumCorners[0];
    6.                
    7.                 float3 ray = screenPos.x * localX + screenPos.y * localY + _FrustumCorners[0];
    8.                
    9.                 float3 pos = cameraPos + (-ray) * depth;
    10.                 return pos;
    11.             }
    and the code that calls it:

    Code (CSharp):
    1. float3 worldPos = DepthToWorld(i.uv, depth);
    and the code that creates the frustum corners matrix:

    Code (CSharp):
    1.         float CAMERA_NEAR = camera.nearClipPlane;
    2.         float CAMERA_FAR = camera.farClipPlane;
    3.         float CAMERA_FOV = camera.fieldOfView;
    4.         float CAMERA_ASPECT_RATIO = camera.aspect;
    5.        
    6.         Matrix4x4 frustumCorners = Matrix4x4.identity;      
    7.        
    8.         float fovWHalf = CAMERA_FOV * 0.5f;
    9.        
    10.         Vector3 toRight = camera.transform.right * CAMERA_NEAR * Mathf.Tan (fovWHalf * Mathf.Deg2Rad) * CAMERA_ASPECT_RATIO;
    11.         Vector3 toTop = camera.transform.up * CAMERA_NEAR * Mathf.Tan (fovWHalf * Mathf.Deg2Rad);
    12.        
    13.         Vector3 topLeft = (camera.transform.forward * CAMERA_NEAR - toRight + toTop);
    14.         float CAMERA_SCALE = topLeft.magnitude * CAMERA_FAR/CAMERA_NEAR;  
    15.        
    16.         topLeft.Normalize();
    17.         topLeft *= CAMERA_SCALE;
    18.        
    19.         Vector3 topRight = (camera.transform.forward * CAMERA_NEAR + toRight + toTop);
    20.         topRight.Normalize();
    21.         topRight *= CAMERA_SCALE;
    22.        
    23.         Vector3 bottomRight = (camera.transform.forward * CAMERA_NEAR + toRight - toTop);
    24.         bottomRight.Normalize();
    25.         bottomRight *= CAMERA_SCALE;
    26.        
    27.         Vector3 bottomLeft = (camera.transform.forward * CAMERA_NEAR - toRight - toTop);
    28.         bottomLeft.Normalize();
    29.         bottomLeft *= CAMERA_SCALE;
    30.  
    31.         frustumCorners.SetRow (0, topLeft);
    32.         frustumCorners.SetRow (1, topRight);      
    33.         frustumCorners.SetRow (2, bottomRight);
    34.         frustumCorners.SetRow (3, bottomLeft);
    35.  
    36.         mat.SetMatrix ("_FrustumCorners", frustumCorners);
    and where I originally found this method: https://www.synapsegaming.com/forums/p/1165/13827.aspx (the last post on the page). As I said it seems to work really well but when the camera rotates on the x or z axis the reconstruction doesn't account for the rotation (but does for the y axis). Does anyone what could be going wrong?
     
  2. Chimera3D

    Chimera3D

    Joined:
    Jan 27, 2012
    Posts:
    73
    Am I supposed to be doing a simple matrix multiplication somewhere? Everything seems to check out so I wouldn't think that it would be necessary.
     
  3. Chimera3D

    Chimera3D

    Joined:
    Jan 27, 2012
    Posts:
    73
    Nevermind I figured it out, a few simple errors, the ray variable should not be negative in the line:
    Code (CSharp):
    1. float3 pos = cameraPos + (-ray) * depth;
    and the y component of screenPos in the line:
    Code (CSharp):
    1. float3 ray = screenPos.x * localX + screenPos.y * localY + _FrustumCorners[0];
    has to be inverted and the line should read:
    Code (CSharp):
    1. float3 ray = screenPos.x * localX + (1-screenPos.y) * localY + _FrustumCorners[0];
    and now it works perfectly. :)