首页 > 编程知识 正文

unity 深度图,unity可视化shader

时间:2023-05-05 19:57:53 阅读:28845 作者:3744

title :单元着色器深度图及其应用

类别: unity 3d-shader

tags: [unity,shader,深度贴图,深度]

date :2019-05-1320336044336051

comments :全单元着色器深度图及其应用

上一篇Unity Shader -深度贴图基础和应用(比较详细地记录深度贴图(https://www.Jian Shu.com/p/80a 932 D1 f 11e深度值精度(https://learn OpenGL-cn.readthedocs #_3深度碰撞- https://learn OpenGL-cn.readthedocs.io/zh/latest/04高级操作/01 dengl _5unity shader基础(3)获取深度纹理6655546 .要在html中渲染深度贴图,必须将Camera组件的depthTextureMode深度位设置为1 (或)

用户单元引擎; publicclassdepthtexturetest : mono behaviour (voidonenable ) { getcomponentcamera }.depthtexturemode|=depthtexturemoduremode }然后在shader中定义统一变量。 类型必须为sampler2D,名称必须为_CameraDepthTexture

sampler2D _CameraDepthTexture; //对深度贴图进行采样,然后在模型的屏幕坐标(0,1 )区间对场景深度贴图进行采样(场景深度值)非线性的) 0, 1 )区间) float depth=sample _ depth _ texture _ proj ) _cameradepthttth深度贴图Unity Shader -深度贴图的基础和应用(详细介绍(https://www.jw.jtth )

深度贴图与深度缓存不同

所谓深度图,是预先渲染所有不透明物体而得到的深度缓存,是在渲染各个物体时,基于所提供的深度比较条件而写入的值.

: [请参见“透明物体写入深度姿势”(#透明物体写入深度姿势)

深度纹理来自特定的过程,而不是来自深度缓冲区中的数据。

深度映射与深度缓存Unity4.X和Unity5.X版本的实现方式不同。 Unity4.X是在" RenderType "选项卡中用相机材质球替换检索的,Unity5是在材质球集群路径中检索的。 Unity5官方文件载有:

depthtextureisrenderedusingthesameshaderpassesasusedforshadowcasterrendering (shadowcasterpasstype ).So by extension, ifashaderdoesnotsupportshadowcasting (I.e.there’snoshadowcasterpassintheshaderoranyofthefallbacks ),thenobjectsusingtingttion

makeyourshaderfallbacktosomeothershaderthathasashadowcastingpass,orifyou’reusingsurfaceshaders,addinganaddshadowdirectiviveretivers

notethatonly " opaque " objects (that

which have their materials and shaders setup to use render queue <= 2500) are rendered into the depth texture.

对于自身带有 ShadowCaster Pass 或者 FallBack 中含有,并且 Render Queue 小于等于 2500 的渲染对象才会出现在深度纹理中,详细的测试可以参考:【Unity Shader】Shadow Caster、RenderType和_CameraDepthTexture

深度图里存放了**[0,1]范围的非线性分布的深度值,这些深度值来自NDC坐标。
在延迟渲染中,深度值默认已经渲染到G-buffer;而在前向渲染中,你需要去
申请**,以便Unity在背后利用Shader Replacement将RenderType为Opaque、渲染队列小于等于2500并且有ShadowCaster Pass的物体的深度值渲染到深度图中。

实际测试

即使关了 深度写入 ZWrite Off , 深度图 还是有这个对象的深度信息. (使用 framedebugger 调试)

注意

需要注意的是 能量场 ( 透明渲染 ) _CameraDepthTexture 中只保存了场景中不透明物体的深度信息,因此这个时候无法从CameraDepthTexture 中获取 能量场 的深度信息,所以要在 vert 中计算顶点的深度,这里我利用了 COMPUTE_EYEDEPTH 这个内置的宏。在之后的 frag 内就可以很方便的获取场景和能量场当前片元的深度了。
参考: http://www.php361.com/index.php?c=index&a=view&id=5257

//verto.screenPos = ComputeScreenPos(o.vertex);COMPUTE_EYEDEPTH(o.screenPos.z);//fragfloat sceneZ = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(i.screenPos)));float partZ = i.screenPos.z; 相交判断

以上面 能量场 (ForceField) 为例, ForceField 丢到透明度队列渲染, 则该物体不会再就不会写入到深度图中, 从 Frame Debug 中可以看出

所以可以用 vert 计算出 深度值, 与 深度图 中的值 ( 也就是场景中 不透明 物体的z值 ) 相比较, 小于某个阈值时可以定义为相交.

//verto.screenPos = ComputeScreenPos(clipPos); // ComputeScreenPos 的参数是剪裁空间下的位置COMPUTE_EYEDEPTH(o.screenPos.z); // 计算出 顶点位置 视空间 的 z 值, 保存到 o.screenPos.z //fragfloat depth = SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(i.screenPos)); // 用模型的 屏幕坐标([0, 1]区间) 去 采样 场景深度图 获取场景 深度值float sceneZ = LinearEyeDepth(depth); // 把 深度值 转换到 视空间float partZ = i.screenPos.z;// 两者相减就是深度的差异diff,再用1 - diff就得到了一个“相交程度”。float diff = sceneZ - partZ; // 两个值都在同一空间下, 就可以做比较了float intersect = (1 - diff) * _IntersectPower; 相关宏 #define COMPUTE_EYEDEPTH(o) o = -UnityObjectToViewPos( v.vertex ).z # 计算出 视空间 的 z 值# define SAMPLE_DEPTH_TEXTURE_PROJ(sampler, uv) (tex2Dproj(sampler, uv).r)#define UNITY_PROJ_COORD(a) a LinearEyeDepth 与 Linear01Depth 的使用场景

两者的共同点是 参数都是 用从 深度图 中采样出来的 深度值.

//verto.screenPos = ComputeScreenPos(clipPos); // ComputeScreenPos 的参数是剪裁空间下的位置//fragfloat depth = SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(i.screenPos));

LinearEyeDepth

可以用在 物体a 需要与场景的 深度值 作比较, 进而判断出是否相交. 此时需要保证 物体a 不会渲染都深度图中, 不然不能做比较. 可以参考 [深度图 不等于 深度缓存](#深度图 不等于 深度缓存)

比较的两个值需要转换到 同一空间 下 (一般就是是 视空间) 才能进行比较, 具体代码可以参考 相交判断

Linear01Depth

可以用在 控制的值 (材质球暴露出来设置) 与 深度值 作比较, 所以要把 深度值 约束在 [0, 1] 区间内就得用到这个函数. 控制的值 就可以在 [0,1] 区间与 深度比较了.

例如扫描线效果

float4 frag_depth(v2f_img i) : SV_Target { float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv); float lnr01Depth = Linear01Depth(depth); fixed4 screenTexture = tex2D(_MainTex, i.uv); float near = smoothstep(_ScanValue, lnr01Depth, _ScanValue - _ScanLineWidth); // _ScanValue 就是 控制值, 在 [0, 1] 区间 float far = smoothstep(_ScanValue, lnr01Depth, _ScanValue + _ScanLineWidth); fixed4 emissionClr = _ScanLineColor * (near + far); return screenTexture + emissionClr;}

后处理直接绘制 深度图

float4 frag_depth(v2f_img i) : SV_Target { float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv); float lnr01Depth = Linear01Depth(depth); return fixed4(lnr01Depth, lnr01Depth, lnr01Depth, 1);}

透明 ( transparent ) 物体写入深度的姿势

参考: Unity3D - Shader - 开启深度写入的半透明效果 - https://blog.csdn.net/zrdfh/article/details/78690574

正常来说 透明物体 是不会写入深度的, 但是可以通过增加多一个 pass 只用来写入深度, 但不输出颜色.

注意: 即使通过增加 深度写入pass 的方式, 也不能将该物体写入到 深度图 中, 因为pass只在正常渲染下起作用.

Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}// 仅仅是把模型的深度信息写入深度缓冲中// 从而剔除模型中被自身遮挡的片元Pass { // 开启深度写入 ZWrite On // 用于设置颜色通道的写掩码(Wirte Mask) // ColorMask RGB|A|0|(R/G/B/A组合) // 当为0时意味着该Pass不写入任何颜色通道,也就不会输出任何颜色 ColorMask 0}

实测一下, 将透明物体的渲染设为 1000, 让它比 opaque 更快渲染

有深度写入pass的结果. 可以正常遮挡后面渲染的 胶囊体 , 同时和天空盒混合了

没有深度写入pass的结果, 不能遮挡 胶囊体

将透明物体的渲染设为 3000, 让它比 opaque 更后渲染, 就正常可以正常混合到 胶囊体, 应为颜色缓存区已经有了胶囊体的颜色了.

踩坑 如果代码没错,而看到的是全黑的,那么应该就是摄像机的Far Clip Plane设得太大。 深度值 推到 世界坐标位置

Unity3D 片元NDC空间z值(ZBuffer)转View空间z值,公式推导 - https://blog.csdn.net/u012149999/article/details/78678901

全面认识Depth - 这里有关于Depth的一切 - https://zhuanlan.zhihu.com/p/25095708

shader 推导流程, 可以参照 运动模糊

//使用宏和纹理坐标对深度纹理进行采样,得到深度值float d = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv_depth);//构建当前像素的NDC坐标,xy坐标由像素的纹理坐标映射而来,z坐标由深度值d映射而来float4 H = float4(i.uv.x * 2 - 1, i.uv.y * 2 - 1, d * 2 - 1, 1);//使用 当前帧的视角 * 投影矩阵 的逆矩阵 对H进行变换float4 D = mul(_CurrentViewProjectionInverseMartix, H);//把结果除以它的w分量,得到该像素世界空间下的坐标float4 worldPos = D / D.w;

为什么要除以 分量w ? 参考说明 剪裁坐标

因为经过了 投影矩阵, 分量w 就不在为1, 所以要求得具体的世界坐标, 就需要 除以 分量w 的影响

深度偏移

Offset 修改深度偏移值

Pass{Name "FORWARD" Tags { "LightMode" = "ForwardBase" }ZWrite OnOffset 3000,0

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。