UnityShader基础案例(七)——遮挡显示

一、这种是只要有遮挡就显示。

        遮挡显示需要两个Pass,第一个Pass用于占坑,第二个Pass用于正常输出。

Shader "Custom/Test0"
{
    Properties
    {
        _MainColor("主颜色",Color)=(1,1,1,1)
    }
    SubShader
    {
        Tags{"Queue"="Overlay"}
        //正常漫反射
        Pass
        {
            //ZWrite off
            //深度值更大的通过测试,同时写入深度缓存
            ZTest Greater
            ZWrite On
            //没有必要输入颜色值
            ColorMask 0
        }
        Pass
        {
            //正常渲染
            Tags
            {
                "LightMode"="ForwardBase" "Queue"="Overlay"
            }
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #include "UnityLightingCommon.cginc"
            fixed4 _MainColor;

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

            struct v2f
            {
                float4 pos:SV_POSITION;
                float3 worldNormal :COLOR;
            };

            v2f vert(a2v v)
            {
                v2f o;

                o.pos = UnityObjectToClipPos(v.vertex);

                o.worldNormal = UnityObjectToWorldNormal(v.normal);

                return o;
            }

            fixed4 frag(v2f i):SV_Target
            {
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;

                fixed3 worldNormal = normalize(i.worldNormal);

                fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);

                fixed3 diffuse = _LightColor0.rgb * _MainColor.rgb *
                    (dot(worldLight, worldNormal) * 0.5 + 0.5);

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

        这种算是最简单的写法了。

        一般我们需要被遮挡的时候显示一下轮廓什么的。

        这时候第一个Pass的作用就不只是占坑,我们还需要关闭深度写入用于做一些特殊处理。        

Shader "Custom/Test0"
{
    Properties
    {
        _MainColor("主颜色",Color)=(1,1,1,1)
        _FresnelPow("菲涅尔次幂",Float)=1.0
        _FresnelStrength("菲涅尔次幂",Float)=1.0
    }
    SubShader
    {
        Tags{"Queue"="Overlay"}
        //正常漫反射
        Pass
        {
            //ZWrite off
            //深度值更大的通过测试,同时写入深度缓存
            
            ZTest Greater
            ZWrite off
            Blend SrcAlpha OneMinusSrcAlpha
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"        
            fixed4 _MainColor;
            fixed _FresnelPow;
            fixed _FresnelStrength;

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

            struct v2f
            {
                float4 pos:SV_POSITION;
                float4 worldPos:TEXCOORD0;
                float3 worldNormal :COLOR;
            };

            v2f vert(a2v v)
            {
                v2f o;

                o.pos = UnityObjectToClipPos(v.vertex);
                o.worldPos=mul(unity_ObjectToWorld,v.vertex);
                o.worldNormal = UnityObjectToWorldNormal(v.normal);

                return o;
            }

            fixed4 frag(v2f i):SV_Target
            {       
                fixed3 worldNormal = normalize(i.worldNormal);

                fixed3 worldViewDir=normalize(+_WorldSpaceCameraPos-i.worldPos);               

                fixed fresnel=pow(1-dot(worldNormal,worldViewDir),_FresnelPow)*_FresnelStrength;                

                return fixed4(1,1,1, fresnel);
            }
            ENDCG
        }
        Pass
        {
            Tags
            {
                "LightMode"="ForwardBase"
            }
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #include "UnityLightingCommon.cginc"
            fixed4 _MainColor;

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

            struct v2f
            {
                float4 pos:SV_POSITION;
                float3 worldNormal :COLOR;
            };

            v2f vert(a2v v)
            {
                v2f o;

                o.pos = UnityObjectToClipPos(v.vertex);

                o.worldNormal = UnityObjectToWorldNormal(v.normal);

                return o;
            }

            fixed4 frag(v2f i):SV_Target
            {
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;

                fixed3 worldNormal = normalize(i.worldNormal);

                fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);

                fixed3 diffuse = _LightColor0.rgb * _MainColor.rgb *
                    (dot(worldLight, worldNormal) * 0.5 + 0.5);
                return fixed4(diffuse+ambient, 1);
            }
            ENDCG
        }
        
    }
}

        这种遮挡显示一般适用于3D游戏,只要挡住了全给显示出来。

        还有一种给处理方式就是遮挡的话把遮挡物给透明处理了,这个用射线检测可能会更好,shader的实现没想到,主要是遮没遮挡只能通过人物判断,你一判断人物,遮挡物的信息就丢失了,但如果反过来判断遮挡物,那么人物遮没遮住就不知道了。        

        这种渲染一般都很少用,一般有遮挡都会让摄像机移动,因为游戏里面加这种菲涅尔透视效果怪怪的。

二、因为场景导致的穿模遮挡

        根据我平常玩的游戏还有一种东西,这种时候遮挡需要处理的和前面不一样,前面的是只要遮挡必渲染,这种需要按总体前后顺序渲染,解决穿模现象。

        2D和3D的结合,如明日方舟,2D人物是斜插在场景中的,那个柱子理论上是要挡住人物的头部,但我们需要把它显示出来,但如果是柱子上面正常挡住的角色那就正常挡住即可。

        这种就是属于 强制按从后到前的顺序渲染,然后把深度值强行按这个顺序写进去,这意味着人物要和柱子放一个渲染队列。        

Shader "Custom/Test0"
{
    Properties
    {
        _MainColor("主颜色",Color)=(1,1,1,1)

    }
    SubShader
    {
        Tags{"Queue"="Overlay"}
        Pass
        {
            ZTest Always
            ZWrite on
            ColorMask 0
        }
        Pass
        {
            Tags
            {
                "LightMode"="ForwardBase"
            }
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #include "UnityLightingCommon.cginc"
            fixed4 _MainColor;

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

            struct v2f
            {
                float4 pos:SV_POSITION;
                float3 worldNormal :COLOR;
            };

            v2f vert(a2v v)
            {
                v2f o;

                o.pos = UnityObjectToClipPos(v.vertex);

                o.worldNormal = UnityObjectToWorldNormal(v.normal);

                return o;
            }

            fixed4 frag(v2f i):SV_Target
            {
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;

                fixed3 worldNormal = normalize(i.worldNormal);

                fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);

                fixed3 diffuse = _LightColor0.rgb * _MainColor.rgb *
                    (dot(worldLight, worldNormal) * 0.5 + 0.5);
                return fixed4(diffuse+ambient, 1);
            }
            ENDCG
        }
        
    }
}

        但我看了明日方舟之前的技术会,他们的实现不是这种,是把人物立起来,用立起来的深度值去做深度测试,然后再斜着渲染,我也不知道怎么实现。

        结果应该是没问题的反正试了很多种情况,前面的猴头是插进中间的猴头的,后面的猴头是没插进去的,按前后顺序正常渲染,不确定明日方舟开发者是不是还遇到其他问题了。

       

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值