unity中采样深度图的结果处理

本文围绕深度图应用展开,介绍了LinearEyeDepth和Linear01Depth函数。重点阐述通过深度图重建世界坐标系的两种方法,一是逆矩阵方式,虽能实现转换但性能差;二是屏幕射线插值方式。还说明了计算ScreenUV的方式,可用于采样深度图。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

此篇内容是基于深度图的应用的说明,对深度图不清楚的,请查看:
深度图的说明

  1. 关于相机的深度侧视图:
    在这里插入图片描述深度:存的是Z值,不是此点到相机的距离(例如 G点的深度是AH,但是AG是G点到相机的距离)
    (1)第二个函数 LinearEyeDepth
    此函数返回就是相机空间中的Z值
    (2)第一个函数:Linear01Depth
    此函数的返回值是(0,1)的线性值,也是相机空间(视角空间)中的
    0:相机的位置是0
    1:远裁剪平面是1
    在相机空间中的Z值是深度最原始的值,将Z值/原裁剪平面far,就转换到了(0,1)的范围内
    此处附上《Shader入门精要》中的推到过程:
    采样深度图推导过程请点击此处查看。

下面通过深度图重建世界坐标系:

(方法一)逆矩阵方式重建

:在frag着色器中得到uv坐标(已经进行过齐次除法,且已经由【-1,1】换算到【0,1】),采样深度图得到Clip裁剪空间中的Z值
所以就得到了Clip裁剪空间中的 坐标(x,y,z).然后乘以VP矩阵的逆矩阵,就转换到世界空间中的坐标(记得/.w)
下面是逆推的演示:
条件:已知条件(M为VP矩阵,M^-1即为其逆矩阵,Clip为裁剪空间,ndc为标准设备空间,world为世界空间):
(1)
ndc = Clip.xyzw / Clip.w = Clip / Clip.w

world = M^-1 * Clip

二者结合得:

world = M ^-1 * ndc * Clip.w
(2)
我们已知M和ndc,然而还是不知道Clip.w,但是有一个特殊情况,是world的w坐标,经过变换后应该是1,即

1 = world.w = (M^-1 * ndc).w * Clip.w

进而得到Clip.w = 1 / (M^ -1 * ndc).w

带入上面等式得到:

world = (M ^ -1 * ndc) / (M ^ -1 * ndc).w

所以,世界坐标就等于ndc进行VP逆变换之后再除以自身的w。
(3)缺点
不过这种方式重建世界坐标,性能比较差,一般来说,我们都是逐顶点地进行矩阵运算,毕竟定点数一般还是比较少的,但是全屏幕逐像素进行矩阵运算,这个计算量就不是一般的大了,性能肯定是吃不消的。

(方法二):屏幕射线插值方式重建视空间坐标

在这里插入图片描述假如我们得到了 相机在世界空间中的位置A,并且已知一个方向向量AG
那么:G点在世界空间中的位置 = 世界空间相机位置A 沿着AG方向 平移AG的长度

代码和实现方式如下:

重建世界坐标系

(3) 计算ScreenUV ,的方式:

  1. 在vertex中 使用 ComputeScreenPos 函数计算:
    此函数执行齐次除法, 归一化, 这两个步骤混合起来就是 下面的计算
// 
float4 ComputeScreenPos(float4 positionCS)
{
    float4 o = positionCS * 0.5f;
    o.xy = float2(o.x, o.y * _ProjectionParams.x) + o.w;
    o.zw = positionCS.zw;
    return o;
}
  1. 在vertex中计算的 pos : SV_POSITION
    (1) 此pos 在vertex中是齐次裁剪坐标
    (2)此pos 在fragment中是 屏幕坐标 (屏幕坐标的范围:(0,0)到 (width,hight)),在fragment中计算,视口坐标 直接用 pos / 屏幕宽高
    (3)用上面的结果,采样 _CameraDepthTexture得到缓冲区存储的深度
struct Fragment 
{
    float2 positionSS;
    // 屏幕坐标
    float2 screenUV;
    // 此点自身在视图空间的深度
    float depth;
    // 在深度图中存储的深度(可能不是此点本身的深度)
    float bufferDepth;
};



///
// positionSS  是传入的  positionSS :SV_POSITION的值

// 在Vertex 函数中    positionSS  是齐次裁剪坐标,此时并未进行齐次除法 也 没有归一化
// 在 Fragment函数中  positionSS 是屏幕坐标 (此时 距离转换到 视口坐标 screenUV 坐标, 就差一个 屏幕宽高的缩放了)


Fragment GetFragment(float4 positionSS)
{
    Fragment f;
    f.positionSS = positionSS.xy;
    f.screenUV = f.positionSS / _ScreenParams.xy;
    
    // 正交相机的深度   存储在 w 分量中
    f.depth = IsOrthographicCamera() ? OrthographicDepthBufferToLinear(positionSS.z) : positionSS.w;
    f.bufferDepth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, sampler_point_clamp, f.screenUV);  
    f.bufferDepth = IsOrthographicCamera() ? OrthographicDepthBufferToLinear(f.bufferDepth) : LinearEyeDepth(f.bufferDepth,_ZBufferParams);
    return f;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值