美文网首页Unity3d 技术笔记
ShaderLab: 剔除和深度测试(Culling and Z

ShaderLab: 剔除和深度测试(Culling and Z

作者: 子夜书案 | 来源:发表于2022-05-05 22:14 被阅读0次

    概述:

    不渲染视野内不可见的多边形的操作称之为剔除。
    所有的多边形都有正面和背面,视野永远看不见背面,因此Unity也不需要渲染背面。这个过程用专业术语称之为:背面剔除(Backface culling)
    另外有一项技术,保证渲染的永远是离视野最近的面,从容让渲染出的效果看起来更真实,这项技术被深度检测(Depth testing)

    工作时机:

    剔除时机

    语法:

    Cull

    Cull Back | Front | Off 
    

    控制剔除多边形的那些边?

    • Back Don't render polygons that are facing away from the viewer. default: back-facing polygons are culled.
      背面,背对着观察者的面,这是默认选项
    • Front Don't render polygons that are facing towards the view.Used for turning objects inside-out.
      前面,朝向观察者的面,通常用于表现翻转效果
    • Off Disable culling-all faces are drawn.Used for special effects.
      关闭剔除,所有朝向都绘制。通常用于特殊效果。

    样例:

    
    Shader "Unlit/CullingTest"
    {
        Properties
        {
            _MainTex ("Texture", 2D) = "white" {}
            [Header(Cull)]
            // https://docs.unity3d.com/ScriptReference/Rendering.CullMode.html
            // default need to be Front, because we need to make sure decal render correctly even if camera goes into decal cube
            [Enum(UnityEngine.Rendering.CullMode)]_Cull("_Cull (default = Front) _____to improve GPU performance, Set to Back if camera never goes into cube volume, else set to Front", Float) = 1 //1 = Front
        }
        SubShader
        {
            Tags { "RenderType"="Opaque" "Queue"="Geometry" }
            Cull [_Cull]
            Pass
            {
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                // make fog work
                #pragma multi_compile_fog
                
                #include "UnityCG.cginc"
    
                struct appdata
                {
                    float4 vertex : POSITION;
                    float2 uv : TEXCOORD0;
                };
    
                struct v2f
                {
                    float2 uv : TEXCOORD0;
                    UNITY_FOG_COORDS(1)
                    float4 vertex : SV_POSITION;
                };
    
                sampler2D _MainTex;
                float4 _MainTex_ST;
                
                v2f vert (appdata v)
                {
                    v2f o;
                    o.vertex = UnityObjectToClipPos(v.vertex);
                    o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                    UNITY_TRANSFER_FOG(o,o.vertex);
                    return o;
                }
                
                fixed4 frag (v2f i) : SV_Target
                {
                    // sample the texture
                    fixed4 col = tex2D(_MainTex, i.uv);
                    // apply fog
                    UNITY_APPLY_FOG(i.fogCoord, col);
                    return col;
                }
                ENDCG
            }
        }
    }
    
    
    
    Cull [_Cull]  //从外面读取数据
    

    效果:

    Cull Back | Front | Off 效果

    ZTest

    ZTest  Less  |  LEqual | GEqual | NotEqual | Always
    

    How should depth testing be perfromed.Default is LEqual(draw objects in from or at the distance as existing objects;hide objects behind them).
    深度测试执行方式,默认为 LEqual(小于等于)。Unity中离摄像机越近深度越小,越大离得越远。LEqual 表示执行深度测试时,像素点与缓存中的进行比较,如果小于缓存值,便能通过测试。
    除了LEqual 外,还有下面这些参数可用:

    函数名 描述
    Never 1 从不渲染
    Less 2 当小于缓存值时执行
    Equal 3 当等于缓存值时执行
    LEqual 4 当小于等于缓存值时执行
    Greater 5 当大于缓存值时执行
    NoEqual 6 当不等于缓存值时执行
    GEqual 7 当大于等于缓存值时执行
    Alaways 8 一直执行

    ZWrite

    ZWrite On | Off
    

    Controls whether pixels from this object are written to the depth buffer(default is On).if you're drawing solid objects,leave this on .if you're drawing semitransparent effects,switch to Zwrite off.
    控制物体的像素点是否写入深度缓存,如果绘制是固体(不透明)保持它为打开状态,如果是透明,关闭它。
    设置在渲染过程中是否更新深度缓冲区内容。通常,ZWrite 对不透明对象启用,对半透明对象禁用。
    禁用 ZWrite 会导致不正确的深度排序。这种情况下,您需要在 CPU 上对几何体进行排序。

    当且仅当 ZTest 通过和 ZWrite 开启时,像素点的深度才会被写入 ```depth buffer`` 中

    Offset

    Offset Factor, Units
    

    Allows you specify a depth offset with two parameters.factor and units.Factor scales the maximum Z slop,with respect to X or Y of the polygon,and units scale the minimum resolvable depth buffer value.This allows you to force one polygon to be drawn on top of another although they are actually in the same position.
    For example Offset 0,-1 pulls the polygon closer to the camera ignoring the polygon's slope,whereas Offset -1,-1 will pull the polygon even closer when looking at a grazing angle.

    允许通过 Factor 和 Units 来指定深度偏移。Factor 是多边形 Z 轴基于 X 或者 Y 的最大斜率的缩放量,Units 是深度缓存中最小可分值的缩放量。通过调整参数,你可以强制使同一位置的多边形绘制在其它多边形之上。
    例如:Offset 0, -1 可以忽略多边形的斜率,将其推进摄像机。Offset -1, -1 从波动角(grazing angle)观察,多边形被拉得更靠近。

    grazing_angle

    Offset 主要用来解决 Z-fighting 问题

    • Z-fighting:当多边形共面时,深度缓存无法分离它们,导致深度不稳定,从而会出现图像在帧间来回穿插闪烁。

    如下效果:

    Z-fighting

    能解决这种问题的shader:

    Shader "Test/Quad"
    {
        Properties
        {
            _OffsetFactor("Offset Factor",Float) = 0
            _OffsetUnits("Offset Units",Float) = 0
            _Color ("Main Color", Color) = (1,1,1,1)
        }
        SubShader
        {
            Tags { "RenderType"="Opaque" }
            Offset [_OffsetFactor],[_OffsetUnits]
            Pass
            {
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                // make fog work
    
                #include "UnityCG.cginc"
    
                struct appdata
                {
                    float4 vertex : POSITION;
                    float2 normal : NORMAL;
                };
    
                struct v2f
                {
                    float2 wnormal : NORMAL;
                    float4 vertex : SV_POSITION;
                };
                fixed4 _Color;
                v2f vert (appdata v)
                {
                    v2f o;
                    o.vertex = UnityObjectToClipPos(v.vertex);
                    o.wnormal = UnityObjectToWorldNormal((v.normal,1));
                    return o;
                }
    
                fixed4 frag (v2f i) : SV_Target
                {
                    return _Color * (dot(normalize(_WorldSpaceLightPos0.xyz),i.wnormal) * 0.5 + 0.5);
                }
                ENDCG
            }
        }
    }
    

    关键在下面两段代码:

      _OffsetFactor("Offset Factor",Float) = 0 // Factor 属性面板可设置,默认0
      _OffsetUnits("Offset Units",Float) = 0 // Units 属性面板可设置,默认0
    
      Offset [_OffsetFactor],[_OffsetUnits]
    
    调整后的

    引用:

    https://docs.unity3d.com/2020.1/Documentation/Manual/SL-CullAndDepth.html

    相关文章

      网友评论

        本文标题:ShaderLab: 剔除和深度测试(Culling and Z

        本文链接:https://www.haomeiwen.com/subject/uwugyrtx.html