美文网首页
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从深度缓冲重建世界空间位置

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

  • Unity Shader 深度值重建世界坐标

    Unity Shader-深度相关知识总结与效果实现(LinearDepth,Reverse Z,世界坐标重建,软...

  • Unity中的深度测试相关知识与问题

    深度缓冲格式、深度冲突及平台差异深度测试UnityZ-Fighting产生原因Unity Shader - Off...

  • QT+OPenGL十五之深度缓冲区

    深度缓冲区 OpenGL中使用深度缓冲区,来高效解决物体遮挡的问题,即相同屏幕位置离我们最近的片段应该被保留并且记...

  • Unity中的深度图

    深度图中存储的值是什么?(深度缓冲Zbuffer的值) 顶点P: (1)观察空间坐标:P = (x, y, z, ...

  • OpenGL-深度测试

    本节了解的内容 什么叫做深度缓冲区。 深度缓冲区的作用。 如何使用深度缓冲区测试。 可视化深度值。 如何解决深度值...

  • Shader 快捷记录

    位置相关 1. 视空间位置 o.pos =mul(UNITY_MATRIX_MVP, v.vertex); 2.物...

  • OpenGL 模板缓冲区的理解

    OpenGL缓冲区 颜色缓冲区包含颜色索引或者RGBA颜色数据 深度缓冲区存储每个像素的深度值。当启动深度测试时,...

  • 深度/模板测试

    深度测试 深度缓冲(Depth Buffer)存储每个片段的信息,深度缓冲由窗口系统自动创建并将其深度值存储为 1...

  • [6].开启Opengl的深度测试把

    跳去目录 (这里需要先完成demo5) 深度缓冲(Depth buffer) 深度缓冲,也被叫做Z-缓冲,是用来存...

网友评论

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

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