[ShaderLab Guilty Gear Cartoon Character_2D Style_"Sol Badguy"_Character Rendering (Part 2)]

Insert image description here

Character initial effect:

Insert image description here

Basic renderingSimpleBas

Shader "SimpleBase"
{
    
    
    Properties
    {
    
    
        [Header(BaseColor)]
        _MainTex ("BaseTex", 2D) = "white" {
    
    }
        [Space(20)]
        [Header(ILM)]
        _ILMTex("ILMTex",2D) = "white"{
    
    }
        [Space(20)]
        [Header(SSS)]
        _SssTex("SssTex",2D) = "white"{
    
    }
        [Space(20)]
        [Header(Detail)]
        _DetailTex("DetailTex",2D) = "white"{
    
    }
    }
    SubShader
    {
    
    
        Tags {
    
     "RenderType"="Opaque" }
        LOD 100

        Pass
        {
    
    
            Tags{
    
    "LightMode"="ForwardBase"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fwdbase

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

            struct appdata
            {
    
    
                float4 vertex : POSITION;
                float2 uv0 : TEXCOORD0;
                float2 uv1 : TEXCOORD1;
                float4 tangent :TEXCOORD2;
                half3 normal : NORMAL;
                half4 color : COLOR;
            };

            struct v2f
            {
    
    
                float4 uv : TEXCOORD0;
                float4 pos : SV_POSITION;
                half4 vertexColor : TEXCOORD1;
                half3 worldNormal : TEXCOORD2;
                float3 worldPos : TEXCOORD3;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            sampler2D _ILMTex;
            sampler2D _SssTex;
            sampler2D _DetailTex;

            v2f vert (appdata v)
            {
    
    
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv.xy = TRANSFORM_TEX(v.uv0, _MainTex);
                o.uv.zw = v.uv1;
                o.vertexColor = v.color;
                o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;
                o.worldNormal = mul(v.normal,(float3x3)unity_WorldToObject);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
    
    
                fixed4 ilm = tex2D(_ILMTex,i.uv.xy);
                fixed4 baseColor = tex2D(_MainTex, i.uv.xy);
                fixed4 sssColor = tex2D(_SssTex,i.uv.xy);
                fixed3 detail = tex2D(_DetailTex,i.uv.zw);
                half ao = saturate((i.vertexColor.r - 0.7) * 50);
                half3 worldNormal = normalize(i.worldNormal);
                half3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
                half3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
                half3 halfDir = normalize(worldLightDir + worldViewDir);
                half NdotH = saturate(dot(halfDir,worldNormal));
                half NdotL = dot(worldLightDir,worldNormal);
                half sssFactor = saturate((NdotL * 0.5 + 0.5 - i.vertexColor.b * 0.5) * 50) * ao;
                fixed4 finalColor = 1;
                finalColor.rgb = lerp(sssColor,baseColor,sssFactor) * detail * ilm.a;
                return finalColor;
            }
            ENDCG
        }
    }
}

Resource analysis

Model

Vertex color:

B channel gray of model
Insert image description here

Texture resources

Insert image description here

SOL_base_Basic color block effect:

Insert image description here

Among them, the effect of SOL_base_A channel:

Insert image description here

  • Among them, channel A is to draw black the text pattern area on the character.
SOL_ilm: as follows

Insert image description here

Regional distribution on SOL_ilm model

as follows:
Insert image description here

- From left to right, RGBA.
  • R channel: Controls the overall highlight intensity.

  • G channel: Controls the offset value of NdotL lighting, such as wrinkles.

  • B channel: Control the size, range or shape of the highlight.

  • A channel: the inner drawing line of the character model.

  • Vertex color:

  • R channel: AO, also controls NdotL lighting offset.

SOL_Sss: as follows

Insert image description here

The effect of SOL_ilm on the model

Insert image description here

The color obtained by multiplying the value of SSSTexture and the color of the ambient light determines the shadow color. Key light color for
bright areas Ambient light color for dark areas

optimization

Full body picture before optimization

Insert image description here

Optimized whole body picture

Insert image description here

facial comparison chart

Insert image description here

Belt and arm stroke comparison chart

Insert image description here

Comparison chart

Please add image description

Rendering code

Shader "SOL"
{
    
    
    Properties
    {
    
    
        [Header(BaseColor)]
        _MainTex ("BaseTex", 2D) = "white" {
    
    }
        [Space(20)]
        [Header(ILM)]
        _ILMTex("ILMTex",2D) = "gray"{
    
    }
        [Space(20)]
        [Header(SSS)]
        _SssTex("SssTex",2D) = "black"{
    
    }
        [Space(20)]
        [Header(Detail)]
        _DetailTex("DetailTex",2D) = "white"{
    
    }
        _ToonThreshold("ToonThreshold",Range(0,1)) = 0.5
        _ToonHardness("ToonHardness",Float) = 20.0
        _SpecColor("spec color", Color) = (1,1,1,1)
        _SpecSize("Spec Size",Range(0,1)) = 1
        [Space(20)]
        [Header(OutLine)]
        _OutlineColor("Outline Color", Color) = (0,0,0,0)
        _Outlinewidth("Outline Width",Range(0,1)) = 1
    }
    SubShader
    {
    
    
        Tags {
    
     "RenderType"="Opaque" }
        LOD 100
        Pass
        {
    
    
            Tags{
    
    "LightMode"="ForwardBase"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fwdbase

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

            struct appdata
            {
    
    
                float4 vertex : POSITION;
                float2 uv0 : TEXCOORD0;
                float2 uv1 : TEXCOORD1;
                half3 normal : NORMAL;
                half4 color : COLOR;
            };

            struct v2f
            {
    
    
                float4 uv : TEXCOORD0;
                float4 pos : SV_POSITION;
                half4 vertexColor : TEXCOORD1;
                half3 worldNormal : TEXCOORD2;
                float3 worldPos : TEXCOORD3;
            };

            sampler2D _MainTex;
            sampler2D _ILMTex;
            sampler2D _SssTex;
            sampler2D _DetailTex;

            half _ToonThreshold;
            half _ToonHardness;
            half _SpecSize;

            //没有定义"float4 _SpecColor" 是因为在#include "UnityLightingCommon.cginc"文件里已经被声明。
            // float4 _SpecColor;

            v2f vert (appdata v)
            {
    
    
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = float4 (v.uv0,v.uv1);
                o.vertexColor = v.color;
                o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;
                o.worldNormal = mul(v.normal,(float3x3)unity_WorldToObject);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
    
    
                half2 uv1 = i.uv.xy;
                half2 uv2 = i.uv.zw;
                //贴图采样、亮部和暗部的颜色、控制高光的强度
                fixed4 ilm = tex2D(_ILMTex,i.uv.xy);
                half spec_intensity = ilm.r;//控制高光强度
                half diffuse_control = ilm.g * 2.0 - 1.0;//光照偏移
                half spec_size = ilm.b;//控制高光形状
                half inner_line = ilm.a;//内描线
                fixed4 baseColor = tex2D(_MainTex, i.uv.xy);//亮部的颜色
                fixed4 sssColor = tex2D(_SssTex,i.uv.xy);//暗部的颜色
                fixed3 detail = tex2D(_DetailTex,i.uv.zw);//细节线条
                //顶点处理
                half ao = saturate((i.vertexColor.r - 0.7) * 50);
                //向量
                half3 worldNormal = normalize(i.worldNormal);
                half3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
                half3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
                //漫反射
                half NdotL = dot(worldLightDir,worldNormal);
                half halflambert = (NdotL + 1.0) * 0.5;
                half lambertterm = halflambert * ao + diffuse_control;
                half toondiffuse = saturate ((lambertterm - _ToonThreshold) * _ToonHardness);
                half3 finaldiffuse  = lerp(sssColor ,baseColor,toondiffuse);

                //高光
                float NdotV = (dot(worldNormal,worldViewDir) + 1.0) * 0.5;
                float spec_term = NdotV * ao + diffuse_control;
                spec_term = halflambert * 0.9 + spec_term * 0.1;
                half toon_spec = saturate((spec_term - (1.0 - spec_size * _SpecSize)) * 500);
                half3 speccolor = (_SpecColor.xyz + baseColor) * 0.5;
                half3 finaspec = toon_spec * speccolor * spec_intensity;

                //描线
                half3 inner_line_Color = lerp(baseColor * 0.2 , float3(1.0,1.0,1.0),inner_line);
                half3 ditailcolor = tex2D(_DetailTex , uv2);
                ditailcolor = lerp(baseColor * 0.2, float3(1.0,1.0,1.0),ditailcolor);
                half3 finalline = inner_line_Color * inner_line_Color * ditailcolor;

                fixed3 finalColor = (finaldiffuse + finaspec) * finalline;
                return float4(finalColor,1.0);
            }
            ENDCG
        }
        Pass
        {
    
    
            Cull Front
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fwdbase
            #include "UnityCG.cginc"
            struct appdata
            {
    
    
                float4 vertex : POSITION;
                float2 uv0 : TEXCOORD0;
                half3 normal : NORMAL;
                half4 color : COLOR;
            };
            struct v2f
            {
    
    
                float2 uv : TEXCOORD0;
                float4 pos : SV_POSITION;
                half4 vertexColor : TEXCOORD1;
                half3 worldNormal : TEXCOORD2;
                float3 worldPos : TEXCOORD3;
            };
            sampler2D _MainTex;
            float4 _OutlineColor;
            float _Outlinewidth;

            v2f vert (appdata v)
            {
    
    
                v2f o;
                float3 pos_VS = UnityObjectToViewPos(v.vertex);
                float3 normal_WS = UnityObjectToWorldNormal(v.normal);
                float3 outline_dir = normalize(mul((float3x3)UNITY_MATRIX_V,normal_WS));
                o.vertexColor = v.color;
                pos_VS += outline_dir * _Outlinewidth * 0.001 * v.color.a;
                o.pos = mul(UNITY_MATRIX_P,float4(pos_VS,1.0));
                o.uv = v.uv0;
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
    
    
                fixed3 baseColor = tex2D(_MainTex, i.uv.xy).xyz;
                half maxComponent = max(max(baseColor.r,baseColor.g),baseColor.b) - 0.004;
                half3 saturatedColor = step(maxComponent.rrr,baseColor) * baseColor;
                saturatedColor = lerp(baseColor.rgb,saturatedColor,0.6);
                half3 outlineColor = 0.8 * saturatedColor * baseColor * _OutlineColor.xyz;
                return float4(outlineColor,1.0);
            }
            ENDCG
        }
    }
}

Card rendering reference link:

Zenji Nishikawa: The secret of "real-time 3D graphics of pure cartoon animation"
[Translation] The secret of "real-time 3D graphics of pure cartoon animation" implemented in Zenji Nishikawa's "experimental game graphics" "GUILTY GEAR Xrd -SIGN-", Part 1 (1)

Guess you like

Origin blog.csdn.net/xukaibo111/article/details/133418246