unity, 在image effect shader中用_CameraDepthTexture重建世界坐标
--------------更新
更简单的方法:
//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重建世界坐标的更多相关文章
- Unity内置的shader include files
Unity内置的shader include files:这些文件都以.cninc结尾, HLSLSupport.cginc:自动包含,一些跨平台编译相关的宏和定义. UnityShaderVaria ...
- 【Unity Shaders】Mobile Shader Adjustment—— 什么是高效的Shader
本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...
- unity 切圆角矩形 --shader编程
先上个效果图 制作思路 如上图我们要渲染的就是上图带颜色的部分 步骤: 先获取黄色和蓝绿部分 例如以下图 算法 |U|<(0.5-r)或|V|<(0.5-r) 注意的是模型贴图最大值是1. ...
- Unity进阶之:Shader渲染
版权声明: 本文原创发布于博客园"优梦创客"的博客空间(网址:http://www.cnblogs.com/raymondking123/)以及微信公众号"优梦创客&qu ...
- 【原创翻译】初识Unity中的Compute Shader
一直以来都想试着自己翻译一些东西,现在发现翻译真的很不容易,如果你直接把作者的原文按照英文的思维翻译过来,你会发现中国人读起来很是别扭,但是如果你想完全利用中国人的语言方式来翻译,又怕自己理解的不到位 ...
- Unity Shaders Vertex & Fragment Shader入门
http://blog.csdn.net/candycat1992/article/details/40212735 三个月以前,在一篇讲卡通风格的Shader的最后,我们说到在Surface Sha ...
- 【Unity Shaders】Mobile Shader Adjustment —— 为手机定制Shader
本系列主要參考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同一时候会加上一点个人理解或拓展. 这里是本书全部的插图.这里是本书所需的代码和 ...
- Unity 3D动态修改Shader状态,使物体透明等等
Unity动态改Shader状态透明 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- ...
- unity中使用自定义shader进行光照贴图烘培无法出现透明度的坑爹问题
最近开发中在对场景进行光照贴图烘焙时发现一个坑爹问题,在使用自定义shader的时候,shader命名中必须包含Transparent路径,否则烘焙的时候不对alpha通道进行计算,烘焙出来都是狗皮膏 ...
随机推荐
- BZOJ5091 摘苹果 BZOJ2017年11月月赛 概率,期望
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ5091 11月月赛B题 题意概括 题解 代码 #include <cstring> #i ...
- BZOJ1202 [HNOI2005]狡猾的商人 spfa
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1202 题意概括 有一个数列,共n个数字. 告诉你m个区间和,问是否矛盾. 数据组数<=100 ...
- HDU Tody HDU2112
不想用floyd了 也不一定适合 floyd只能处理小数据 dijkstra算法 wa了很久 一个是dijkstra里面的u 导致RE了无数次 下标溢出 还有就是注意细节 当起点和终点 ...
- Java Web 之javabeans
Java遇见HTML——JSP篇之JavaBeans: http://www.cnblogs.com/Qian123/p/5277425.html
- 如何安装破解Unity, 以5.6.1为例
1.Unity官方网址:http://unity3d.com 系统会根据网址IP,自动转到中国区,网址变为:http://unity3d.com/cn/ 点击“获取Unity” 2.选择Person ...
- BeanUtils进行日期格式的拷贝转换
自定义Converter的方法: import java.text.ParseException; import java.text.SimpleDateFormat; import org.apac ...
- 类属性判断 hasattr getattr
- laravel5 项目上线后务必将开发环境更改为生产环境
如果以开发环境上线,出错信息将全通过json暴露出来了,屏蔽方式如下: .env 文件设置如下APP_ENV=productionAPP_DEBUG=false 改完设置后把缓存清理一遍 如果更改后清 ...
- FastAdmin 如何隐藏操作栏中的“删除”按钮“?
刚刚在群里看到有人询问如何隐藏(删除)操作栏中的”删除”按钮,如下这个. 我也不会,在论坛上也没找到,但有找到一篇关于根据条件怎么隐藏按钮的问题,Karson 老大有提供的解决方法.我就照样画葫芦写了 ...
- Linux学习之用户配置文件详解(十四)
Linux学习之用户配置文件详解 目录 用户信息文件/etc/password 影子文件/etc/shadow 组信息文件/etc/group 组密码文件/etc/gshadow 用户信息文件/etc ...