时间:2025-08-24 20:48
人气:
作者:admin
【从UnityURP开始探索游戏渲染】专栏-直达
_ZTestMode对应深度测试枚举值:
_ZWrite控制深度缓冲写入(0=Off,1=On)Shader "Custom/URP_ZTestExample"
{
Properties
{
_MainTex("Base Texture", 2D) = "white" {}
_Color("Tint Color", Color) = (1,1,1,1)
[Enum(UnityEngine.Rendering.CompareFunction)]
_ZTestMode("ZTest Mode", Int) = 4 // 默认LEqual
[Toggle]_ZWrite("ZWrite", Float) = 1
}
SubShader
{
Tags {
"RenderType"="Opaque"
"RenderPipeline"="UniversalRenderPipeline"
"Queue"="Geometry"
}
Pass
{
// ShaderLab命令配置
ZTest [_ZTestMode]
ZWrite [_ZWrite]
Cull Back
Blend Off
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
CBUFFER_START(UnityPerMaterial)
float4 _Color;
int _ZTestMode;
float _ZWrite;
CBUFFER_END
TEXTURE2D(_MainTex);
SAMPLER(sampler_MainTex);
struct Attributes
{
float4 positionOS : POSITION;
float2 uv : TEXCOORD0;
};
struct Varyings
{
float4 positionHCS : SV_POSITION;
float2 uv : TEXCOORD0;
};
Varyings vert(Attributes IN)
{
Varyings OUT;
OUT.positionHCS = TransformObjectToHClip(IN.positionOS.xyz);
OUT.uv = IN.uv;
return OUT;
}
half4 frag(Varyings IN) : SV_Target
{
half4 col = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, IN.uv) * _Color;
return col;
}
ENDHLSL
}
}
}
通过ShaderLab命令ZTest可设置深度测试比较规则,支持以下选项:
Less:深度小于当前缓存则通过(默认值)Greater:深度大于当前缓存则通过LEqual:深度小于等于当前缓存则通过GEqual:深度大于等于当前缓存则通过Equal:深度等于当前缓存则通过NotEqual:深度不等于当前缓存则通过Always:始终通过(等同于关闭深度测试)场景深度纹理,存储非线性深度值(0-1范围)
启用要求:URP Asset中勾选 Depth Texture 选项
着色器声明:
hlsl
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
_CameraOpaqueTextureCore.hlsl)hlsl
float linearDepth = LinearEyeDepth(depthSample, _ZBufferParams); // 转换为线性深度
float normalizedDepth = Linear01Depth(depthSample, _ZBufferParams); // [0,1]归一化
Opaque Downsampling:调整不透明纹理分辨率(None/2x/4x)_CameraDepthNormalsTexture,需通过 Renderer Feature 手动实现ZTest 指令动态调整(如 ZTest Greater)Shader "Custom/WaterDepth"
{
Properties
{
[MainTexture] _MainTex("Base (RGB)", 2D) = "white" {}
_DepthFactor("Depth Factor", Range(0,1)) = 0.5
}
SubShader
{
Tags
{
"Queue"="Transparent"
"RenderType"="Transparent"
"RenderPipeline"="UniversalRenderPipeline"
}
Pass
{
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
TEXTURE2D(_MainTex);
SAMPLER(sampler_MainTex);
CBUFFER_START(UnityPerMaterial)
float4 _MainTex_ST;
float _DepthFactor;
CBUFFER_END
struct Attributes
{
float4 positionOS : POSITION;
float2 uv : TEXCOORD0;
};
struct Varyings
{
float4 positionHCS : SV_POSITION;
float4 screenPos : TEXCOORD0;
float2 uv : TEXCOORD1;
};
Varyings vert(Attributes IN)
{
Varyings OUT;
OUT.positionHCS = TransformObjectToHClip(IN.positionOS.xyz);
OUT.screenPos = ComputeScreenPos(OUT.positionHCS);
OUT.uv = TRANSFORM_TEX(IN.uv, _MainTex);
return OUT;
}
half4 frag(Varyings IN) : SV_Target
{
float2 screenUV = IN.screenPos.xy / IN.screenPos.w;
float depth = SampleSceneDepth(screenUV);
depth = LinearEyeDepth(depth, _ZBufferParams);
float sceneZ = depth - IN.screenPos.w;
float waterDepth = saturate(sceneZ * _DepthFactor);
half4 col = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, IN.uv);
col.a = waterDepth;
return col;
}
ENDHLSL
}
}
}
Shader "Hidden/DepthOfField"
{
SubShader
{
Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalRenderPipeline" }
Cull Off
ZWrite Off
ZTest Always
Pass
{
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
TEXTURE2D(_MainTex);
SAMPLER(sampler_MainTex);
CBUFFER_START(UnityPerMaterial)
float _FocusDistance;
float _BlurSize;
CBUFFER_END
struct Attributes
{
float4 positionOS : POSITION;
float2 uv : TEXCOORD0;
};
struct Varyings
{
float4 positionHCS : SV_POSITION;
float2 uv : TEXCOORD0;
};
Varyings vert(Attributes IN)
{
Varyings OUT;
OUT.positionHCS = TransformObjectToHClip(IN.positionOS.xyz);
OUT.uv = IN.uv;
return OUT;
}
half4 frag(Varyings IN) : SV_Target
{
float depth = SampleSceneDepth(IN.uv);
depth = Linear01Depth(depth, _ZBufferParams);
float blur = saturate(abs(depth - _FocusDistance) * _BlurSize);
half4 col = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, IN.uv);
col.rgb = lerp(col.rgb, col.rgb * 0.5, blur);
return col;
}
ENDHLSL
}
}
}
Shader "Custom/StencilDepth"
{
Properties
{
[MainTexture] _MainTex("Texture", 2D) = "white" {}
_StencilRef("Stencil Ref", Int) = 1
}
SubShader
{
Tags
{
"Queue"="Geometry"
"RenderPipeline"="UniversalRenderPipeline"
}
Stencil
{
Ref [_StencilRef]
Comp Less
Pass Replace
}
Pass
{
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
TEXTURE2D(_MainTex);
SAMPLER(sampler_MainTex);
CBUFFER_START(UnityPerMaterial)
float4 _MainTex_ST;
int _StencilRef;
CBUFFER_END
struct Attributes
{
float4 positionOS : POSITION;
float2 uv : TEXCOORD0;
};
struct Varyings
{
float4 positionHCS : SV_POSITION;
float2 uv : TEXCOORD0;
};
Varyings vert(Attributes IN)
{
Varyings OUT;
OUT.positionHCS = TransformObjectToHClip(IN.positionOS.xyz);
OUT.uv = TRANSFORM_TEX(IN.uv, _MainTex);
return OUT;
}
half4 frag(Varyings IN) : SV_Target
{
return SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, IN.uv);
}
ENDHLSL
}
}
}
URP Asset配置
启用深度纹理生成:
Project Settings > Graphics > URP Global Settings → 勾选Depth Texture选项。
Renderer Data设置
在使用的Renderer Asset(如UniversalRenderer_Forward)中:
→ 添加SSAO效果(Screen Space Ambient Occlusion)
→ 将SSAO的Source属性设为Depth
此操作强制URP启用DepthPrepass通道渲染静态物体深度到_CameraDepthTexture。
Edit > Project Settings > PlayerOther Settings面板中勾选Static Batching选项Frame Debugger检查合批效果,确认是否存在SRP Batch或Static Batch条目Window > Analysis > Frame Debugger
UNITY_REVERSED_Z)Shader队列要求
动态物体Shader需使用不透明渲染队列:
Tags {
"Queue"="Geometry" // 半透明队列无法使用深度图
"RenderType"="Opaque"
}
深度采样声明
在动态物体的Shader中显式声明深度纹理:
hlsl
TEXTURE2D(_CameraDepthTexture);
SAMPLER(sampler_CameraDepthTexture);
摄像机设置
确保动态物体所在摄像机的渲染路径:
csharpCopy Code
var cameraData = camera.GetUniversalAdditionalCameraData();
cameraData.requiresDepthTexture = true;// 强制深度纹理可用
RenderPass优先级
DepthPrepass默认在阴影渲染后执行,优先于CopyDepth Pass。动态物体深度通过后续的CopyDepth Pass复制到同一_CameraDepthTexture。
Frame Debugger检查
开启Window > Analysis > Frame Debugger:
→ 确认存在DepthPrepass通道(静态物体深度)
→ 检查CopyDepth通道是否处理动态物体深度
深度值测试
在Shader中输出线性深度验证:
hlsl
float depth = SampleSceneDepth(uv);
depth = Linear01Depth(depth, _ZBufferParams);
return float4(depth.xxx, 1); // 灰度图显示深度
UNITY_REVERSED_Z宏判断)。【从UnityURP开始探索游戏渲染】专栏-直达
(欢迎点赞留言探讨,更多人加入进来能更加完善这个探索的过程,????)