防止ColorMask遮挡对象网格的部分

时间:2018-02-08 19:48:36

标签: unity3d shader fragment-shader vertex cg

我正在尝试使用着色器来防止对象在离开特定区域时进行渲染。但是,使用表面着色器执行此操作时,为了解决绘图问题,我必须使用深度缓冲区。目前我正在通过

这样做
Pass {
    ColorMask 0
}

然而,这导致的效果不会使网格的部分呈现在颜色蒙版的绘制部分之后。

为了解决这个问题,我试图完成传递,但是丢弃了碎片,但这会导致面部以错误的顺序渲染。这可能是由于下面着色器脚本中的Cull Off,但这不是我的程序处理内部渲染的正常方式,在没有大量代码的情况下提供合理结果只是一件很简单的事情。 Cull BackCull Off也会发生这种情况。

我怎样才能使ColorMask 0不会掩盖它背后的内容,或者当所有片段被丢弃时,可以使用什么CG程序来防止面部渲染错误的问题?

enter image description here

着色器代码 - Lit.shader

Shader "Culling/Lit" {
    Properties {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
        _Metallic ("Metallic", Range(0,1)) = 0.0

        //Properties normally assigned by script but can be done manually
        _SHOWCULL("Show Cull", Int) = 0

        _RADIUS("Radius", Float) = 0

        _STARTX("Start X", Float) = 0
        _STARTY("Start Y", Float) = 0
        _STARTZ("Start Z", Float) = 0

        _CENTREX("Centre X", Float) = 0
        _CENTREY("Centre Y", Float) = 0
        _CENTREZ("Centre Z", Float) = 0

        _ENDX("End X", Float) = 0
        _ENDY("End Y", Float) = 0
        _ENDZ("End Z", Float) = 0

        _MODE("Mode", Int) = 0
    }
    SubShader {
        Tags{ "Queue" = "Transparent" "RenderType" = "Transparent" "IgnoreProjector" = "True" }
        LOD 200
        Blend SrcAlpha OneMinusSrcAlpha
        ZWrite On

        Pass {
            //Renders faces in wrong order
            /*CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag

                fixed4 _Color;

                struct appdata {
                    float4 vertex : POSITION;
                };

                struct v2f {
                    float4 vertex : POSITION;
                };

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

                fixed4 frag (v2f i) : COLOR {
                    discard;
                    return _Color;
                }
            ENDCG*/
            ColorMask 0
        }

        Cull Off //Not normally used as provides incorrect light but way to fix is not needed for this and it is here to show example inside

        CGPROGRAM
        #pragma surface surf Standard fullforwardshadows alpha
        #pragma target 3.0

        sampler2D _MainTex;

        struct Input {
            float2 uv_MainTex;
            float3 worldPos;
        };

        half _Glossiness;
        half _Metallic;
        fixed4 _Color;

        UNITY_INSTANCING_CBUFFER_START(Props)
        UNITY_INSTANCING_CBUFFER_END

        int _SHOWCULL;

        float _RADIUS;

        float _STARTX;
        float _STARTY;
        float _STARTZ;

        float _CENTREX;
        float _CENTREY;
        float _CENTREZ;

        float _ENDX;
        float _ENDY;
        float _ENDZ;

        int _MODE;

        void surf (Input IN, inout SurfaceOutputStandard o) {
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
            o.Albedo = c.rgb;
            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;
            o.Alpha = c.a;

            if (_MODE == 0) {
                //For Cylinder
                if (sqrt(((IN.worldPos.x - _CENTREX) * (IN.worldPos.x - _CENTREX)) +
                    ((IN.worldPos.z - _CENTREZ) * (IN.worldPos.z - _CENTREZ))) < _RADIUS
                    && IN.worldPos.y > _STARTY && IN.worldPos.y < _ENDY) {
                }
                else
                {
                    discard; //ignores that pixel - doesnt render it
                }
            }
            else if (_MODE == 1) {
                //For Sphere
                if (sqrt(((IN.worldPos.x - _CENTREX) * (IN.worldPos.x - _CENTREX)) +
                    ((IN.worldPos.y - _CENTREY) * (IN.worldPos.y - _CENTREY)) +
                    ((IN.worldPos.z - _CENTREZ) * (IN.worldPos.z - _CENTREZ))) < _RADIUS) {
                }
                else
                {
                    discard; //ignores that pixel - doesnt render it
                }
            }
            else if (_MODE == 2) {
                // For Cuboid
                if (IN.worldPos.x > _STARTX && IN.worldPos.x < _ENDX
                    && IN.worldPos.y > _STARTY && IN.worldPos.y < _ENDY
                    && IN.worldPos.z > _STARTZ && IN.worldPos.z < _ENDZ) {
                }
                else
                {
                    discard; //ignores that pixel - doesnt render it
                }
            }
        }

        ENDCG
    }
    FallBack "Diffuse"
}

1 个答案:

答案 0 :(得分:0)

这可以通过使用相同的数学来剪切与网格一起使用的ColorMask来解决。这样,深度缓冲区仍然存在,因此面部以正确的顺序绘制,并且不会遮挡任何内容。

...
Pass {
    ColorMask 0

    CGPROGRAM
    #pragma vertex vert
    #pragma fragment frag

    #include "UnityCG.cginc"

    float _RADIUS;

    float _STARTX;
    float _STARTY;
    float _STARTZ;

    float _CENTREX;
    float _CENTREY;
    float _CENTREZ;

    float _ENDX;
    float _ENDY;
    float _ENDZ;

    float _MODE;

    sampler2D _MainTex;
    fixed4 _Color;
    // vertex shader inputs
    struct appdata
    {
        float4 vertex : POSITION; // vertex position
        float2 uv : TEXCOORD0; // texture coordinate
    };

    // vertex shader outputs ("vertex to fragment")
    struct v2f
    {
        float2 uv : TEXCOORD0; // texture coordinate
        float4 vertex : SV_POSITION; // clip space position
        float4 position_in_world_space : TEXCOORD1; //same as uv
    };

    float4 _MainTex_ST;

    // vertex shader
    v2f vert (appdata v)
    {
        v2f o;
        o.vertex = UnityObjectToClipPos(v.vertex);
        o.position_in_world_space = mul(unity_ObjectToWorld, v.vertex);
        o.uv = TRANSFORM_TEX(v.uv, _MainTex);
        return o;
    }

    fixed4 frag (v2f i) : SV_Target
    {
        fixed4 col = tex2D(_MainTex, i.uv) * _Color;

        if (_MODE == 0) {
            //For Cylinder
            if (sqrt(((i.position_in_world_space.x - _CENTREX) * (i.position_in_world_space.x - _CENTREX)) + 
                ((i.position_in_world_space.z - _CENTREZ) * (i.position_in_world_space.z - _CENTREZ))) < _RADIUS
                && i.position_in_world_space.y > _STARTY && i.position_in_world_space.y < _ENDY) {}
            else
            {
                discard; //ignores that pixel - doesnt render it
            }
        }
        else if (_MODE == 1){
             //For Sphere
            if (sqrt(((i.position_in_world_space.x - _CENTREX) * (i.position_in_world_space.x - _CENTREX)) + 
                ((i.position_in_world_space.y - _CENTREY) * (i.position_in_world_space.y - _CENTREY)) +
                ((i.position_in_world_space.z - _CENTREZ) * (i.position_in_world_space.z - _CENTREZ))) < _RADIUS) {}
            else
            {
                discard; //ignores that pixel - doesnt render it
            }
        }
        else if (_MODE == 2){
            // For Cuboid
            if (i.position_in_world_space.x > _STARTX && i.position_in_world_space.x < _ENDX
                && i.position_in_world_space.y > _STARTY && i.position_in_world_space.y < _ENDY
                && i.position_in_world_space.z > _STARTZ && i.position_in_world_space.z < _ENDZ) {}
            else 
            {
                discard; //ignores that pixel - doesnt render it
            }
        }

        return col;
    }
    ENDCG
}
...