美文网首页
Unity从深度缓冲重建世界空间位置

Unity从深度缓冲重建世界空间位置

作者: LEO_青蛙 | 来源:发表于2020-06-20 17:18 被阅读0次
    深度效果

    在某些特定应用场景,比如说屏幕空间反射SSR,会要求我们从深度缓冲中重建像素点的世界空间位置。本文介绍在Unity中如何从深度缓冲中重建世界空间位置。

    1、在NDC空间中重建

    第一种方法是通过像素的屏幕坐标位置来计算。


    在NDC空间中重建

    (1)首先将屏幕空间坐标转换到NDC空间中。

    //vertex
    o.screenPos = ComputeScreenPos(o.vertex);//o.vertex是裁剪空间的顶点
    //fragment
    float4 ndcPos = (o.screenPos / o.screenPos.w) * 2 - 1;
    

    注意1:ComputeScreenPos返回的值是齐次坐标系下的屏幕坐标值,其范围为[0, w]。
    所以这里先将范围转为[0, 1],再转为[-1, 1]。
    注意2:o.screenPos.z本身就是裁剪空间下的值,范围为[-w, w],除以w范围已经转为[-1, 1],已经没有必要再*2-1,所以这里的z值多做了一步操作,导致变成没有意义的值,但是这里的z值没有用处。

    (2)然后将屏幕像素对应在摄像机远平面(Far plane)的点转换到剪裁空间(Clip space)。因为在NDC空间中远平面上的点的z分量为1,所以可以直接乘以摄像机的Far值来将其转换到剪裁空间(实际就是反向透视除法)。

    float far = _ProjectionParams.z;
    float3 clipVec = float3(ndcPos.x, ndcPos.y, 1.0) * far;
    

    (3)接着通过逆投影矩阵(Inverse Projection Matrix)将点转换到观察空间(View space)。

    float3 o.viewVec = mul(unity_CameraInvProjection, clipVec.xyzz).xyz;
    

    (4)已知在观察空间中摄像机的位置一定为(0,0,0),所以从摄像机指向远平面上的点的向量就是其在观察空间中的位置。将向量乘以线性深度值,得到在深度缓冲中储存的值的观察空间位置。

    float depth = UNITY_SAMPLE_DEPTH(tex2Dproj(_CameraDepthTexture, i.screenPos));
    float3 viewPos = i.viewVec * Linear01Depth(depth);
    

    (5)最后将观察空间中的位置变换到世界空间中。

    float3 worldPos = mul(UNITY_MATRIX_I_V, float4(viewPos, 1.0)).xyz;
    

    2、在世界空间中重建

    第二种方法是利用在世界空间中从摄像机指向屏幕像素点的向量来计算。


    在世界空间中重建

    (1)首先构造在世界空间中从摄像机指向屏幕像素点的向量。

    o.worldSpaceDir = WorldSpaceViewDir(v.vertex);
    

    (2)将向量转换到观察空间,存储其z分量的值。注意向量和位置的空间转换是不同的,当w分量为0的时候Unity会将其视为向量,而当w分量为1的时候Unity将其视为位置。

    o.viewSpaceZ = mul(UNITY_MATRIX_V, float4(o.worldSpaceDir, 0.0)).z;
    

    (3)在深度缓冲中采样。这里使用tex2Dproj而不是tex2D的原因是screenPos是用ComputeScreenPos来计算得到的,用tex2Dproj可以帮我们做透视除法。

    float eyeDepth = UNITY_SAMPLE_DEPTH(tex2Dproj(_CameraDepthTexture, i.screenPos));
    eyeDepth = LinearEyeDepth(eyeDepth);
    

    (4)因为像素点的观察线性深度就是其在观察空间中的z分量,所以根据向量的z分量计算其缩放因子,将向量缩放到实际的长度。

    i.worldSpaceDir *= -eyeDepth / i.viewSpaceZ;
    

    (5)最后以摄像机为起点,缩放后的向量为指向向量,得到像素点在世界空间中位置。

    float3 worldPos = _WorldSpaceCameraPos + i.worldSpaceDir;
    

    本文转载自知乎

    相关文章

      网友评论

          本文标题:Unity从深度缓冲重建世界空间位置

          本文链接:https://www.haomeiwen.com/subject/zbswxktx.html