Skip to content

【Shader练习-米拉】

二次元角色渲染效果实现。

效果拆分演示:

MiLaShader.shader

shader
Shader "VP666/MiLaShader"
{
    Properties
    {
        [NoScaleOffset]
        _MainTex ("Texture", 2D) = "white" {}

        [Header(Metal)]
        _MetalMask ("Metal Mask", 2D) = "black" {}
        _Gloss ("Gloss", Range(0, 1)) = 0.8

        [Header(Rim)]
        _RimColor ("Rim Color", Color) = (1,1,1,1)
		_RimPower ("Rim Power", Range(0, 20)) = 10
		_RimIntensity ("Rim Intensity", Range(0, 1)) = 0.5

        [Header(Outline)]
        _OutlineColor ("Outline Color", Color) = (0,0,0,1)
        _OutlineWidth ("Outline Width", Range(0, 0.1)) = 0.001
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }

        // Outline Pass
        Pass
        {
            Name "OUTLINE"
            Tags { "LightMode" = "Always" }
            Cull Front
            ZWrite On
            ColorMask RGB
            Blend SrcAlpha OneMinusSrcAlpha

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

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

            struct v2f
            {
                float4 pos : SV_POSITION;
            };

            float _OutlineWidth;
            fixed4 _OutlineColor;

            v2f vert(appdata v)
            {
                v2f o;
                float3 normal = normalize(v.normal);
                float3 outlineOffset = normal * _OutlineWidth;
                float3 pos = v.vertex + outlineOffset;
                o.pos = UnityObjectToClipPos(float4(pos, 1.0));
                return o;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                return _OutlineColor;
            }
            ENDCG
        }

        // Main Pass
        Pass
        {
            Name "FORWARD"
            Tags { "LightMode"="ForwardBase" }

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
            #include "Lighting.cginc"
            #include "AutoLight.cginc"
            #pragma multi_compile_fwdbase_fullshadows
            #pragma target 3.0
            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                float3 normal : NORMAL;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 pos : SV_POSITION;
                float3 normal : TEXCOORD1;
                float3 worldPos : TEXCOORD2;
                LIGHTING_COORDS(3,4)
            };

            sampler2D _MainTex;
            sampler2D _MetalMask;
            float _Gloss;
            float4 _RimColor;
            float _RimPower;
            float _RimIntensity;

            half toondiffuse(float3 normal, float3 lightDir)
            {
                float d = max(0.,dot(normal,lightDir));
                // return step(0.5,d);//硬过度
                return smoothstep(0.48,0.52,d);//软过度
            }

            v2f vert (appdata v)
            {
                v2f o = (v2f)0;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.normal = UnityObjectToWorldNormal(v.normal);
                o.uv = v.uv;
                o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
                TRANSFER_VERTEX_TO_FRAGMENT(o);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // 主纹理
                fixed4 baseDiffuseColor = tex2D(_MainTex, i.uv);

                // 环境光和主纹理颜色
                fixed4 ambientColor = UNITY_LIGHTMODEL_AMBIENT * baseDiffuseColor;
                
                // 直接光与主纹理颜色
                fixed4 lightColor = _LightColor0 * baseDiffuseColor;

                // 兰伯特光照模型遮罩
                float3 normalWS = normalize(i.normal);
                half diffuseMask = toondiffuse(normalWS, _WorldSpaceLightPos0.xyz);
                
                fixed4 diffuseColor = lerp(ambientColor,lightColor,diffuseMask);
                
                // 阴影
                fixed shadow = LIGHT_ATTENUATION(i);
                diffuseColor = diffuseColor * shadow;

                // 像素位置指向摄像机的方向
                float3 viewDirWS = normalize(_WorldSpaceCameraPos.xyz - i.worldPos);
                
                // 高光
                float3 halfDirWS = normalize(_WorldSpaceLightPos0.xyz + viewDirWS);
                float ndoth = max(0.0,dot(normalWS,halfDirWS));
                float metal = tex2D(_MetalMask, i.uv).r;
                float specularExponent = exp2(_Gloss * 11) + 2;
                float specular = pow(max(0.0, ndoth), specularExponent) * _Gloss;
                float highlight = specular * metal;// 高光遮罩
                fixed4 specularColor = _LightColor0.rgba * highlight;
                diffuseColor = diffuseColor + specularColor;

                // 边缘光   
                half rim = 1.0 - saturate(dot(i.normal, viewDirWS));
				half4 rimColor = (_RimColor * pow(rim, _RimPower)) * _RimIntensity;
                return diffuseColor + rimColor;
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}

MIT Licensed