【渲染流水线】[逐片元阶段]-[模版测试]以UnityURP为例
[*]用于精确控制像素丢弃的逐片元操作,通过模板缓冲区(8位整数/像素)实现复杂遮罩效果。
[*]支持8种比较函数和6种缓冲操作
[*]当前模版操作,只能在Shader文件中书写操作,ShaderGraph中无法直接使用模版指令。
【从UnityURP开始探索游戏渲染】专栏-直达
核心配置预览
[*]核心配置所有配置列出(非全必要):
Stencil {
Ref 2 // 必要模版数值
ReadMask 255
WriteMask 255
Comp Greater // 必要比较操作符
Pass Replace // 必要通过后的操作
Fail Keep
ZFail DecrSat
}1. 核心配置命令
[*]Ref:设置参考值(0-255整数),用于与模板缓冲区比较
[*]ReadMask:读取掩码(0-255),按位与操作后比较(默认255)
[*]WriteMask:写入掩码(0-255),控制可修改的缓冲区位(默认255)
2. 比较函数命令
Comp支持以下枚举值:
[*]Always/Never:始终通过/拒绝
[*]Less/Greater:小于/大于时通过
[*]Equal/NotEqual:等于/不等于时通过
[*]LessEqual/GreaterEqual:小于等于/大于等于时通过
3. 操作命令
Pass/Fail/ZFail支持的操作:
[*]Keep:保持原值
[*]Zero:置零
[*]Replace:用Ref值替换
[*]IncrSat/DecrSat:饱和增减(0/255边界)
[*]IncrWrap/DecrWrap:循环增减
[*]Invert:按位取反
模板测试具体过程
[*]缓冲区初始化
[*]清除模板缓冲:GL.Clear(ClearBufferMask.StencilBufferBit)
[*]设置初始值:GL.StencilMask(0xFF)(默认全255)
[*]测试阶段-逐片元
plaintext
if (片元模板值 [比较函数] 参考值) {
执行通过操作(如保留像素)
} else {
执行失败操作(如丢弃像素)
}
[*]缓冲更新
[*]根据测试结果修改模板缓冲值(可选)
比较函数(StencilFunc)
函数含义OpenGL常量Never永远不通过GL_NEVERAlways永远通过GL_ALWAYSLess模板值 < 参考值GL_LESSLEqual模板值 ≤ 参考值GL_LEQUALGreater模板值 > 参考值GL_GREATERGEqual模板值 ≥ 参考值GL_GEQUALEqual模板值 == 参考值GL_EQUALNotEqual模板值 != 参考值GL_NOTEQUAL缓冲操作(StencilOp)
操作组合含义Keep保持当前模板值不变(默认)Zero将模板值设为0Replace用参考值替换模板值Incr/IncrWrap模板值+1(超过255时,前者截断后者循环)Decr/DecrWrap模板值-1(低于0时,前者截断后者循环)Invert按位取反(~操作)示例1
[*]遮罩区域shader
Shader "Custom/StencilMask" {
SubShader {
Tags { "Queue"="Geometry-1" } // 优先渲染
ColorMask 0 // 不写入颜色
ZWrite Off
Stencil {
Ref 1
Comp Always
Pass Replace // 将模板值设为1
}
Pass {} // 空Pass仅用于写入模板
}
}
[*]物体模版测试shader,该Shader仅在模板值为1的区域内渲染物体。
Shader "Custom/StencilObject" {
SubShader {
Stencil {
Ref 1
Comp Equal // 仅渲染模板值=1的区域
Pass Keep
}
Pass {
// 正常着色代码...
}
}
}示例2 外轮廓描边
Shader "Custom/StencilOutline" {
Properties {
_MainTex ("Base Texture", 2D) = "white" {}
_OutlineColor ("Outline Color", Color) = (1,0,0,1)
_OutlineWidth ("Outline Width", Range(0, 0.1)) = 0.05
}
SubShader {
Tags {
"RenderPipeline"="UniversalRenderPipeline"
"RenderType"="Opaque"
}
// Pass 1: 正常渲染角色并写入模板
Pass {
Name "Character"
Tags
{
"LightMode" = "UniversalForward"
}
Stencil {
Ref 1
Comp Always
Pass Replace
ZFail Keep
}
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
struct Attributes {
float4 positionOS : POSITION;
float2 uv : TEXCOORD0;
};
struct Varyings {
float4 positionCS : SV_POSITION;
float2 uv : TEXCOORD0;
};
TEXTURE2D(_MainTex);
SAMPLER(sampler_MainTex);
Varyings vert(Attributes IN) {
Varyings OUT;
OUT.positionCS = TransformObjectToHClip(IN.positionOS.xyz);
OUT.uv = IN.uv;
return OUT;
}
half4 frag(Varyings IN) : SV_Target {
return SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, IN.uv);
}
ENDHLSL
}
// Pass 2: 渲染轮廓
Pass {
Name "Outline"
Cull Front
Stencil {
Ref 1
Comp NotEqual
Pass Keep
}
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
struct Attributes {
float4 positionOS : POSITION;
float3 normalOS : NORMAL;
};
struct Varyings {
float4 positionCS : SV_POSITION;
};
CBUFFER_START(UnityPerMaterial)
float4 _OutlineColor;
float _OutlineWidth;
CBUFFER_END
Varyings vert(Attributes IN) {
Varyings OUT;
float3 posWS = TransformObjectToWorld(IN.positionOS.xyz * (1 + _OutlineWidth));
float3 normalWS = TransformObjectToWorldNormal(IN.normalOS);
// posWS += normalWS * _OutlineWidth; // 沿法线方向扩展
OUT.positionCS = TransformWorldToHClip(posWS);
return OUT;
}
half4 frag(Varyings IN) : SV_Target {
return _OutlineColor;
}
ENDHLSL
}
}
}【从UnityURP开始探索游戏渲染】专栏-直达
(欢迎点赞留言探讨,更多人加入进来能更加完善这个探索的过程,
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页:
[1]