找回密码
 立即注册
查看: 206|回复: 0

入门精要-第十三章-深度图原理理解

[复制链接]
发表于 2022-11-30 07:33 | 显示全部楼层 |阅读模式
写了卡渲的人物和树,已经用了两次深度图了,未来什么雪地脚印、水体都会用到,深感深度图的重要性,特开文章从头分析。
分析一下unity的深度图套餐。套餐真香,拿来就能吃,也没分析过组成成分。现在想自己做着吃喽!
原理


非线性分布、范围为[0,1]的高精度深度值被存在深度纹理中,通过NDC的z分量得到。
非线性


在MVP变换的最后一步,当我们使用透视投影矩阵时,这个变换就是非线性的。mvp变换完成后,还要进行齐次除法变换为NDC,即变到[-1,1]的立方体空间。


[0,1]


z分量范围为[-1,1],因此要做一个映射。d=0.5·zndc+0.5
深度纹理来源


使用延迟渲染路径,深度纹理可以访问到,因为延迟渲染会把这些信息渲染到G-buffer 中。
而当无法直接获取深度缓存时,深度和法线纹理是通过一个单独的Pass 渲染而得的。具体实现是, Unity 会使用着色器替换(Shader Replacement) 技术选择那些渲染类型(SubShader RenderType)为Opaque 的物体,将渲染队列小于等于2500 (AlphaTest以下)的物体渲染到深度和法线纹理中。即半透明不行。
URP中实现


开头定义
TEXTURE2D_X_FLOAT(_CameraDepthTexture); SAMPLER(sampler_CameraDepthTexture);
为啥要用_X_FLOAT,我猜是为Instancing和更高的精度考虑。(妹学呢,instancing,久仰大名,可惜快到期末,忙成狗)。
输出结构体中增加
float4 posScr: TEXCOORD7;
顶点着色器
v.posScr = ComputeScreenPos(v.posCS);
函数源码
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;}
ComputeScreenPos输入裁剪空间顶点坐标,_ProjectionParams.x在默认情况下是1(若使用翻转的投影矩阵则为-1),上述代码实际输出:
Outputx = clipx / 2 + clipw / 2;
Outputy = clipy / 2 + clipw / 2;
Outputz = clipz;
Outputw = clipw;
可以看出,这里的xy并不是真正的视口空间下的坐标,因此,要在片元着色器中除以它的w分量。

为什么不在ComputeScreenPos中除以w分量得到真正的屏幕空间坐标,因为如果Unity在顶点着色器中这么做的华,就会破坏从顶点到片元着色器的插值的结果。投影空间不是线性的,而插值是线性的。

经过除法操作后,我们可以得到该片元在视口空间的坐标了,也就是一个xy范围都在[0,1]之间的值。如果是透视投影 z[-Near,Far] w[Near,Far], 如果是正交投影 z[-1,1],w恒为1。

片元着色器
half2 screenUV = v.posScr.xy/v.posScr.w;half depth = SAMPLE_TEXTURE2D_X(_CameraDepthTexture, sampler_CameraDepthTexture, screenUV).r;half linearEyeDepth = LinearEyeDepth(depth, _ZBufferParams);
转换到线性空间原理不多看。先会用。
这样就得到了线性空间(视角空间)下的深度值啦。
引用
Shader学习笔记(三)学习Shader所需的数学基础

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-6-16 18:56 , Processed in 0.087565 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表