Re:《Unity Shader入门精要》13.3全局雾效--如何从深度纹理重构世界坐标

前排感谢评论区西瓜与拖鞋的指正,原本对于顶点着色器中得到的interpolatedRay的定义有误解,经过指正已经修改博文中的描述

如何从深度纹理重构世界坐标

游戏特效,后处理是必不可少的,而后处理经常需要我们得到当前画面的像素对应世界空间的所有信息。

思路

  1. 通过深度纹理取得NDC坐标,然后再通过NDC坐标还原成世界空间坐标
//csharp脚本部分
Matrix4x4 matrix = camera.projectionMatrix * camera * worldToCameraMatrix;
Matrix4x4 InverseMatrix = matrix.inverse;

//shader部分
float d = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv_depth);
float4 H = float4(i.uv.x * 2 - 1, i.uv.y * 2 - 1, d * 2 - 1, 1);
float D  = mul(InverseMatrix, H);
float worldPos = D/D.w

计算量比较大,一般用下面的方法。
2. 通过得到相机的坐标和世界空间下像素和相机的偏移量相加得到像素的世界坐标。这里偏移量通过顶点的线性深度乘以顶点着色器输出并被插值后所得的相机指向像素的射线来得到。

float4 worldPos = _WorldSpaceCameraPos + linearDepth * interpolatedRay;

接下来来介绍这种办法计算的过程。
我们很容易计算出相机到近平面四个顶点的向量方向以及世界空间下的长度,只需要得到相机记录的fov,aspect等信息
在这里插入图片描述
在这里插入图片描述
我们要得到的是像素的世界坐标。
这里有个很重要的点,相机能看到这个像素,必然说明原本的世界坐标的点和在近平面的投影点(像素位置)处于相机相机指向像素的射线的方向上。也就是下面13.7图。
在这里插入图片描述
所以问题转为如何得出相机到像素所对应的世界坐标的向量的长度
很幸运的是我们拥有深度纹理,所以13.7图的depth是已知的。
那么如何通过depth来得到dist,这里书本上举例的是TL点的计算。
在这里插入图片描述
书本上的interpolatedRay的长度并不是相机点指向近平面像素的长度,相机点指向近平面像素的真正向量是
dist * nor(interpolatedRay)
而在顶点着色器之中我们计算的是
i.interpolatedRay.xyz = scale * nor(interpolatedRay)
depth通过顶点着色器到片元着色器的过程中进行插值,且dist = scale * depth 从而在片元着色器上取得
depth * i.interpolatedRay.xyz
这里把interpolatedRay理解成相机点指向近平面像素的真正向量就行。
单单看这个点的计算是没问题的,自己手画一个就能得出结果。但关键是为什么所有点都满足,这里设世界坐标下任意一点A。
请添加图片描述
其和相机的连线经过近平面并产生交点
请添加图片描述
画出near向量
请添加图片描述
延长near到长度和A点的z变量,也就是depth一样长,并且做三角形OAB和ODC
这张有点乱,希望大家不要嫌弃,真的不太懂怎么安排线
请添加图片描述
很容易发现三角形ODC ~ 三角形OAB
得到长度关系
|near| / |interpolatedRay| = |depth| / |dist|
对任意点都是适用的

上文提到书本上的interpolatedRay是 scale * nor(interpolatedRay),
所以在片元着色器中乘上depth
对应书上片元着色器的部分就是这部分代码。
在这里插入图片描述

2D情况下

可能只想要得到近平面的像素点(平面本身构成的图片的像素)在世界空间下的位置,只需要计算出相机到近平面的四个顶点的向量直接插值,无需任何深度纹理的信息。
也就是书上的这部分代码无需乘scale
在这里插入图片描述
并且计算公式变为

float4 worldPos = _WorldSpaceCameraPos + interpolatedRay;

这样子的情况下,雾效的产生将和相机直接挂钩,相机的近平面就是雾效产生的地方,可以在2D游戏中使用。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 16
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值