--------------更新

更简单的方法:

     //depth: raw depth, nonlinear, 0 at near plane, 1 at far plan

           float4 screenUVwithDepth=float4(screenUV,depth,1);//now x,y,z are in [0,1]
                ndcPos=screenUVwithDepth*2-1;//now x,y,z are in [-1,1] and w=1
                float4 worldPos=mul(clipToWorld,ndcPos);

     worldPos/=worldPos.w;//important

--------------旧帖

我用于渲染_CameraDepthTexture的相机是一个透视相机。正交的情况没试,估计差不多。

unity的image effect的机制我们大致都了解:它是画了一个覆盖全屏的quad(具体尺寸和位置未知)。

要注意的是image effect使用的投影矩阵并非相机的投影矩阵,而是使用了一个正交投影矩阵(具体形式未知),这一点我卡了好久才意识到,不过一想也很正常合理,毕竟只是想画个全屏quad,直接push个正交矩阵(即切换到2d模式)去画就好了。

虽然image effect使用的投影矩阵和相机不一致,但两者之间的联系是投影到2d屏幕的结果是相同的,这是关键。

下面开始重建:

对于image effect下的当前像素p,可以获得其屏幕坐标sPos_p=(screenX_p,screenY_p,0),这也是p在相机下的屏幕坐标,由于_CameraDepthTexture恰好铺满相机屏幕,所以p在_CameraDepthTexture上的纹理坐标sUV_p=sPos_p.xy/screenSize,即p点处深度值为

depth=_CameraDepthTexture(sUV_p)

设p点处深度值为depth的点为p',则p’在相机空间的z值为

linearDepth=LinearEyeDepth(depth)

如图,即|QP'|=linearDepth:

现在我们要求的是P'的世界坐标,计算如下:

1,先求P点的世界坐标,分两步:

(1)求p的归一化设备空间坐标ndcPos_p=screenToNDC*sPos_p.

(2)求p的世界坐标wPos_p:

  temp=clipToWorldMatrix*ndcPos_p. (clipToWorldMatrix须从外部传入)

  wPos_p=temp/temp.w

2,设由eyeWorldPos指向P的单位向量为dir,则dir=normalize(wPos_p-eyeWorldPos).

3,distance(eyeWorldPos,P')=|QP'|/cos(theta)=linearDepth/dot(eyeWorldDir,dir)

4,最终P'点世界坐标为wPos_p'=eyeWorldPos+dir*distance(eyePos,P')

重建完成。

说明:

1,eyeWorldPos可在shader中通过内置变量获取。eyeWorldDir我试过直接用内置变量UNITY_MATRIX_V [2].xyz,结果似乎不对,于是改用了从外部传入camera.tranform.forward,这样结果是对的。

2,这里只是为说明原理方便,使用了“image effect和相机两种渲染模式下屏幕空间坐标相等”这个条件来解题,而实际上若利用“两种模式下归一化设备空间坐标相等”来做更简单些,至少不用把screenSize牵扯进来了。

3,clipToWorldMatrix必须从外部传入,因为

clipToWorldMatrix=camera.cameraToWorldMatrix*camera.ProjectionMatrix.inverse

其中camera.ProjectionMatrix必须从外部传入才能获得正确的值,因为image effect shader内部已经被unity偷粮换柱成正交矩阵了。

4,Projection或unProjection的过程一定不要忘了做透视除法。

5,linearDepth的确切含义是“相机空间中的z坐标”,按此含义,它表示的是前面图中|QP'|的长度,而非eye到P'的距离。

6,如何验证上面方法重建出的世界坐标是正确呢?

我采用的方法是把distance(eyeWorldPos,P')/farPlane作为颜色值渲染出来。然后再另搞一个非重建的测试用例,也把distance(eyeWorldPos,worldPos)/farPlane作为颜色值渲染出来(使用完全相同的测试场景,完全相同的相机角度),然后看两幅图是否一模一样。我测试的结果是一样的。

----补充:

1,如果嫌unity自带的image effect机制有太多黑箱,比如全屏quad位置和尺寸不详,所使用的投影矩阵不详,也可以自己搞custom的image effect机制来替换unity自带机制:自己用GL指令画全屏quad,自己push投影矩阵。参考:http://flafla2.github.io/2016/10/01/raymarching.html(这是一篇讲在unity中搭建raymarching环境的文章,其中采用了自定义image effect机制的做法)。

2,在网上搜到一些其它重建源码:

https://github.com/zezba9000/UnityMathReference/tree/master/Assets/Shaders/DepthBuffToWorldPos
(这个我仔细测试了一下,效果是正确的,但其DepthBuffToWorldPosDemo.cs中计算clipToWorld的方法有点儿怪,我没理解)

https://github.com/keijiro/DepthToWorldPos

(这个没细测,感觉也是正确的)

----补充2

进一步验证,用重建的世界坐标(与一张shadow map配合)生成的阴影:

由此进一步证明了重建结果的正确性。

unity, 在image effect shader中用_CameraDepthTexture重建世界坐标的更多相关文章

  1. Unity内置的shader include files

    Unity内置的shader include files:这些文件都以.cninc结尾, HLSLSupport.cginc:自动包含,一些跨平台编译相关的宏和定义. UnityShaderVaria ...

  2. 【Unity Shaders】Mobile Shader Adjustment—— 什么是高效的Shader

    本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...

  3. unity 切圆角矩形 --shader编程

    先上个效果图 制作思路 如上图我们要渲染的就是上图带颜色的部分 步骤: 先获取黄色和蓝绿部分 例如以下图 算法 |U|<(0.5-r)或|V|<(0.5-r) 注意的是模型贴图最大值是1. ...

  4. Unity进阶之:Shader渲染

    版权声明: 本文原创发布于博客园"优梦创客"的博客空间(网址:http://www.cnblogs.com/raymondking123/)以及微信公众号"优梦创客&qu ...

  5. 【原创翻译】初识Unity中的Compute Shader

    一直以来都想试着自己翻译一些东西,现在发现翻译真的很不容易,如果你直接把作者的原文按照英文的思维翻译过来,你会发现中国人读起来很是别扭,但是如果你想完全利用中国人的语言方式来翻译,又怕自己理解的不到位 ...

  6. Unity Shaders Vertex & Fragment Shader入门

    http://blog.csdn.net/candycat1992/article/details/40212735 三个月以前,在一篇讲卡通风格的Shader的最后,我们说到在Surface Sha ...

  7. 【Unity Shaders】Mobile Shader Adjustment —— 为手机定制Shader

    本系列主要參考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同一时候会加上一点个人理解或拓展. 这里是本书全部的插图.这里是本书所需的代码和 ...

  8. Unity 3D动态修改Shader状态,使物体透明等等

    Unity动态改Shader状态透明 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- ...

  9. unity中使用自定义shader进行光照贴图烘培无法出现透明度的坑爹问题

    最近开发中在对场景进行光照贴图烘焙时发现一个坑爹问题,在使用自定义shader的时候,shader命名中必须包含Transparent路径,否则烘焙的时候不对alpha通道进行计算,烘焙出来都是狗皮膏 ...

随机推荐

  1. Asp.Net Core 2.0 项目实战(5)Memcached踩坑,基于EnyimMemcachedCore整理MemcachedHelper帮助类。

    Asp.Net Core 2.0 项目实战(1) NCMVC开源下载了 Asp.Net Core 2.0 项目实战(2)NCMVC一个基于Net Core2.0搭建的角色权限管理开发框架 Asp.Ne ...

  2. BZOJ1901 Zju2112 Dynamic Rankings 主席树

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1901 题意概括 给你一段序列(n个数),让你支持一些操作(共m次), 有两种操作,一种是询问区间第 ...

  3. 2.2博客系统 |FileField字段 |Media配置

    基于forms组件和Ajax实现注册功能 1 基于forms组件设计注册页面 --点击头像 === 点击input --头像预览: 修改用户选中的文件对象:获取文件对象的路径:修改img的src属性, ...

  4. 基于Spring Boot的微服务搭建

    环境: 项目结构: 关键配置 pom.xml <?xml version="1.0" encoding="UTF-8"?> <project ...

  5. Android入门笔记

    Android项目的目录结构(Eclipse版) src:项目源代码文件夹 R.java:存放项目中所有资源文件的资源id,永远不要修改 Android.jar:Android的jar包,导入此包方可 ...

  6. iptables转发端口

    1.本机端口转发 把发往本机80端口的数据重定向到8080端口 iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-por ...

  7. 二分图带权匹配 KM算法与费用流模型建立

    [二分图带权匹配与最佳匹配] 什么是二分图的带权匹配?二分图的带权匹配就是求出一个匹配集合,使得集合中边的权值之和最大或最小.而二分图的最佳匹配则一定为完备匹配,在此基础上,才要求匹配的边权值之和最大 ...

  8. git 修改文件内容

    在安装Git和创建版本库的时候,我们已经成功地添加并提交了一个readme.txt文件,现在,是时候继续工作了,于是,我们继续修改readme.txt文件,改成如下内容  [root@node1 gi ...

  9. SQL数据库连接到服务器出错——无法连接到XXX

    问题:Windows或者SQL Server身份验证下,出现连接到服务器出错 解决方式: 1.检查实例名称是否正确,如下 根据自己电脑的实际名称修改修改如下: 1)Microsoft SQL Serv ...

  10. Android HttpURLConnection.connect找不到源 HttpURLConnection连接失败 HttpURLConnection.connect IO异常 解决办法

    Android HttpURLConnection.connect找不到源  HttpURLConnection连接失败 HttpURLConnection.connect IO异常 解决办法 以下代 ...