Shader学习16——遮挡描边

遮挡描边,就是游戏里的人物走到房子后面的时候,部分身体还希望能看到特效,比如下面这种:

image.png

这里很明显需要两个pass通道来实现,一个pass显示基础的兰伯特或者其他的渲染方式,另一个显示遮挡部分的渲染方式。因此还是在兰伯特基础上改,增加一个pass通道,设置为

Blend SrcAlpha One//设置颜色混合结果
            ZWrite off  //关闭深度缓存,重写对象的绘制顺序
            ztest greater//当深度大于最小值时,渲染对象

效果如下:

image.png

代码:

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "Unlit/遮挡描边"
{
    Properties
    {
        _Diffuse ("Diffuse", Color) = (1,1,1,1)
        _MainTex ("Texture", 2D) = "white" {}

        _RimColor("RimColor", Color) = (1,1,1,1) //边缘光颜色
        _RimPower("RimPower",Range(0,1)) =0 //边缘光强度
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" "LightMode"="ForwardBase"}
        LOD 100
        Pass
        {
            Blend SrcAlpha One//设置颜色混合结果
            ZWrite off  //关闭深度缓存,重写对象的绘制顺序
            ztest greater//当深度大于最小值时,渲染对象

            
            ztest greater
            
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            
            float4 _RimColor;
            float _RimPower;
            
            struct appdata_t {
                float4 vertex : POSITION;
                float2 texcoord : TEXCOORD0;
                float4 color:COLOR;
                float4 normal:NORMAL;
            };
            
            struct v2f {
                float4  pos : SV_POSITION;
                float4  color:COLOR;
            } ;
            v2f vert (appdata_t v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                //计算出顶点到相机的向量,并归一化
                float3 viewDir = normalize(ObjSpaceViewDir(v.vertex));
                //点乘观察方向和法线方向,即顶点的法线方向越对着相机的时候 结果越小
                // float rim = saturate(dot(viewDir,v.normal));//中间向两边减弱
                float rim = 1-saturate(dot(viewDir,v.normal));//使用1-saturate(dot(viewDir,v.normal)就可以获得物体朝其他方向的边缘
                o.color = _RimColor*pow(rim,_RimPower);
                return o;
            }
            float4 frag (v2f i) : COLOR
            {
                return i.color; 
            }
            ENDCG

        }
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

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

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

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float3 normal:NORMAL;
                float4 vertex : SV_POSITION;
            };
            
            fixed4 _Diffuse;
            sampler2D _MainTex;
            float4 _MainTex_ST;

            v2f vert (a2v v)
            {
                v2f o;
                //顶点坐标转换
                o.vertex = UnityObjectToClipPos(v.vertex);
                //获取法线(统一到世界坐标系下)。
                o.normal = UnityObjectToWorldNormal(v.normal);
                //获取UV
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                //获取环境光
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                //获取归一化的法线
                fixed3 worldNormal = normalize(i.normal);
                //fixed3 worldNormal = i.normal;
                //获取环境光的方向
                fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
                //兰伯特:漫反射颜色 = 光源颜色 x 材质的漫反射颜色 x Max(0,Dot(法线,指向光源的方向))
                //计算光照强度
                fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLight)*0.5+0.5);
                //叠加
                fixed3 color = ambient + diffuse;

                //获取贴图颜色
                fixed4 col = tex2D(_MainTex, i.uv);
                //将贴图颜色与顶点计算的颜色相乘 
                col=fixed4(col.rgb*color.rgb,1.0);
                return fixed4(col.rgb,1.0);
            }

            
            ENDCG
        }
    }
    Fallback "Diffuse"
}

如果不想要描边,也可以不用1-,直接出来的效果如下:

image.png

当然了,如果以上两种效果都不喜欢,也可以写其他的方式渲染。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
你好!要在Shader Graph中实现物体描边效果,可以尝试以下步骤: 1. 创建一个新的Shader Graph。 2. 添加一个Unlit Master节点作为主节点。 3. 添加一个Sprite节点,并将其连接到Unlit Master节点的Albedo输入。 4. 在Shader Graph中创建一个新的Sub Graph。 5. 在Sub Graph中创建一个Custom Function节点,命名为"Outline"。 6. 将Custom Function节点连接到Sub Graph的输出节点。 7. 在Custom Function节点中,添加一个Input节点,命名为"Alpha",用于控制描边的强度。 8. 添加一个Sample Texture 2D节点,用于采样纹理。 9. 将Sample Texture 2D节点的输出连接到Custom Function节点的输出。 10. 添加一个Sample Gradient节点,用于采样渐变纹理。 11. 将Sample Gradient节点的输出连接到Custom Function节点的输出。 12. 在Custom Function节点中,使用Alpha输入和采样的纹理和渐变纹理来计算描边效果。 13. 返回到主Shader Graph,将Sub Graph节点连接到Unlit Master节点的Alpha输入。 14. 在主Shader Graph中创建一个Multiply节点,并将其连接到Sub Graph节点的输出。 15. 将Multiply节点的另一个输入连接到Unlit Master节点的Alpha输入。 16. 将Multiply节点的输出连接到Unlit Master节点的Alpha输入。 这样,你就可以在Shader Graph中实现物体描边效果。你可以根据需要调整描边的强度和样式,例如修改渐变纹理或自定义描边的计算方式。希望对你有帮助!如果有任何问题,请随时提问。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值