根據深度值反推頂點的世界坐標值


頂點從世界空間轉換到NDC空間:

需要先通過視角矩陣轉換到攝像機空間,然后再通過透視矩陣轉換到齊次裁剪空間,最后做透視除法(齊次裁剪空間的坐標除以自己的w分量),公式:

\(V_{proj} = M_{proj}M_{view}V_{world} \tag{1.1}\)
\(V_{ndc} = V_{proj} / V_{proj}.w \tag{1.2}\)

根據深度值反推世界坐標

當我們知道一個坐標的深度值,並且知道當前的屏幕空間坐標,那么就可以通過屏幕空間坐標和深度值得到NDC坐標

\(V_{ndc} = (V_{screen}.x * 2.0 - 1.0, V_{screen}.y * 2.0 - 1.0, depth, 1.0) \tag{2.1}\)

當我們知道了NDC坐標之后我們可能會就想可以根據上面的世界空間轉換到NDC空間的步驟的逆直接得到世界坐標了,這個步驟會是這樣:

\(V_{proj} = (M_{proj}M_{view})^{-1}V_{ndc}) * V_{proj}.w \tag{2.2}\)

是的,這時候你就會發現你並不知道\(V_{proj}.w\)的值是什么,因為這個值在做透視除法之后已經丟失了。
但是,可以世界坐標的w值時已知的且\(V_{world}.w = 1.0\),所以有:

\(V_{world}.w = ((M_{proj}M_{view})^{-1}V_{ndc}).w * V_{proj}.w = 1.0 \tag{2.3}\)

所以有:

\(V_{proj}.w = 1.0 / ((M_{proj}M_{view})^{-1}V_{ndc}).w \tag{2.4}\)

把上式帶入\(\left( 2.2 \right)\),得:

\(V_{proj} = (M_{proj}M_{view})^{-1}V_{ndc}) / ((M_{proj}M_{view})^{-1}V_{ndc}).w \tag{2.5}\)

所以,世界坐標就為NDC坐標右乘\(M_{proj}M_{view})^{-1}\),再除以自身的w。

在Unity中的實例:

//main problem encountered is camera.projectionMatrix = ??????? worked but further from camera became more inaccurate
//had to use GL.GetGPUProjectionMatrix( ) seems to stay pretty exact now
//在C#中傳遞變換矩陣進shader:
Matrix4x4 viewMat = camera.worldToCameraMatrix;
Matrix4x4 projMat = GL.GetGPUProjectionMatrix( camera.projectionMatrix, false );
Matrix4x4 viewProjMat = (projMat * viewMat);          
Shader.SetGlobalMatrix("_ViewProjInv", viewProjMat.inverse);
//in fragment shader:
uniform float4x4 _ViewProjInv;
float4 GetWorldPositionFromDepth( float2 uv_depth )
{    
        float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv_depth);
        float4 H = float4(uv_depth.x*2.0-1.0, (uv_depth.y)*2.0-1.0, depth, 1.0);
        float4 D = mul(_ViewProjInv,H);
        return D/D.w;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM