TA不一样(十一)

前言:Stencil Buffer(模板缓存)做为一个核心缓冲区类型,简单介绍一下实现和功能。然后再补充一下剔除和深度的功能。

Stencil Buffer

1.什么是stencil buffer
  • 如果将屏幕上所有像素想象成一串连续的0组成的矩形,那么stencil bufer的作用就是将某些0变为1,2,3 ..255
  • 在每个pass中可以决定只渲染某个特定stencil值的像素并抛弃对其他非该值像素的操作
  • stencil bufer与depth buffer一样,都是缓冲区,存在于显存内的某一片区域中
  • 目前的显卡架构中,stenci buffer与depth bufer是在一起的,比如在depth/stencil缓冲区某个32位的区域中,有24位记录着像素A的depth数据,紧接着8位记录着像素A的stencil数据
  • stencil测试在管线中写入与读取的位置在透明测试(AlphaTest)和深度测试(DepthTest)之间

2.常用语法格式

Stencil

{

Ref reference Value // 参考值 默认値为 0

Comp comparisonFunction // 定义参考值与缓冲值比较的方法 默认值为Always

Pass stencilOperation // 定义当通过模板测试时,根据参考值对缓冲值的处

// 理方法 默认值为keep

Fail stencillperation // 定义当没有通过模板测试时,根据参考值对缓冲值

// 的处理方法 默认为keep

ZFail stencilOperation // 定义当通过模板测试却没有通过深度测试时,根据

// 参考对缓冲值的处理方法 默认为keep

}


3.代码实现

使用stencil buffer实现物体描边。

之前实现描边通过法线拓展并进行前剔除实现物体边缘膨胀描边,而通过stencil buffer实现的是通过渲染顺序,跳过法线扩展和模型的重合部分实现描边。由于描边通过Ref值Comp Equal(相等判断),多个部分重合模型的描边会丢失重合部分的描边。

cs 复制代码
Shader "MyCustom/StencilOutline"
{
    Properties
    {
        // 描边宽度
        _Edge       ("_Edge",       Float)      = 0.1
        
        // 物体颜色
        _Color   ("_Color",     Color)      = (1, 1, 1, 1)
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }

        Stencil
        {
            Ref 0           // 0-255
            Comp Equal      // 已经定义的ref 和 stencil buff值做对比
            Pass IncrSat    // ref 值自增1
        }


        // 第一部分Pass渲染物体,施加lambert效果,由于第一次经过Stencil Buffer,默认值为0对比通过,执行Pass逻辑,屏幕这部分值自增一为1。

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
            #include "Lighting.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };

            struct v2f
            {
                float4 vertex       : SV_POSITION;
                float3 worldNormal  : TEXCOORD0;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                float3 worldNormal = normalize(i.worldNormal);
                float3 worldLight = normalize(_WorldSpaceLightPos0.xyz);

                float diffuse = saturate(dot(worldNormal, worldLight) * 0.5 + 0.5);

                // ambient
                float3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;

                return float4(diffuse + ambient, 1);
            }
            ENDCG
        }

         // 第二部分Pass法线扩展实现描边,由于第二次经过Stencil Buffer,覆盖区域默认值为0对比之前模型渲染的屏幕部分的值为1,不通过跳过渲染。只有法线扩出来的部分默认值为0,进行渲染并执行Pass逻辑自增1。

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            struct appdata
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };

            struct v2f
            {
                float4 vertex       : SV_POSITION;
            };

            float _Edge;
            float4 _Color;

            v2f vert (appdata v)
            {
                v2f o;

                o.vertex = v.vertex + normalize(float4(v.normal, 0)) * _Edge;
                o.vertex = UnityObjectToClipPos(o.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                return _Color;
            }
            ENDCG
        }
    }
}

通过stencil buffer实现X射线透视效果。

渲染顺序:x射线物体 --> 遮挡物体 --> 被遮挡物体

stencil buffer值:x射线物体(99,永远通过,赋值为99),遮挡物体(0,相等通过,自增1),被遮挡物体(99,相等通过,自增1)

cs 复制代码
Shader "MyCustom/StencilXrayMask"
{
    Properties
    {
        _Color          ("_Color",          Color)      = (1, 1, 1, 1)
    }
    SubShader
    {
        //Tags { "RenderType"="Opaque" }

        ZWrite Off
        ColorMask 0

        Stencil
        {
            Ref 99           // 0-255,例子中是99
            Comp always      // 比较的结果是永远通过
            Pass replace     // pass的结果是替换,就是拿99替换 stencil buff的值,由于优先渲染,X射线遮罩部分的值为99,遮挡物值为0被跳过渲染,被遮挡物值为99进行渲染。
        }

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
            #include "Lighting.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };

            struct v2f
            {
                float4 vertex       : SV_POSITION;
                float3 worldNormal  : TEXCOORD0;
            };

            float4 _Color;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                return _Color;
            }
            ENDCG
        }
    }
}

Culling和Z(剔除和深度)

1.Cull剔除
  • 剔除语法:Cull Back | Front | Off
  • Back:不渲染背离观察者的多边形
  • Front:不渲染面向观察者的多边形,用于从里到外翻转对象
  • Off:禁用剔除-绘制所有面
  • VFace:表示一个渲染表面是否面朝相机。使用这个语义需要 Shader Model 3.0,也就是#pragma target 3.0

在使用Cull Off绘制所以面时,可以在片元着色器中使用VFace参数表示正反面

fixed4 frag (v2f i, float facing : VFACE) : SV_Target

{

// facing>0为正面,<0为反面

float4 col = lerp(_Color0, _Color1, facing > 0);

float3 normal = i.normal * 0.5 + 0.5;

col.rgb = lerp(normal, float3(0, 0, 1), facing > 0);

return col;

}


2.深度

深度缓存(depth buffer)

  • 存储着准备要绘制在屏幕上的像素点的深度值。

  • 如果启用了深度缓冲区,在绘制每个像素之前,OpenGL会把该像素的深度值和深度缓存的深度值进行比较。
    深度测试 (depth test)

  • 将要绘制的新像素的z值与深度缓冲区中对应位置的z值进行比较,如果比深度缓存中的值小,那么用新像素的颜色值更新深度缓存中对应像素的颜色值。
    ZTest Less | Greater | LEqual | GEqual | Equal | NotEqual | Always

  • 应如何执行深度测试

  • 默认值为 LEqual

ZWrite On l Off

  • 控制是否将此对象的像素写入深度缓冲区
  • 默认值为 On
  • 如果要绘制实体对象,将其保留为 On。如果要绘制半透明效果,请切换到ZWrite Off

Offset Factor, Units

  • 允许使用两个参数指定深度偏移
相关推荐
benben0441 年前
《Unity Shader入门精要》学习笔记二
unity·unity shader
是嘟嘟啊2 年前
【Unity】线性代数基础:矩阵、矩阵乘法、转置矩阵、逆矩阵、正交矩阵等
线性代数·unity·矩阵·矩阵乘法·逆矩阵·unity shader·矩阵转置
avi91112 年前
Unity Shader - 2024 工具篇
unity·游戏引擎·unity shader