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通道进行计算,烘焙出来都是狗皮膏 ...
随机推荐
- Asp.Net Core 2.0 项目实战(4)ADO.NET操作数据库封装、 EF Core操作及实例
Asp.Net Core 2.0 项目实战(1) NCMVC开源下载了 Asp.Net Core 2.0 项目实战(2)NCMVC一个基于Net Core2.0搭建的角色权限管理开发框架 Asp.Ne ...
- BZOJ3514 Codechef MARCH14 GERALD07加强版 LCT
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ3514 题意概括 N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数. N ...
- ATM+购物车商城
模拟实现一个ATM + 购物商城程序 额度 15000或自定义 实现购物商城,买东西加入 购物车,调用信用卡接口结账 可以提现,手续费5% 支持多账户登录 支持账户间转账 记录每月日常消费流水 提供还 ...
- Ubuntu 下常用命令
整理一下比较常用的操作命令: 附上一个Linux 命令大全: http://man.linuxde.net/ 打开终端:Ctrl+Alt+T ls: ls : 查看当前路径下的文件夹以及文件 ls + ...
- 洛谷P1926 小书童—刷题大军【01背包】
题目链接:https://www.luogu.org/problemnew/show/P1926 题目背景 数学是火,点亮物理的灯:物理是灯,照亮化学的路:化学是路,通向生物的坑:生物是坑,埋葬学理的 ...
- Mongodb - 二进制安装
0.概述 mongodb版本:4.0.2 linux版本:redhat 6.5 安装方式:二进制安装 1.关闭防火墙 /etc/init.d/iptables status/etc/init.d/ip ...
- 关于 tensorflow-gpu 中 CUDA 和 CuDNN 版本适配问题
问题 今天在使用 tensorflow-yolov3 的时候,发现报错 Loaded runtime CuDNN library: but source was compiled with: . Cu ...
- Jackson ObjectMapper readValue过程
1.整体调用栈 2.看一下调用栈的两个方法 resolve 方法中通过 Iterator i$ = this._beanProperties.iterator() 遍历属性的所有子属性,缓存对应的 d ...
- Spring框架学习06——AOP底层实现原理
在Java中有多种动态代理技术,如JDK.CGLIB.Javassist.ASM,其中最常用的动态代理技术是JDK和CGLIB. 1.JDK的动态代理 JDK动态代理是java.lang.reflec ...
- Java并发程序设计(十一)设计模式与并发之生产者-消费者模式
设计模式与并发之生产者-消费者模式 生产者-消费者模式是一个经典的多线程设计模式.它为多线程间的协作提供了良好的解决方案.在生产者-消费者模式中,通常由两类线程,即若干个生产者线程和若干个消费者线程. ...