directxshaderhlslogre3d

Linear Depth to World Position


I have the following fragment and vertex shaders.

HLSL code ` // Vertex shader //-----------------------------------------------------------------------------------

void mainVP( 
   float4 position     : POSITION, 
   out float4 outPos   : POSITION, 
   out float2 outDepth : TEXCOORD0, 
   uniform float4x4 worldViewProj,
   uniform float4 texelOffsets,
   uniform float4 depthRange)   //Passed as float4(minDepth, maxDepth,depthRange,1 / depthRange)
{ 
    outPos = mul(worldViewProj, position);
    outPos.xy += texelOffsets.zw * outPos.w;
    outDepth.x = (outPos.z - depthRange.x)*depthRange.w;//value [0..1]
    outDepth.y = outPos.w; 
} 

// Fragment shader  
void mainFP( float2 depth: TEXCOORD0, out float4 result : COLOR) { 
    float finalDepth = depth.x;
    result = float4(finalDepth, finalDepth, finalDepth, 1);
}

`

This shader produces a depth map.

This depth map must then be used to reconstruct the world positions for the depth values. I have searched other posts but none of them seem to store the depth using the same formula I am using. The only similar post is the following Reconstructing world position from linear depth

Therefore, I am having a hard time reconstructing the point using the x and y coordinates from the depth map and the corresponding depth.

I need some help in constructing the shader to get the world view position for a depth at particular texture coordinates.


Solution

  • It doesn't look like you're normalizing your depth. Try this instead. In your VS, do:

    outDepth.xy = outPos.zw;

    And in your PS to render the depth, you can do:

    float finalDepth = depth.x / depth.y;

    Here is a function to then extract the view-space position of a particular pixel from your depth texture. I'm assuming you're rendering screen aligned quad and performing your position-extraction in the pixel shader.

    // Function for converting depth to view-space position
    // in deferred pixel shader pass.  vTexCoord is a texture
    // coordinate for a full-screen quad, such that x=0 is the
    // left of the screen, and y=0 is the top of the screen.
    float3 VSPositionFromDepth(float2 vTexCoord)
    {
        // Get the depth value for this pixel
        float z = tex2D(DepthSampler, vTexCoord);  
        // Get x/w and y/w from the viewport position
        float x = vTexCoord.x * 2 - 1;
        float y = (1 - vTexCoord.y) * 2 - 1;
        float4 vProjectedPos = float4(x, y, z, 1.0f);
        // Transform by the inverse projection matrix
        float4 vPositionVS = mul(vProjectedPos, g_matInvProjection);  
        // Divide by w to get the view-space position
        return vPositionVS.xyz / vPositionVS.w;  
    }
    

    For a more advanced approach that reduces the number of calculation involved but involves using the view frustum and a special way of rendering the screen-aligned quad, see here.