Unity 深度 depth (URP)

本文基于Unity URP,对深度相关知识进行整理。介绍了Eye Depth,即物体相对摄像机平面的距离,还提及ComputeScreenPos的作用;阐述深度图,包括其存储及采样方法;最后讲述根据深度重建世界坐标的多种方法,如逆推、射线法等。

本文只是对深度的一些整理和个人理解,如果有不对的地方,请一定要告诉我。演示基于Unity URP, shader用shader graph 或者HLSL,build-in自行根据对照表更改

1. Eye Depth(观察空间)

Eye Depth是物体相对于摄像机所在平面的距离,因为是相对,所以Z是相反的,Eye Depth的0就是摄像机,1就是一个单位,10就是10个单位,所以有的人会把他称为“World” space Depth,这个depth在所有平台上都是一样的,而且不区分正交透视,因为他在投影之前。在shader graph 中如何得到片段的Eye Depth呢

正交或者投影

 只适用于透视

HLSL

第一种

// 顶点
float3 positionWS = TransformObjectToWorld(IN.positionOS.xyz);
float3 positionVS = TransformWorldToView(positionWS);
OUT.positionVS = positionVS;
// 片段
float fragmentEyeDepth = -IN.positionVS.z;

 第二种

//裁剪空间坐标
float4 positionCS 	= TransformWorldToHClip(input.positionOS.xyz);
OUT.positionCS 		= positionCS;
//求屏幕坐标
//一种方法是
float4 positionScr	= positionCS * 0.5f;
positionScr.xy 		= float2(positionScr.x, positionScr.y * _ProjectionParams.x) + positionScr.w;
positionScr.zw 		= positionCS.zw;
OUT.scrPos= positionScr;
//或者直接用URP封装的
OUT.scrPos= ComputeScreenPos(positionCS);//[-w,w]->[0,w]
//片段
float fragmentEyeDepth = IN.scrPos.w;

这边扯开了,先讲下ComputeScreenPos,他的作用是把裁剪空间齐次坐标转换到屏幕空间的齐次坐标 ,或者换句话说就是把xy取值范围从[-w,w] 转到 [0,w],然后再做透视除法(齐次除法),取值范围变成[0,1],就可以用来提取屏幕纹理了

注意 透视除法应该放在片段着色器里执行,不然会造成UV扭曲,因为片段着色器之前的光栅化会对几何数据做差值,而做差值前做除法会导致结果不准确

这个方法得到了屏幕齐次坐标,那么再经过透视除法,可以的到NDC,再走一步可以直接得到Z Buffer Depth,也就是深度纹理中的像素值

float3 ndcPos 		= IN.scrPos.xyz / IN.scrPos.w;//[0-1] D3D
float2 screenUV 	= ndcPos.xy;
float zdepth 		= ndcPos.z; 

对于D3D,NDC z取值范围已经是[0,1],所以可以直接相等,而openGL z在[-1,1],需要

z* 0.5 + 0.5

所以我常用的是第二种方法,因为可以顺便得到更多的信息

 PS:

NDC=

### Unity URP中的深度问题及其解决方案 #### 深度图配置与使用 在Unity的通用渲染管线(URP)中,为了正确处理场景中的物体遮挡关系以及实现诸如阴影、反射等效果,深度图的应用至关重要。对于不透明对象而言,在Shader中启用深度写入功能是必要的;而对于半透明对象,默认情况下不会参与深度测试也不更新深度缓冲区,这意味着如果希望某些特殊材质能够影响或响应其他几何体,则需特别设置。 当涉及到具体的Shader编写时,确保通过`DepthStencilState`来控制如何对待深度值是非常重要的[^2]: ```csharp Tags { "RenderType"="Opaque" } // 或者针对特定需求调整此标签 Pass { ZWrite On // 开启深度写入 } ``` 此外,在片段着色器阶段读取来自先前绘制通道所存储的距离信息前,先声明并初始化好相应的纹理资源和采样状态变量: ```hlsl TEXTURE2D(_CameraDepthTexture); SAMPLER(sampler_CameraDepthTexture); float rawZ = SAMPLE_TEXTURE2D(_CameraDepthTexture, sampler_CameraDepthTexture, i.uv).r; ``` 以上操作允许后续逻辑基于这些数据执行进一步计算,比如转换为视空间位置或是作为环境光散射强度衰减因子的一部分[^1]。 #### 解决SRP Batcher兼容性挑战 值得注意的是,在利用URP特性的同时还可能遇到性能优化工具——如SRP Batcher带来的新难题。由于该机制依赖于静态批处理技术减少Draw Call次数从而提高效率,因此任何引入额外关键字组合的情况都可能导致其失效。具体表现为含有条件编译指令(`#pragma multi_compile`)或其他动态变化属性(例如自定义光照模型参数) 的Material可能会被排除在外[^3]。 对此类情形的一个有效应对策略是在不影响核心视觉表现的前提下尽可能精简可选配置项数量,并考虑采用预烘焙方式代替运行时期望实时改变的部分内容。同时也要留意官方文档和技术社区内关于最新版本修复进展的消息,以便及时跟进最佳实践建议。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值