World Space From Depth Texture Cover

从深度图中获取世界空间的坐标

为什么要从深度图重建世界坐标 一个很大的应用情景是在后处理的阶段,或是计算一些屏幕空间的效果(如SSR、SSAO等),只能获取到一张深度贴图,而不是每一个几何体的顶点数据,很多的计算中却又需要用到世界坐标或者是视空间的坐标,这时我们就需要通过深度图来重建世界空间的坐标。 重建世界坐标的流程 首先要获取屏幕空间的UV,这里记为positionSS,范围是(0, 1)(0, 1)。 使用UV采样深度贴图,获取到当前的深度值。 使用UV和深度值,得到标准化设备坐标,这里记为positionNDC。 使用裁剪空间到视空间的变换矩阵乘以positionNDC,除以W分量,得到视空间坐标,这里记为positionVS。 使用视空间到世界空间的变换矩阵乘以positionVS,得到世界空间坐标,这里记为positionWS。 这里使用DepthToPositionShader.shader,假装是屏幕后处理的shader,来演示一下重建世界坐标的流程,这样比直接写屏幕后处理的shader能够更好的去了解Unity的空间变换的方式。 这个shader有以下几个需要注意的点: 为了使用_CameraDepthTexture这张深度贴图,需要在srp的设置中开启Depth Texture这个选项。这样子在渲染的时候会在DepthPrePass用shader中的Depth Only这个pass去先渲染出深度贴图。我们就能够在渲染物体的时候直接拿到包含当前物体的深度贴图了。 顶点着色器和片元着色器中的SV_POSITION并不完全相同。对于顶点着色器来说,SV_POSITION就是之前所说的\((\frac X {\tan {\frac {fovy} 2} \cdot \frac x y }, -\frac Y {\tan {\frac {fovy} 2}}, \frac {Zn} {f - n} + \frac {fn} {f - n}, -Z)\);但是在片元着色器中,SV_POSITION的XY分量会乘上屏幕的宽高,Z分量则是已经除以W之后的深度值。屏幕的宽高信息保存在_ScreenParams这个内置的变量中,它的前两位是屏幕的宽高像素数,后两位是宽高的像素数的倒数加一。 要针对DX11和OpenGL不同的透视变换矩阵来调整UV的Y分量的数值,也就是要注意UNITY_UV_STARTS_AT_TOP这个宏的使用。出现获得的坐标跟随着摄像机的移动发生奇怪的倾斜的时候,往往都是忘记对Y分量的平台差异进行处理。 最后得到的视空间和世界空间的坐标值,要记得除以这个坐标值的W分量,相当于是做了一次归一化,才能得到正确的坐标。 DepthToPositionShader.shader Shader "zznewclear13/DepthToPositionShader" { Properties { [Toggle(REQUIRE_POSITION_VS)] _Require_Position_VS("Require Position VS", float) = 0 } HLSLINCLUDE #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/core.hlsl" #pragma multi_compile _ REQUIRE_POSITION_VS sampler2D _CameraDepthTexture; struct Attributes { float4 positionOS : POSITION; float2 texcoord : TEXCOORD0; }; struct Varyings { float4 positionCS : SV_POSITION; float2 texcoord : TEXCOORD0; }; Varyings Vert(Attributes input) { Varyings output = (Varyings)0; VertexPositionInputs vertexPositionInputs = GetVertexPositionInputs(input....

July 3, 2021 · zznewclear13
Space Transformation Cover

Unity空间变换总览

空间变换和平台差异 将一个物体渲染到我们的屏幕上,需要经过一系列的坐标变换,这些坐标变换是在shader中使用矩阵进行计算的。变换的顺序如下,从物体空间(Object Space)到世界空间(World Space),从世界空间到视空间(View pace),从相机控件到裁剪空间(Clip Space),最后显示到我们的屏幕空间(Screen Space)。 这一部分讲的空间变换是在Unity之外的空间变换,具体的Unity的空间变换还需要看这里。 物体空间到世界空间 这里用到的矩阵相对比较简单。我们用\(R\), \(T\)和\(S\)来分别代表物体的旋转平移和缩放系数,\(R\)由物体的三个旋转角决定,这里的格式是一个3x3的矩阵,\(T\)和\(S\)是两个1x3的向量,用\(P\)来代表物体空间的一个点。那么这个点在世界空间中的坐标就可以使用下面的式子进行计算: $$ P_{world} = \begin{pmatrix} R_{00} S_x& R_{01}& R_{02}& T_x \cr R_{10}& R_{11} S_y& R_{12}& T_y \cr R_{20}& R_{21}& R_{22} S_z& T_z \cr 0& 0& 0& 1 \end{pmatrix} \times \begin{pmatrix} P_x \cr P_y \cr P_z \cr 1 \end{pmatrix} $$ 这个4x4的矩阵就是物体空间到世界空间的变换矩阵,这里记为\(M_{o\to w}\),在\(P\)的基础上额外增加了一个维度的这个向量,是\(P\)对应的齐次坐标。对于普通的向量\(V\)(如物体表面切线方向、视线方向、光源方向)等,从物体空间变换到世界空间时,齐次坐标的高次位应当为0,上式变为: $$ V_{world} = \begin{pmatrix} R_{00} S_x& R_{01}& R_{02}& T_x \cr R_{10}& R_{11} S_y& R_{12}& T_y \cr R_{20}& R_{21}& R_{22} S_z& T_z \cr 0& 0& 0& 1 \end{pmatrix} \times \begin{pmatrix} V_x \cr V_y \cr V_z \cr 0 \end{pmatrix} $$ 要注意的是:将物体空间的法线\(N\)变换到世界空间时,应当使用\(M_{o\to w}\)的逆矩阵的转置\((M_{o\to w}^{-1})^T\),也就是世界空间到物体空间的变换矩阵的转置\((M_{w\to o})^T\)乘物体空间的法线\((M_{w\to o})^T \times N\),这条式子等价于\(N \times M_{w\to o}\)。而对于正交矩阵来说,其逆矩阵就是这个矩阵的转置,因此可以像普通向量一样处理法线。...

July 1, 2021 · zznewclear13
zznewclear13 技术美术 图形学 个人博客 technical art computer graphics