Unity根据深度值计算世界坐标

    xiaoxiao2021-03-25  40

    最近在Unity在ForwardPath的情况下,实现一个DeferRender的效果。 其中在DeferRender的时候会用到世界坐标。 世界坐标有三个值x,y,z,如果要记录三个值就需要三个通道来记录世界坐标。 第一部分:根据深度值世界坐标 其实在DeferRender的时候我们对每一个像素值都是可以知道屏幕坐标的xy值的, 那么只要知道了深度值, 就可以反向推出世界坐标了。 图1-1 模型空间到屏幕空间的过程 在经过透视除法得到的结果xyz 都是在-1 -- 1 (opengl) 或者0-1(directx)。 我们只要获取到这个深度值。 在PC中, vertex的 shader写法如下: 图1-2 在vertshader中获取深度值 记录的深度值就可以在后处理过程当中使用了。 当然可以通过另外一种方法获取深度值就是设置Camera的depthTextureMode 为depth 或者depthnormal。 这样在shader中只要做如下声明就可以获得深度贴图了。 图1-3 在sheder中声明 _CameraDepthTexture 现在已经可以获得深度值了。 如何构建屏幕空间的坐标呢? 拿到屏幕上的坐标,组合深度值就是了。我们在使用Graphics.Blit的时候UV值就是 屏幕空间的归一化坐标了。 现在只要获得两个矩阵就可以获得世界坐标。 一个是投影矩阵MatriProjection, 一个是MatrixWToV。 求出这两个矩阵的逆矩阵就可以轻松通过矩阵成向量获得世界坐标。 图1-4 根据屏幕坐标和深度值求世界坐标 图1-4中 有个矩阵_ViewProjectionInverseMatrix 是投影矩阵和世界坐标转观察空间矩阵相乘求逆得到的。通过Material.setMatrix设置的。 图1-5 在PreRender中设置_ViewProjectionInverseMatrix 第二部分:如何测试你的结果是否正确 在Shader中如何测试我们计算的结果是多少,或者是否正确? 有几种方式都可以测试。 一种是使用帧调试器, 在调试的过程当中可以清楚的看到Shader计算的值。不论是参数还是计算结果。 Unity5已经自带帧调试器了。 而Unity5以前的版本 则可以使用IntelGPA, 高通的AdrenoProfiler 打出一个exe的包用Visual Studio的帧调试器。 当然还有其他一些工具。 另外一种方式则是直接输出颜色值, 把你的值压缩在0-1范围内。这里可以直接使用第二种方法。因为我们在正常的渲染情况下渲染一遍物体,把深度值渲染到一张RenderTexture上,然后在后处理中反推出世界坐标。 那么只要我们把世界坐标的值压缩在0-1赋值给这个物体的颜色即可。 然后在后处理中同样把计算的世界坐标压缩到0-1直接。 只要编辑器下Scene里的物体颜色和Game里的物体颜色一致,结果就对了。否则就是错的。 图2-1 在渲染物体的输出世界坐标坐标作为颜色值 图2-2 后处理中计算的直接坐标值和实际的世界坐标值一致的结果 在实际测试过程当中,会出现物体拖得太远在camera里就看不见了, 这是因为z-fighting的原因, 我们计算出来的z值和原坐标的z并非是线性关系,而是一条曲线值。 在某些地方就会出现精度问题。 z-fighting可以阅读文章:https://www.scratchapixel.com/lessons/3d-basic-rendering/perspective-and-orthographic-projection-matrix/opengl-perspective-projection-matrix 第三部分:仍然有疑问的地方 1、回到图1-1当中, 在透视除法之后理论上xyz的值都应该是-1--1 或者0-1。 而我使用的是OpenGL的做法即 -1---1。 但我在图1-2中取深度值直接取 z = o.position.z / o.postion.w 而不是 z =( o.position.z / o.postion.w + 1 ) * 0.5 测试也是前哪一种方法是对的, 而后一种方法是错的。 2、我是否可以观察空间下的z 除以 farplane的值就可以了。 因为如果z超过了farplane 就被裁剪掉了。 然后在后处理过程当中直接拿到view空间下的坐标替换z值,然后乘上 UNITY_MATRIX_MV 的逆矩阵 和 _Object2World 就可以得到世界坐标了呢? 3、在实际的不同平台上裁剪空间上区别还没有验证。 附件是我在Unity4.6下测试代码, 在unity5中会报错,只要修改其中的 GenerateDepthAndShowWoldPos.shader即可运行了。 参考: 1、 https://forum.unity3d.com/threads/reconstructing-world-pos-from-depth-imprecision.228936/ 2、 http://www.klayge.org/2011/01/16/klayge中的延迟渲染(二)/

    转载请注明原文地址: https://ju.6miu.com/read-30423.html

    最新回复(0)