unity 半透明描线shader

发布于:2025-06-21 ⋅ 阅读:(19) ⋅ 点赞:(0)

效果如图
在这里插入图片描述

Shader "Custom/TransparentWithOutline_Fixed"
{
    Properties
    {
        // 主材质属性
        _Color ("Main Color", Color) = (1,1,1,1)
        _MainTex ("Base (RGB) Trans (A)", 2D) = "white" {}
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
        _Metallic ("Metallic", Range(0,1)) = 0.0
        _Alpha ("Transparency", Range(0,1)) = 0.5
        
        // 描边属性
        _OutlineWidth ("Outline Width", Range(0.01, 0.1)) = 0.05
        _OutlineColor ("Outline Color", Color) = (0, 0, 0, 1)
    }
    
    SubShader
    {
        Tags { "Queue"="Transparent" "RenderType"="Transparent" "IgnoreProjector"="True" }
        LOD 200
        Pass
        {
            Name "STENCIL_WRITE"
            ZWrite Off
            ZTest Always  // 总是通过深度测试
            ColorMask 0   // 不写入任何颜色
            Cull Off      // 渲染所有面
            
            Stencil {
                Ref 255
                Comp Always
                Pass Replace
                Fail Keep
                ZFail Keep
            }
            
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            
            struct appdata
            {
                float4 vertex : POSITION;
            };
            
            struct v2f
            {
                float4 vertex : SV_POSITION;
            };
            
            v2f vert(appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                return o;
            }
            
            fixed4 frag(v2f i) : SV_Target
            {
                return 0; // 不写入颜色
            }
            ENDCG
        }
        
        // 主材质Pass (只负责渲染,不处理Stencil)
        Pass
        {
            Name "MAIN"
            Tags { "LightMode" = "ForwardBase" }
            
            ZWrite Off
            ZTest LEqual  // 正常深度测试
            Blend SrcAlpha OneMinusSrcAlpha
            
            Stencil {
                Ref 255
                Comp Always
                Pass Replace
            }
            
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fwdbase
            #include "UnityCG.cginc"
            #include "UnityStandardBRDF.cginc"
            #include "AutoLight.cginc"
            
            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                float3 normal : NORMAL;
            };
            
            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 pos : SV_POSITION;
                float3 worldNormal : TEXCOORD1;
                float3 worldPos : TEXCOORD2;
                LIGHTING_COORDS(3,4)
            };
            
            sampler2D _MainTex;
            float4 _MainTex_ST;
            float4 _Color;
            float _Glossiness;
            float _Metallic;
            float _Alpha;
            
            v2f vert (appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
                TRANSFER_VERTEX_TO_FRAGMENT(o);
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                // 采样纹理
                fixed4 col = tex2D(_MainTex, i.uv) * _Color;
                
                // 基础光照计算
                float3 worldNormal = normalize(i.worldNormal);
                float3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
                float3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
                
                // 漫反射
                float ndotl = saturate(dot(worldNormal, worldLightDir));
                float3 diffuse = ndotl * _LightColor0.rgb;
                
                // 镜面反射
                float3 halfDir = normalize(worldLightDir + worldViewDir);
                float spec = pow(saturate(dot(worldNormal, halfDir)), _Glossiness * 128);
                float3 specular = _LightColor0.rgb * spec * _Metallic;
                
                // 环境光
                float3 ambient = ShadeSH9(float4(worldNormal, 1));
                
                // 组合光照
                float3 lighting = diffuse + specular + ambient;
                col.rgb *= lighting;
                
                // 应用透明度
                col.a *= _Alpha;
                
                return col;
            }
            ENDCG
        }
        // 描边Pass
        Pass
        {
            Name "OUTLINE"
            Cull Front
            ZTest Always
            ZWrite Off
            Blend SrcAlpha OneMinusSrcAlpha
            
            Stencil {
                Ref 255
                Comp NotEqual
                Pass Keep
            }
            
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

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

            struct v2f
            {
                float4 vertex : SV_POSITION;
            };

            float _OutlineWidth;
            fixed4 _OutlineColor;

            v2f vert(appdata v)
            {
                v2f o;
                
                float4 pos = UnityObjectToClipPos(v.vertex);
                float3 normal = mul((float3x3)UNITY_MATRIX_IT_MV, v.normal);
                normal.z = -0.5;
                pos.xy += normalize(TransformViewToProjection(normal.xy)) * _OutlineWidth * pos.w;
                
                o.vertex = pos;
                return o;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                return _OutlineColor;
            }
            ENDCG
        }
        
        
    }
    
    FallBack "Transparent/VertexLit"
}

描边就是个简单的法线外扩,对直角边没有处理,效果差,但是没有需求改这个,就不处理了。

先写一个正常的半透明材质(第二个pass),这个pass只负责渲染半透明。在之前添加一个pass,ZTest Always,无论什么深度都会进行处理,把所有Stencil都设置为255,但是不进行任何的颜色处理。最后再添加一个简单的法线外扩,同样ZTest Always,只要是不属于255的范围都进行描边。这样就可以做到又不显示半透明材质又可以有描边。


网站公告

今日签到

点亮在社区的每一天
去签到