光照

作者: Dragon_boy | 来源:发表于2023-06-26 15:37 被阅读0次

    Toon_DoubleShadeWithFeather为例,shader第二、三个pass。
    平行光:

            Pass {
                Name "FORWARD"
                Tags {
                    "LightMode"="ForwardBase"
                }
    
                Cull[_CullMode]
                
                
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                //#define UNITY_PASS_FORWARDBASE
                #include "UnityCG.cginc"
                #include "AutoLight.cginc"
                #include "Lighting.cginc"
                #pragma multi_compile_fwdbase_fullshadows
                #pragma multi_compile_fog
                #pragma only_renderers d3d9 d3d11 glcore gles gles3 metal vulkan xboxone ps4 switch
                #pragma target 3.0
    
                //v.2.0.4
                #pragma multi_compile _IS_CLIPPING_OFF
                #pragma multi_compile _IS_PASS_FWDBASE
                //v.2.0.7
                #pragma multi_compile _EMISSIVE_SIMPLE _EMISSIVE_ANIMATION
                //
                #include "UCTS_DoubleShadeWithFeather.cginc"
    
                ENDCG
            }
    

    平行光支持自发光和动态自发光。
    其它光:

            Pass {
                Name "FORWARD_DELTA"
                Tags {
                    "LightMode"="ForwardAdd"
                }
    
                Blend One One
                Cull[_CullMode]
                
                
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                //#define UNITY_PASS_FORWARDADD
                #include "UnityCG.cginc"
                #include "AutoLight.cginc"
                #include "Lighting.cginc"
                //for Unity2018.x
                #pragma multi_compile_fwdadd_fullshadows
                #pragma multi_compile_fog
                #pragma only_renderers d3d9 d3d11 glcore gles gles3 metal vulkan xboxone ps4 switch
                #pragma target 3.0
    
                //v.2.0.4
                #pragma multi_compile _IS_CLIPPING_OFF
                #pragma multi_compile _IS_PASS_FWDDELTA
                #include "UCTS_DoubleShadeWithFeather.cginc"
    
                ENDCG
            }
    

    主要实现位于UCTS_DoubleShadeWithFeather.cginc中。
    顶点着色器没有什么特别的,只不过增加了一个判断是否镜像的过程。如果镜像的话,镜中摄像机Z轴应该与现实场景中相反。

                VertexOutput vert (VertexInput v) {
                    VertexOutput o = (VertexOutput)0;
                    UNITY_SETUP_INSTANCE_ID(v);
                    UNITY_TRANSFER_INSTANCE_ID(v, o);
                    UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
                    o.uv0 = v.texcoord0;
                    o.normalDir = UnityObjectToWorldNormal(v.normal);
                    o.tangentDir = normalize( mul( unity_ObjectToWorld, float4( v.tangent.xyz, 0.0 ) ).xyz );
                    o.bitangentDir = normalize(cross(o.normalDir, o.tangentDir) * v.tangent.w);
                    o.posWorld = mul(unity_ObjectToWorld, v.vertex);
                    float3 lightColor = _LightColor0.rgb;
                    o.pos = UnityObjectToClipPos( v.vertex );
                    //v.2.0.7 鏡の中判定(右手座標系か、左手座標系かの判定)o.mirrorFlag = -1 なら鏡の中.
                    float3 crossFwd = cross(UNITY_MATRIX_V[0], UNITY_MATRIX_V[1]);
                    o.mirrorFlag = dot(crossFwd, UNITY_MATRIX_V[2]) < 0 ? 1 : -1;
                    //
                    UNITY_TRANSFER_FOG(o,o.pos);
                    TRANSFER_VERTEX_TO_FRAGMENT(o)
                    return o;
                }
    

    片元着色器中,先是采样法线贴图和颜色纹理的正常操作:

                float4 frag(VertexOutput i, fixed facing : VFACE) : SV_TARGET {
    
                    UNITY_SETUP_INSTANCE_ID(i);
                    UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
    
                    i.normalDir = normalize(i.normalDir);
                    float3x3 tangentTransform = float3x3( i.tangentDir, i.bitangentDir, i.normalDir);
                    float3 viewDirection = normalize(_WorldSpaceCameraPos.xyz - i.posWorld.xyz);
                    float2 Set_UV0 = i.uv0;
                    //v.2.0.6
                    //float3 _NormalMap_var = UnpackNormal(tex2D(_NormalMap,TRANSFORM_TEX(Set_UV0, _NormalMap)));
                    float3 _NormalMap_var = UnpackScaleNormal(tex2D(_NormalMap,TRANSFORM_TEX(Set_UV0, _NormalMap)), _BumpScale);
                    float3 normalLocal = _NormalMap_var.rgb;
                    float3 normalDirection = normalize(mul( normalLocal, tangentTransform )); // Perturbed normals
                    float4 _MainTex_var = tex2D(_MainTex,TRANSFORM_TEX(Set_UV0, _MainTex));
    

    接着是clipping,选择使用clipping mask还是颜色纹理的alpha通道

    //v.2.0.4
    #ifdef _IS_CLIPPING_MODE
    //DoubleShadeWithFeather_Clipping
                    float4 _ClippingMask_var = tex2D(_ClippingMask,TRANSFORM_TEX(Set_UV0, _ClippingMask));
                    float Set_Clipping = saturate((lerp( _ClippingMask_var.r, (1.0 - _ClippingMask_var.r), _Inverse_Clipping )+_Clipping_Level));
                    clip(Set_Clipping - 0.5);
    #elif _IS_CLIPPING_TRANSMODE
    //DoubleShadeWithFeather_TransClipping
                    float4 _ClippingMask_var = tex2D(_ClippingMask,TRANSFORM_TEX(Set_UV0, _ClippingMask));
                    float Set_MainTexAlpha = _MainTex_var.a;
                    float _IsBaseMapAlphaAsClippingMask_var = lerp( _ClippingMask_var.r, Set_MainTexAlpha, _IsBaseMapAlphaAsClippingMask );
                    float _Inverse_Clipping_var = lerp( _IsBaseMapAlphaAsClippingMask_var, (1.0 - _IsBaseMapAlphaAsClippingMask_var), _Inverse_Clipping );
                    float Set_Clipping = saturate((_Inverse_Clipping_var+_Clipping_Level));
                    clip(Set_Clipping - 0.5);
    
    #elif _IS_CLIPPING_OFF
    //DoubleShadeWithFeather
    #endif
    

    然后是光源。对于平行光,确保场景中一定有相应的光源,如果没有则使用默认的(大概是斜下45°)(defaultLightDirection),也可以使用用户自定义的平行光方向(customLightDirection)。

                    UNITY_LIGHT_ATTENUATION(attenuation, i, i.posWorld.xyz);
    
    //v.2.0.4
    #ifdef _IS_PASS_FWDBASE
    
                    float3 defaultLightDirection = normalize(UNITY_MATRIX_V[2].xyz + UNITY_MATRIX_V[1].xyz);
                    //v.2.0.5
                    float3 defaultLightColor = saturate(max(half3(0.05,0.05,0.05)*_Unlit_Intensity,max(ShadeSH9(half4(0.0, 0.0, 0.0, 1.0)),ShadeSH9(half4(0.0, -1.0, 0.0, 1.0)).rgb)*_Unlit_Intensity));
                    float3 customLightDirection = normalize(mul( unity_ObjectToWorld, float4(((float3(1.0,0.0,0.0)*_Offset_X_Axis_BLD*10)+(float3(0.0,1.0,0.0)*_Offset_Y_Axis_BLD*10)+(float3(0.0,0.0,-1.0)*lerp(-1.0,1.0,_Inverse_Z_Axis_BLD))),0)).xyz);
                    float3 lightDirection = normalize(lerp(defaultLightDirection,_WorldSpaceLightPos0.xyz,any(_WorldSpaceLightPos0.xyz)));
                    lightDirection = lerp(lightDirection, customLightDirection, _Is_BLD);
                    //v.2.0.5: 
                    float3 lightColor = lerp(max(defaultLightColor,_LightColor0.rgb),max(defaultLightColor,saturate(_LightColor0.rgb)),_Is_Filter_LightColor);
    

    对于其它光源,则正常计算,可选顶点法线或法线贴图法线来计算NoL。

    #elif _IS_PASS_FWDDELTA
                    float3 lightDirection = normalize(lerp(_WorldSpaceLightPos0.xyz, _WorldSpaceLightPos0.xyz - i.posWorld.xyz,_WorldSpaceLightPos0.w));
                    //v.2.0.5: 
                    float3 addPassLightColor = (0.5*dot(lerp( i.normalDir, normalDirection, _Is_NormalMapToBase ), lightDirection)+0.5) * _LightColor0.rgb * attenuation;
                    float pureIntencity = max(0.001,(0.299*_LightColor0.r + 0.587*_LightColor0.g + 0.114*_LightColor0.b));
                    float3 lightColor = max(0, lerp(addPassLightColor, lerp(0,min(addPassLightColor,addPassLightColor/pureIntencity),_WorldSpaceLightPos0.w),_Is_Filter_LightColor));
    #endif
                    float3 halfDirection = normalize(viewDirection+lightDirection);
                    //v.2.0.5
                    _Color = _BaseColor;
    

    然后是最重要的toon shading。
    对于场景第一个主要光源(通常是平行光)
    获取base,1st shade, 2nd shade的颜色,以及采样控制1st和2nd分布的position texture。

    #ifdef _IS_PASS_FWDBASE
                    float3 Set_LightColor = lightColor.rgb;
                    float3 Set_BaseColor = lerp( (_BaseColor.rgb*_MainTex_var.rgb), ((_BaseColor.rgb*_MainTex_var.rgb)*Set_LightColor), _Is_LightColor_Base );
                    //v.2.0.5
                    float4 _1st_ShadeMap_var = lerp(tex2D(_1st_ShadeMap,TRANSFORM_TEX(Set_UV0, _1st_ShadeMap)),_MainTex_var,_Use_BaseAs1st);
                    float3 Set_1st_ShadeColor = lerp( (_1st_ShadeColor.rgb*_1st_ShadeMap_var.rgb), ((_1st_ShadeColor.rgb*_1st_ShadeMap_var.rgb)*Set_LightColor), _Is_LightColor_1st_Shade );
                    //v.2.0.5
                    float4 _2nd_ShadeMap_var = lerp(tex2D(_2nd_ShadeMap,TRANSFORM_TEX(Set_UV0, _2nd_ShadeMap)),_1st_ShadeMap_var,_Use_1stAs2nd);
                    float3 Set_2nd_ShadeColor = lerp( (_2nd_ShadeColor.rgb*_2nd_ShadeMap_var.rgb), ((_2nd_ShadeColor.rgb*_2nd_ShadeMap_var.rgb)*Set_LightColor), _Is_LightColor_2nd_Shade );
                    float _HalfLambert_var = 0.5*dot(lerp( i.normalDir, normalDirection, _Is_NormalMapToBase ),lightDirection)+0.5;
                    float4 _Set_2nd_ShadePosition_var = tex2D(_Set_2nd_ShadePosition,TRANSFORM_TEX(Set_UV0, _Set_2nd_ShadePosition));
                    float4 _Set_1st_ShadePosition_var = tex2D(_Set_1st_ShadePosition,TRANSFORM_TEX(Set_UV0, _Set_1st_ShadePosition));
    

    应用Unity系统阴影值(UNITY_LIGHT_ATTENUATION计算得到),_Tweak_SystemShadowsLevel值为±0.5,因此阴影值先映射到0.5-1。混合阴影值大约是\big<1-\frac{(NoL-(BS-BF))\times S1P}{BF}\big>(简化过),其中NoL映射到了0-1,且应用了系统阴影值。

                    float _SystemShadowsLevel_var = (attenuation*0.5)+0.5+_Tweak_SystemShadowsLevel > 0.001 ? (attenuation*0.5)+0.5+_Tweak_SystemShadowsLevel : 0.0001;
                    float Set_FinalShadowMask = saturate((1.0 + ( (lerp( _HalfLambert_var, _HalfLambert_var*saturate(_SystemShadowsLevel_var), _Set_SystemShadowsToBase ) - (_BaseColor_Step-_BaseShade_Feather)) * ((1.0 - _Set_1st_ShadePosition_var.rgb).r - 1.0) ) / (_BaseColor_Step - (_BaseColor_Step-_BaseShade_Feather))));
    

    加上1st和2nd之间的step和feather,可得最终颜色。lerp(BC,lerp(1SC,2SC,\big<1-\frac{(NoL-(SS-SF))\times S2P}{SF}\big>), ShadowMask)(此处NoL也是0-1,但未应用系统阴影值)。

                    float3 Set_FinalBaseColor = lerp(Set_BaseColor,lerp(Set_1st_ShadeColor,Set_2nd_ShadeColor,saturate((1.0 + ( (_HalfLambert_var - (_ShadeColor_Step-_1st2nd_Shades_Feather)) * ((1.0 - _Set_2nd_ShadePosition_var.rgb).r - 1.0) ) / (_ShadeColor_Step - (_ShadeColor_Step-_1st2nd_Shades_Feather))))),Set_FinalShadowMask); // Final Color
    

    再来是高光HighColor。
    采样高光mask图,混合镜面反射HoN和遮罩Tweak微调参数计算最终遮罩。
    如果不应用镜面高光,遮罩值大概是\big<HM+Tweak\big>\times (1-step(HoN,(1-HCP^5)))
    如果应用镜面高光,则\big<HM+Tweak\big>\times HoN^{exp2(lerp(11,1,HCP))}
    最后可得混合高光的颜色。

                    float4 _Set_HighColorMask_var = tex2D(_Set_HighColorMask,TRANSFORM_TEX(Set_UV0, _Set_HighColorMask));
                    float _Specular_var = 0.5*dot(halfDirection,lerp( i.normalDir, normalDirection, _Is_NormalMapToHighColor ))+0.5; //  Specular                
                    float _TweakHighColorMask_var = (saturate((_Set_HighColorMask_var.g+_Tweak_HighColorMaskLevel))*lerp( (1.0 - step(_Specular_var,(1.0 - pow(_HighColor_Power,5)))), pow(_Specular_var,exp2(lerp(11,1,_HighColor_Power))), _Is_SpecularToHighColor ));
                    float4 _HighColor_Tex_var = tex2D(_HighColor_Tex,TRANSFORM_TEX(Set_UV0, _HighColor_Tex));
                    float3 _HighColor_var = (lerp( (_HighColor_Tex_var.rgb*_HighColor.rgb), ((_HighColor_Tex_var.rgb*_HighColor.rgb)*Set_LightColor), _Is_LightColor_HighColor )*_TweakHighColorMask_var);
                    //Composition: 3 Basic Colors and HighColor as Set_HighColor
                    float3 Set_HighColor = (lerp( saturate((Set_FinalBaseColor-_TweakHighColorMask_var)), Set_FinalBaseColor, lerp(_Is_BlendAddToHiColor,1.0,_Is_SpecularToHighColor) )+lerp( _HighColor_var, (_HighColor_var*((1.0 - Set_FinalShadowMask)+(Set_FinalShadowMask*_TweakHighColorOnShadow))), _Is_UseTweakHighColorOnShadow ));
    

    再然后是轮廓光RimLight。采样mask,1-NoV计算轮廓光区域,再根据NoL计算光源方向遮罩,加上光源方向参数。

                    float4 _Set_RimLightMask_var = tex2D(_Set_RimLightMask,TRANSFORM_TEX(Set_UV0, _Set_RimLightMask));
                    float3 _Is_LightColor_RimLight_var = lerp( _RimLightColor.rgb, (_RimLightColor.rgb*Set_LightColor), _Is_LightColor_RimLight );
                    float _RimArea_var = (1.0 - dot(lerp( i.normalDir, normalDirection, _Is_NormalMapToRimLight ),viewDirection));
                    float _RimLightPower_var = pow(_RimArea_var,exp2(lerp(3,0,_RimLight_Power)));
                    float _Rimlight_InsideMask_var = saturate(lerp( (0.0 + ( (_RimLightPower_var - _RimLight_InsideMask) * (1.0 - 0.0) ) / (1.0 - _RimLight_InsideMask)), step(_RimLight_InsideMask,_RimLightPower_var), _RimLight_FeatherOff ));
                    float _VertHalfLambert_var = 0.5*dot(i.normalDir,lightDirection)+0.5;
                    float3 _LightDirection_MaskOn_var = lerp( (_Is_LightColor_RimLight_var*_Rimlight_InsideMask_var), (_Is_LightColor_RimLight_var*saturate((_Rimlight_InsideMask_var-((1.0 - _VertHalfLambert_var)+_Tweak_LightDirection_MaskLevel)))), _LightDirection_MaskOn );
                    float _ApRimLightPower_var = pow(_RimArea_var,exp2(lerp(3,0,_Ap_RimLight_Power)));
                    float3 Set_RimLight = (saturate((_Set_RimLightMask_var.g+_Tweak_RimLightMaskLevel))*lerp( _LightDirection_MaskOn_var, (_LightDirection_MaskOn_var+(lerp( _Ap_RimLightColor.rgb, (_Ap_RimLightColor.rgb*Set_LightColor), _Is_LightColor_Ap_RimLight )*saturate((lerp( (0.0 + ( (_ApRimLightPower_var - _RimLight_InsideMask) * (1.0 - 0.0) ) / (1.0 - _RimLight_InsideMask)), step(_RimLight_InsideMask,_ApRimLightPower_var), _Ap_RimLight_FeatherOff )-(saturate(_VertHalfLambert_var)+_Tweak_LightDirection_MaskLevel))))), _Add_Antipodean_RimLight ));
                    //Composition: HighColor and RimLight as _RimLight_var
                    float3 _RimLight_var = lerp( Set_HighColor, (Set_HighColor+Set_RimLight), _RimLight );
    

    接着是MatCap,原理参考MatCap原理介绍及应用 - 知乎 (zhihu.com)

                    //Matcap
                    //v.2.0.6 : CameraRolling Stabilizer
                    //鏡スクリプト判定:_sign_Mirror = -1 なら、鏡の中と判定.
                    //v.2.0.7
                    fixed _sign_Mirror = i.mirrorFlag;
                    //
                    float3 _Camera_Right = UNITY_MATRIX_V[0].xyz;
                    float3 _Camera_Front = UNITY_MATRIX_V[2].xyz;
                    float3 _Up_Unit = float3(0, 1, 0);
                    float3 _Right_Axis = cross(_Camera_Front, _Up_Unit);
                    //鏡の中なら反転.
                    if(_sign_Mirror < 0){
                        _Right_Axis = -1 * _Right_Axis;
                        _Rotate_MatCapUV = -1 * _Rotate_MatCapUV;
                    }else{
                        _Right_Axis = _Right_Axis;
                    }
                    float _Camera_Right_Magnitude = sqrt(_Camera_Right.x*_Camera_Right.x + _Camera_Right.y*_Camera_Right.y + _Camera_Right.z*_Camera_Right.z);
                    float _Right_Axis_Magnitude = sqrt(_Right_Axis.x*_Right_Axis.x + _Right_Axis.y*_Right_Axis.y + _Right_Axis.z*_Right_Axis.z);
                    float _Camera_Roll_Cos = dot(_Right_Axis, _Camera_Right) / (_Right_Axis_Magnitude * _Camera_Right_Magnitude);
                    float _Camera_Roll = acos(clamp(_Camera_Roll_Cos, -1, 1));
                    fixed _Camera_Dir = _Camera_Right.y < 0 ? -1 : 1;
                    float _Rot_MatCapUV_var_ang = (_Rotate_MatCapUV*3.141592654) - _Camera_Dir*_Camera_Roll*_CameraRolling_Stabilizer;
                    //v.2.0.7
                    float2 _Rot_MatCapNmUV_var = RotateUV(Set_UV0, (_Rotate_NormalMapForMatCapUV*3.141592654), float2(0.5, 0.5), 1.0);
                    //V.2.0.6
                    float3 _NormalMapForMatCap_var = UnpackScaleNormal(tex2D(_NormalMapForMatCap,TRANSFORM_TEX(_Rot_MatCapNmUV_var, _NormalMapForMatCap)),_BumpScaleMatcap);
                    //v.2.0.5: MatCap with camera skew correction
                    float3 viewNormal = (mul(UNITY_MATRIX_V, float4(lerp( i.normalDir, mul( _NormalMapForMatCap_var.rgb, tangentTransform ).rgb, _Is_NormalMapForMatCap ),0))).rgb;
                    float3 NormalBlend_MatcapUV_Detail = viewNormal.rgb * float3(-1,-1,1);
                    float3 NormalBlend_MatcapUV_Base = (mul( UNITY_MATRIX_V, float4(viewDirection,0) ).rgb*float3(-1,-1,1)) + float3(0,0,1);
                    float3 noSknewViewNormal = NormalBlend_MatcapUV_Base*dot(NormalBlend_MatcapUV_Base, NormalBlend_MatcapUV_Detail)/NormalBlend_MatcapUV_Base.b - NormalBlend_MatcapUV_Detail;                
                    float2 _ViewNormalAsMatCapUV = (lerp(noSknewViewNormal,viewNormal,_Is_Ortho).rg*0.5)+0.5;
                    //v.2.0.7
                    float2 _Rot_MatCapUV_var = RotateUV((0.0 + ((_ViewNormalAsMatCapUV - (0.0+_Tweak_MatCapUV)) * (1.0 - 0.0) ) / ((1.0-_Tweak_MatCapUV) - (0.0+_Tweak_MatCapUV))), _Rot_MatCapUV_var_ang, float2(0.5, 0.5), 1.0);
                    //鏡の中ならUV左右反転.
                    if(_sign_Mirror < 0){
                        _Rot_MatCapUV_var.x = 1-_Rot_MatCapUV_var.x;
                    }else{
                        _Rot_MatCapUV_var = _Rot_MatCapUV_var;
                    }
                    //v.2.0.6 : LOD of Matcap
                    float4 _MatCap_Sampler_var = tex2Dlod(_MatCap_Sampler,float4(TRANSFORM_TEX(_Rot_MatCapUV_var, _MatCap_Sampler),0.0,_BlurLevelMatcap));
                    //
                    //MatcapMask
                    float4 _Set_MatcapMask_var = tex2D(_Set_MatcapMask,TRANSFORM_TEX(Set_UV0, _Set_MatcapMask));
                    float _Tweak_MatcapMaskLevel_var = saturate(lerp(_Set_MatcapMask_var.g, (1.0 - _Set_MatcapMask_var.g), _Inverse_MatcapMask) + _Tweak_MatcapMaskLevel);
                    //
                    float3 _Is_LightColor_MatCap_var = lerp( (_MatCap_Sampler_var.rgb*_MatCapColor.rgb), ((_MatCap_Sampler_var.rgb*_MatCapColor.rgb)*Set_LightColor), _Is_LightColor_MatCap );
                    //v.2.0.6 : ShadowMask on Matcap in Blend mode : multiply
                    float3 Set_MatCap = lerp( _Is_LightColor_MatCap_var, (_Is_LightColor_MatCap_var*((1.0 - Set_FinalShadowMask)+(Set_FinalShadowMask*_TweakMatCapOnShadow)) + lerp(Set_HighColor*Set_FinalShadowMask*(1.0-_TweakMatCapOnShadow), float3(0.0, 0.0, 0.0), _Is_BlendAddToMatCap)), _Is_UseTweakMatCapOnShadow );
                    //
                    //Composition: RimLight and MatCap as finalColor
                    //Broke down finalColor composition
                    float3 matCapColorOnAddMode = _RimLight_var+Set_MatCap*_Tweak_MatcapMaskLevel_var;
                    float _Tweak_MatcapMaskLevel_var_MultiplyMode = _Tweak_MatcapMaskLevel_var * lerp (1.0, (1.0 - (Set_FinalShadowMask)*(1.0 - _TweakMatCapOnShadow)), _Is_UseTweakMatCapOnShadow);
                    float3 matCapColorOnMultiplyMode = Set_HighColor*(1-_Tweak_MatcapMaskLevel_var_MultiplyMode) + Set_HighColor*Set_MatCap*_Tweak_MatcapMaskLevel_var_MultiplyMode + lerp(float3(0,0,0),Set_RimLight,_RimLight);
                    float3 matCapColorFinal = lerp(matCapColorOnMultiplyMode, matCapColorOnAddMode, _Is_BlendAddToMatCap);
                    float3 finalColor = lerp(_RimLight_var, matCapColorFinal, _MatCap);// Final Composition before Emissive
    

    /* ----------------------------------- */

    平行光可以有自发光效果,对于简易的自发光,采样纹理,应用颜色和mask即可。

    #ifdef _EMISSIVE_SIMPLE
                    float4 _Emissive_Tex_var = tex2D(_Emissive_Tex,TRANSFORM_TEX(Set_UV0, _Emissive_Tex));
                    float emissiveMask = _Emissive_Tex_var.a;
                    emissive = _Emissive_Tex_var.rgb * _Emissive_Color.rgb * emissiveMask;
    

    平行光可支持动态自发光,说白了就是在UV上做文章。

    #elif _EMISSIVE_ANIMATION
                    //v.2.0.7 Calculation View Coord UV for Scroll 
                    float3 viewNormal_Emissive = (mul(UNITY_MATRIX_V, float4(i.normalDir,0))).xyz;
                    float3 NormalBlend_Emissive_Detail = viewNormal_Emissive * float3(-1,-1,1);
                    float3 NormalBlend_Emissive_Base = (mul( UNITY_MATRIX_V, float4(viewDirection,0)).xyz*float3(-1,-1,1)) + float3(0,0,1);
                    float3 noSknewViewNormal_Emissive = NormalBlend_Emissive_Base*dot(NormalBlend_Emissive_Base, NormalBlend_Emissive_Detail)/NormalBlend_Emissive_Base.z - NormalBlend_Emissive_Detail;
                    float2 _ViewNormalAsEmissiveUV = noSknewViewNormal_Emissive.xy*0.5+0.5;
                    float2 _ViewCoord_UV = RotateUV(_ViewNormalAsEmissiveUV, -(_Camera_Dir*_Camera_Roll), float2(0.5,0.5), 1.0);
                    //鏡の中ならUV左右反転.
                    if(_sign_Mirror < 0){
                        _ViewCoord_UV.x = 1-_ViewCoord_UV.x;
                    }else{
                        _ViewCoord_UV = _ViewCoord_UV;
                    }
                    float2 emissive_uv = lerp(i.uv0, _ViewCoord_UV, _Is_ViewCoord_Scroll);
                    //
                    float4 _time_var = _Time;
                    float _base_Speed_var = (_time_var.g*_Base_Speed);
                    float _Is_PingPong_Base_var = lerp(_base_Speed_var, sin(_base_Speed_var), _Is_PingPong_Base );
                    float2 scrolledUV = emissive_uv - float2(_Scroll_EmissiveU, _Scroll_EmissiveV)*_Is_PingPong_Base_var;
                    float rotateVelocity = _Rotate_EmissiveUV*3.141592654;
                    float2 _rotate_EmissiveUV_var = RotateUV(scrolledUV, rotateVelocity, float2(0.5, 0.5), _Is_PingPong_Base_var);
                    float4 _Emissive_Tex_var = tex2D(_Emissive_Tex,TRANSFORM_TEX(Set_UV0, _Emissive_Tex));
                    float emissiveMask = _Emissive_Tex_var.a;
                    _Emissive_Tex_var = tex2D(_Emissive_Tex,TRANSFORM_TEX(_rotate_EmissiveUV_var, _Emissive_Tex));
                    float _colorShift_Speed_var = 1.0 - cos(_time_var.g*_ColorShift_Speed);
                    float viewShift_var = smoothstep( 0.0, 1.0, max(0,dot(normalDirection,viewDirection)));
                    float4 colorShift_Color = lerp(_Emissive_Color, lerp(_Emissive_Color, _ColorShift, _colorShift_Speed_var), _Is_ColorShift);
                    float4 viewShift_Color = lerp(_ViewShift, colorShift_Color, viewShift_var);
                    float4 emissive_Color = lerp(colorShift_Color, viewShift_Color, _Is_ViewShift);
                    emissive = emissive_Color.rgb * _Emissive_Tex_var.rgb * emissiveMask;
    #endif
    

    最后混合上GI自发光可得最终颜色

                   finalColor =  saturate(finalColor) + (envLightColor*envLightIntensity*_GI_Intensity*smoothstep(1,0,envLightIntensity/2)) + emissive;
    

    对于除主光源外的其它光源(点光,聚光等)则更加简单,不必考虑轮廓光,matcap和自发光以及GI,其余类似

    #elif _IS_PASS_FWDDELTA
                    //v.2.0.5:
                    _BaseColor_Step = saturate(_BaseColor_Step + _StepOffset);
                    _ShadeColor_Step = saturate(_ShadeColor_Step + _StepOffset);
                    //
                    //v.2.0.5: If Added lights is directional, set 0 as _LightIntensity
                    float _LightIntensity = lerp(0,(0.299*_LightColor0.r + 0.587*_LightColor0.g + 0.114*_LightColor0.b)*attenuation,_WorldSpaceLightPos0.w) ;
                    //v.2.0.5: Filtering the high intensity zone of PointLights
                    float3 Set_LightColor = lerp(lightColor,lerp(lightColor,min(lightColor,_LightColor0.rgb*attenuation*_BaseColor_Step),_WorldSpaceLightPos0.w),_Is_Filter_HiCutPointLightColor);
                    //
                    float3 Set_BaseColor = lerp( (_BaseColor.rgb*_MainTex_var.rgb*_LightIntensity), ((_BaseColor.rgb*_MainTex_var.rgb)*Set_LightColor), _Is_LightColor_Base );
                    //v.2.0.5
                    float4 _1st_ShadeMap_var = lerp(tex2D(_1st_ShadeMap,TRANSFORM_TEX(Set_UV0, _1st_ShadeMap)),_MainTex_var,_Use_BaseAs1st);
                    float3 Set_1st_ShadeColor = lerp( (_1st_ShadeColor.rgb*_1st_ShadeMap_var.rgb*_LightIntensity), ((_1st_ShadeColor.rgb*_1st_ShadeMap_var.rgb)*Set_LightColor), _Is_LightColor_1st_Shade );
                    //v.2.0.5
                    float4 _2nd_ShadeMap_var = lerp(tex2D(_2nd_ShadeMap,TRANSFORM_TEX(Set_UV0, _2nd_ShadeMap)),_1st_ShadeMap_var,_Use_1stAs2nd);
                    float3 Set_2nd_ShadeColor = lerp( (_2nd_ShadeColor.rgb*_2nd_ShadeMap_var.rgb*_LightIntensity), ((_2nd_ShadeColor.rgb*_2nd_ShadeMap_var.rgb)*Set_LightColor), _Is_LightColor_2nd_Shade );
                    float _HalfLambert_var = 0.5*dot(lerp( i.normalDir, normalDirection, _Is_NormalMapToBase ),lightDirection)+0.5;
                    float4 _Set_2nd_ShadePosition_var = tex2D(_Set_2nd_ShadePosition,TRANSFORM_TEX(Set_UV0, _Set_2nd_ShadePosition));
                    float4 _Set_1st_ShadePosition_var = tex2D(_Set_1st_ShadePosition,TRANSFORM_TEX(Set_UV0, _Set_1st_ShadePosition));
                    //v.2.0.5:
                    float Set_FinalShadowMask = saturate((1.0 + ( (lerp( _HalfLambert_var, (_HalfLambert_var*saturate(1.0+_Tweak_SystemShadowsLevel)), _Set_SystemShadowsToBase ) - (_BaseColor_Step-_BaseShade_Feather)) * ((1.0 - _Set_1st_ShadePosition_var.rgb).r - 1.0) ) / (_BaseColor_Step - (_BaseColor_Step-_BaseShade_Feather))));
                    //Composition: 3 Basic Colors as finalColor
                    float3 finalColor = lerp(Set_BaseColor,lerp(Set_1st_ShadeColor,Set_2nd_ShadeColor,saturate((1.0 + ( (_HalfLambert_var - (_ShadeColor_Step-_1st2nd_Shades_Feather)) * ((1.0 - _Set_2nd_ShadePosition_var.rgb).r - 1.0) ) / (_ShadeColor_Step - (_ShadeColor_Step-_1st2nd_Shades_Feather))))),Set_FinalShadowMask); // Final Color
    
                    //v.2.0.6: Add HighColor if _Is_Filter_HiCutPointLightColor is False
                    float4 _Set_HighColorMask_var = tex2D(_Set_HighColorMask,TRANSFORM_TEX(Set_UV0, _Set_HighColorMask));
                    float _Specular_var = 0.5*dot(halfDirection,lerp( i.normalDir, normalDirection, _Is_NormalMapToHighColor ))+0.5; //  Specular                
                    float _TweakHighColorMask_var = (saturate((_Set_HighColorMask_var.g+_Tweak_HighColorMaskLevel))*lerp( (1.0 - step(_Specular_var,(1.0 - pow(_HighColor_Power,5)))), pow(_Specular_var,exp2(lerp(11,1,_HighColor_Power))), _Is_SpecularToHighColor ));
                    float4 _HighColor_Tex_var = tex2D(_HighColor_Tex,TRANSFORM_TEX(Set_UV0, _HighColor_Tex));
                    float3 _HighColor_var = (lerp( (_HighColor_Tex_var.rgb*_HighColor.rgb), ((_HighColor_Tex_var.rgb*_HighColor.rgb)*Set_LightColor), _Is_LightColor_HighColor )*_TweakHighColorMask_var);
                    finalColor = finalColor + lerp(lerp( _HighColor_var, (_HighColor_var*((1.0 - Set_FinalShadowMask)+(Set_FinalShadowMask*_TweakHighColorOnShadow))), _Is_UseTweakHighColorOnShadow ),float3(0,0,0),_Is_Filter_HiCutPointLightColor);
                    //
    
                    finalColor = saturate(finalColor);
    #endif
    

    透明度上,只在主光源上进行透明度混合等操作。

    #ifdef _IS_CLIPPING_OFF
    //DoubleShadeWithFeather
        #ifdef _IS_PASS_FWDBASE
                        fixed4 finalRGBA = fixed4(finalColor,1);
        #elif _IS_PASS_FWDDELTA
                        fixed4 finalRGBA = fixed4(finalColor,0);
        #endif
    #elif _IS_CLIPPING_MODE
    //DoubleShadeWithFeather_Clipping
        #ifdef _IS_PASS_FWDBASE
                        fixed4 finalRGBA = fixed4(finalColor,1);
        #elif _IS_PASS_FWDDELTA
                        fixed4 finalRGBA = fixed4(finalColor,0);
        #endif
    #elif _IS_CLIPPING_TRANSMODE
    //DoubleShadeWithFeather_TransClipping
                        float Set_Opacity = saturate((_Inverse_Clipping_var+_Tweak_transparency));
        #ifdef _IS_PASS_FWDBASE
                        fixed4 finalRGBA = fixed4(finalColor,Set_Opacity);
        #elif _IS_PASS_FWDDELTA
                        fixed4 finalRGBA = fixed4(finalColor * Set_Opacity,0);
        #endif
    #endif
                    UNITY_APPLY_FOG(i.fogCoord, finalRGBA);
                    return finalRGBA;
    

    UCTS_ShadingGradeMap.cgincUCTS_DoubleShadeWithFeather.cginc略有不同。
    ShadingGradeMap中支持Angel Ring效果,传入了第二套UV

    #ifdef _IS_ANGELRING_OFF
    //
    #elif _IS_ANGELRING_ON
                    o.uv1 = v.texcoord1;
    #endif
    

    颜色计算:

    #ifdef _IS_ANGELRING_OFF
                    float3 finalColor = lerp(_RimLight_var, matCapColorFinal, _MatCap);// Final Composition before Emissive
                    //
    #elif _IS_ANGELRING_ON
                    float3 finalColor = lerp(_RimLight_var, matCapColorFinal, _MatCap);// Final Composition before AR
                    //v.2.0.7 AR Camera Rolling Stabilizer
                    float3 _AR_OffsetU_var = lerp(mul(UNITY_MATRIX_V, float4(i.normalDir,0)).xyz,float3(0,0,1),_AR_OffsetU);
                    float2 AR_VN = _AR_OffsetU_var.xy*0.5 + float2(0.5,0.5);
                    float2 AR_VN_Rotate = RotateUV(AR_VN, -(_Camera_Dir*_Camera_Roll), float2(0.5,0.5), 1.0);
                    float2 _AR_OffsetV_var = float2(AR_VN_Rotate.x, lerp(i.uv1.y, AR_VN_Rotate.y, _AR_OffsetV));
                    float4 _AngelRing_Sampler_var = tex2D(_AngelRing_Sampler,TRANSFORM_TEX(_AR_OffsetV_var, _AngelRing_Sampler));
                    float3 _Is_LightColor_AR_var = lerp( (_AngelRing_Sampler_var.rgb*_AngelRing_Color.rgb), ((_AngelRing_Sampler_var.rgb*_AngelRing_Color.rgb)*Set_LightColor), _Is_LightColor_AR );
                    float3 Set_AngelRing = _Is_LightColor_AR_var;
                    float Set_ARtexAlpha = _AngelRing_Sampler_var.a;
                    float3 Set_AngelRingWithAlpha = (_Is_LightColor_AR_var*_AngelRing_Sampler_var.a);
                    //Composition: MatCap and AngelRing as finalColor
                    finalColor = lerp(finalColor, lerp((finalColor + Set_AngelRing), ((finalColor*(1.0 - Set_ARtexAlpha))+Set_AngelRingWithAlpha), _ARSampler_AlphaOn ), _AngelRing );// Final Composition before Emissive
    #endif
    

    在计算三色阴影时也有不同,利用了ShadingGradeMap:

    #ifdef _IS_PASS_FWDBASE
                    float3 Set_LightColor = lightColor.rgb;
                    float3 Set_BaseColor = lerp( (_MainTex_var.rgb*_BaseColor.rgb), ((_MainTex_var.rgb*_BaseColor.rgb)*Set_LightColor), _Is_LightColor_Base );
                    //v.2.0.5
                    float4 _1st_ShadeMap_var = lerp(tex2D(_1st_ShadeMap,TRANSFORM_TEX(Set_UV0, _1st_ShadeMap)),_MainTex_var,_Use_BaseAs1st);
                    float3 _Is_LightColor_1st_Shade_var = lerp( (_1st_ShadeMap_var.rgb*_1st_ShadeColor.rgb), ((_1st_ShadeMap_var.rgb*_1st_ShadeColor.rgb)*Set_LightColor), _Is_LightColor_1st_Shade );
                    float _HalfLambert_var = 0.5*dot(lerp( i.normalDir, normalDirection, _Is_NormalMapToBase ),lightDirection)+0.5; // Half Lambert
                    //float4 _ShadingGradeMap_var = tex2D(_ShadingGradeMap,TRANSFORM_TEX(Set_UV0, _ShadingGradeMap));
                    //v.2.0.6
                    float4 _ShadingGradeMap_var = tex2Dlod(_ShadingGradeMap,float4(TRANSFORM_TEX(Set_UV0, _ShadingGradeMap),0.0,_BlurLevelSGM));
                    //v.2.0.6
                    //Minmimum value is same as the Minimum Feather's value with the Minimum Step's value as threshold.
                    float _SystemShadowsLevel_var = (attenuation*0.5)+0.5+_Tweak_SystemShadowsLevel > 0.001 ? (attenuation*0.5)+0.5+_Tweak_SystemShadowsLevel : 0.0001;
                    float _ShadingGradeMapLevel_var = _ShadingGradeMap_var.r < 0.95 ? _ShadingGradeMap_var.r+_Tweak_ShadingGradeMapLevel : 1;
                    float Set_ShadingGrade = saturate(_ShadingGradeMapLevel_var)*lerp( _HalfLambert_var, (_HalfLambert_var*saturate(_SystemShadowsLevel_var)), _Set_SystemShadowsToBase );
                    //
                    float Set_FinalShadowMask = saturate((1.0 + ( (Set_ShadingGrade - (_1st_ShadeColor_Step-_1st_ShadeColor_Feather)) * (0.0 - 1.0) ) / (_1st_ShadeColor_Step - (_1st_ShadeColor_Step-_1st_ShadeColor_Feather)))); // Base and 1st Shade Mask
                    float3 _BaseColor_var = lerp(Set_BaseColor,_Is_LightColor_1st_Shade_var,Set_FinalShadowMask);
                    //v.2.0.5
                    float4 _2nd_ShadeMap_var = lerp(tex2D(_2nd_ShadeMap,TRANSFORM_TEX(Set_UV0, _2nd_ShadeMap)),_1st_ShadeMap_var,_Use_1stAs2nd);
                    float Set_ShadeShadowMask = saturate((1.0 + ( (Set_ShadingGrade - (_2nd_ShadeColor_Step-_2nd_ShadeColor_Feather)) * (0.0 - 1.0) ) / (_2nd_ShadeColor_Step - (_2nd_ShadeColor_Step-_2nd_ShadeColor_Feather)))); // 1st and 2nd Shades Mask
                    //Composition: 3 Basic Colors as Set_FinalBaseColor
                    float3 Set_FinalBaseColor = lerp(_BaseColor_var,lerp(_Is_LightColor_1st_Shade_var,lerp( (_2nd_ShadeMap_var.rgb*_2nd_ShadeColor.rgb), ((_2nd_ShadeMap_var.rgb*_2nd_ShadeColor.rgb)*Set_LightColor), _Is_LightColor_2nd_Shade ),Set_ShadeShadowMask),Set_FinalShadowMask);
    
    

    对于Toon_DoubleShadeWithFeather的ShadowCaster pass,其它与常规类似:

            Pass {
                Name "ShadowCaster"
                Tags {
                    "LightMode"="ShadowCaster"
                }
                Offset 1, 1
                Cull Off
                
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                //#define UNITY_PASS_SHADOWCASTER
                #include "UnityCG.cginc"
                #include "Lighting.cginc"
                #pragma fragmentoption ARB_precision_hint_fastest
                #pragma multi_compile_shadowcaster
                #pragma multi_compile_fog
                #pragma only_renderers d3d9 d3d11 glcore gles gles3 metal vulkan xboxone ps4 switch
                #pragma target 3.0
                //v.2.0.4
                #pragma multi_compile _IS_CLIPPING_OFF
                #include "UCTS_ShadowCaster.cginc"
                ENDCG
            }
    

    UCTS_ShadowCaster.cginc中,顶点着色器并不太大变化:

                VertexOutput vert (VertexInput v) {
                    VertexOutput o = (VertexOutput)0;
                    UNITY_SETUP_INSTANCE_ID(v);
                    UNITY_TRANSFER_INSTANCE_ID(v, o);
                    UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
    #ifdef _IS_CLIPPING_MODE
    //_Clipping
                    o.uv0 = v.texcoord0;
    #elif _IS_CLIPPING_TRANSMODE
    //_TransClipping
                    o.uv0 = v.texcoord0;
    #elif _IS_CLIPPING_OFF
    //Default
    #endif
                    o.pos = UnityObjectToClipPos( v.vertex );
                    TRANSFER_SHADOW_CASTER(o)
                    return o;
                }
    

    片元着色器中,应用了clipping mask和颜色纹理中的alpha通道进行剔除操作。

               float4 frag(VertexOutput i) : SV_TARGET {
                    UNITY_SETUP_INSTANCE_ID(i);
    //                UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
    #ifdef _IS_CLIPPING_MODE
    //_Clipping
                    float2 Set_UV0 = i.uv0;
                    float4 _ClippingMask_var = tex2D(_ClippingMask,TRANSFORM_TEX(Set_UV0, _ClippingMask));
                    float Set_Clipping = saturate((lerp( _ClippingMask_var.r, (1.0 - _ClippingMask_var.r), _Inverse_Clipping )+_Clipping_Level));
                    clip(Set_Clipping - 0.5);
    #elif _IS_CLIPPING_TRANSMODE
    //_TransClipping
                    float2 Set_UV0 = i.uv0;
                    float4 _ClippingMask_var = tex2D(_ClippingMask,TRANSFORM_TEX(Set_UV0, _ClippingMask));
                    float4 _MainTex_var = tex2D(_MainTex,TRANSFORM_TEX(Set_UV0, _MainTex));
                    float Set_MainTexAlpha = _MainTex_var.a;
                    float _IsBaseMapAlphaAsClippingMask_var = lerp( _ClippingMask_var.r, Set_MainTexAlpha, _IsBaseMapAlphaAsClippingMask );
                    float _Inverse_Clipping_var = lerp( _IsBaseMapAlphaAsClippingMask_var, (1.0 - _IsBaseMapAlphaAsClippingMask_var), _Inverse_Clipping );
                    float Set_Clipping = saturate((_Inverse_Clipping_var+_Clipping_Level));
                    clip(Set_Clipping - 0.5);
    #elif _IS_CLIPPING_OFF
    //Default
    #endif
                    SHADOW_CASTER_FRAGMENT(i)
                }
    

    相关文章

      网友评论

          本文标题:光照

          本文链接:https://www.haomeiwen.com/subject/gibiydtx.html