## 总览 - `DoubleShadeWithFeather`:UTS/UniversalToon 的标准工作流程模式。允许 2 种阴影颜色(双阴影颜色)和颜色之间的渐变(羽化)。 - `ShadingGradeMap`:更高级的工作流程模式。除了 DoubleShadeWithFeather 功能之外,此着色器还可以保存称为 ShadingGradeMap 的特殊贴图。 ![](https://github.com/unity3d-jp/UnityChanToonShaderVer2_Project/raw/release/urp/2.3.0/Documentation~/Images_jpg/URP_image035.jpg) ### 案例文件 示例文件于`urp-2.2.0-notpackage`标签之后被移除,所以可以切换到该commit将示例文件复制出来。 - ToonShader.unity :Settings for an illustration-style shader. - ToonShader_CelLook.unity :Settings for a cel-style shader. - ToonShader_Emissive.unity :Settings for a shader with an emissive . - ToonShader_Firefly.unity :Multiple real-time point lights. - AngelRing\AngelRing.unity:Angel ring and ShadingGradeMap sample. - Baked Normal\Cube_HardEdge.unity:Baked Normal reference. - BoxProjection\BoxProjection.unity :Lighting a dark room using Box Projection. - EmissiveAnimation\EmisssiveAnimation.unity:EmissiveAnimation sample. - LightAndShadows\LightAndShadows.unity:Comparison between the PBR shader and UTS2. - MatCapMask\MatCapMask.unity:MatcapMask sample. - Mirror\MirrorTest.unity: Sample scene checking for a mirror object - NormalMap\NormalMap.unity :Tricks for using the normal map with UTS2. - PointLightTest\PointLightTest.unity:Sample of cel-style content with point lights. - Sample\Sample.unity :Introduction to the basic UTS2 shaders. - ShaderBall\ShaderBall.unity:UTS2 settings on an example shader ball. ## 贴图 ### 基础贴图 - Base Color - 1st Shade Color - 2nd Shade Color 除了基础的颜色纹理还可以接受多种自定义选项,例如 - High Color - Rim Light - MatCap - Emissive ### 法线贴图 法线贴图一般在`UTS/UniversalToon`中用于平滑阴影渐变效果。 此外还通过与比例尺一起使用来调整皮肤纹理,以及使用`MatCap`表现头发高光效果。 | `选项` | 函数 | 属性 | |:-------------------|:-------------------|:-------------------| | NormalMap Effectiveness | 选择是否在每种颜色上反射法线贴图。如果按钮为Off,则该颜色不会反映法线贴图,而是由对象本身的几何形状评估。 | | | `3 Basic Colors` | 当您希望法线贴图反映在颜色中时,请设置为活动。 | _Is_NormalMapToBase | | `HighColor` | 当您希望法线贴图影响高颜色时,请设置活动。 | _Is_NormalMapToHighColor | | `RimLight` | 当您希望法线贴图影响 RimLight 时,请设置为Active。 | _Is_NormalMapToRimLight | ### 用于添加阴影区域的PositionMap 用于调整投射阴影的顶点位置。`UniversalToonBodyShadingGradeMap`模式下才能使用。 | `选项` | 函数 | 属性 | |:-------------------|:-------------------|:-------------------| | `1st Shade Position Map` |使用PositionMap强制修改`1st Shade Color`的`Position`, 与系统照明无关。指定需要进行投射阴影的区域。| _Set_1st_ShadePosition | | `2nd Shade Position Map` |使用PositionMap强制修改`2st Shade Color`的`Position`, 与系统照明无关。指定需要进行投射阴影的区域。 (也会影响到`1st Shade Color`的`Position Map`). | _Set_2nd_ShadePosition | 为了独立于光照显示第二阴影颜色,请确保填充第一和第二阴影颜色位置图重叠的位置。这样,即使来自其他照明的阴影落在第二个阴影颜色区域,它也会继续显示。 ### Shading Grade Map 基于光照来调整阴影亮度,允许在 UV 点级别控制第一和/或第二阴影颜色。 该贴图的精细控制使得“当光线照射到衣服上时隐藏褶皱”这样的效果成为可能。将诸如环境光遮蔽贴图之类的着色贴图应用到着色等级贴图可以使阴影更容易根据光照下降。这对于创建跟随头发刘海或衣服凹面部分的阴影非常有用。 ### 边缘光效果(RimLight) `RimLight`、`LightDirection_MaskOn`、`Add_Antipoden_RimLight`效果: ![](https://github.com/unity3d-jp/UnityChanToonShaderVer2_Project/raw/release/urp/2.3.0/Documentation~/Images_jpg/UT2018_UTS2_SuperTips_14.jpg) RimLight 通常从相机的角度显示在对象边缘周围。在 UTS2 中,您可以相对于主灯的位置调整边缘灯的显示位置。('LightDirection 蒙版') 您还可以将 RimLight 设置为与光源相反的方向。您还可以使用“添加 Antipodean_RimLight”渲染“光反射”。 如果您只想在光源的相反方向上显示边缘光并沿光源方向切割边缘光,请将边缘光的光方向颜色指定为黑色 (0,0,0)。 ![](https://github.com/unity3d-jp/UnityChanToonShaderVer2_Project/raw/release/urp/2.3.0/Documentation~/Images_jpg/UT2018_UTS2_SuperTips_15.jpg) ### 天使环 https://github.com/unity3d-jp/UnityChanToonShaderVer2_Project/blob/release/urp/2.3.0/Documentation~/index.md#-making-materials-for-angel-ring 制作天使环材质首先需要将头发模型正面投射到UV上,做制作贴图。 ## 颜色 高光颜色 通常色(被光照射部分) 1号阴影(淡) 2号阴影(深) ## 模板功能 ![](https://github.com/unity3d-jp/UnityChanToonShaderVer2_Project/raw/release/urp/2.3.0/Documentation~/Images_jpg/URP_image036.jpg) 可以用来制作睫毛挡住头发的效果。 ## 半兰伯特模型 >有一个问题仍然存在。在光照无法到达的区域,模型的外观通常是全黑的,没有任何明暗变化,这会使模型的背光区域看起来就像一个平面一样,失去了模型细节表现。 为此Valve 公司在开发游戏《半条命》时提出了一种技术,由于该技术是在原兰伯特光照模型的基础上进行了一个简单的修改, 因此被称为半兰伯特光照模型。 $$Cdiffuse=(Clight · Mdiffuse) (0.5 (n· I) + 0.5)$$ 把n·I 的结果范围从[-1, 1 ]映射到[0, 1 ]范围内。也就是说,对于模型的背光面,在原兰伯特光照模型中点积结果将映射到同一个值,即0 值处;而在半兰伯特模型中,背光面也可以有明暗变化,不同的点积结果会映射到不同的值上。 ## 高光计算 使用半兰伯特模型计算高光Mask ```c# //半影值计算高光Mask(半兰伯特模型) float _Specular_var = 0.5*dot(halfDirection,lerp( i.normalDir, normalDirection, _Is_NormalMapToHighColor ))+0.5; // Specular //Step(a,x) => x>=a ? 1 : 0,计算高光Mask float _TweakHighColorMask_var = (saturate((_Set_HighColorMask_var.g+_Tweak_HighColorMaskLevel))*lerp( (1.0 - step(_Specular_var,(1.0 - pow(abs(_HighColor_Power),5)))), pow(abs(_Specular_var),exp2(lerp(11,1,_HighColor_Power))), _Is_SpecularToHighColor )); ``` 高光颜色=高光贴图 * 高光颜色设定值 * 灯光颜色(可选) ```c# 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_IF_SDR((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 )); ``` ## 边缘光 边缘光颜色=边缘光贴图 * 边缘光颜色设定值 * 灯光颜色(可选),其他调整参数有`_Ap_RimLight_Power`、`` ```c# 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 ); //区域计算=1-dot(ViewDir,Normal),之后pow(_RimArea_var,exp2(lerp(3,0,_RimLight_Power))),最后使用UTS祖传公式计算 float _RimArea_var = abs(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_IF_SDR((_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与头发的各向异性高光效果 UTS的老版本模型采用了Matcap给头发圈定高光颜色以及区域范围,之后使用法线贴图来实现类似各向异性的效果: ```c# //Matcap //v.2.0.6 : CameraRolling Stabilizer //Mirror Script Determination: if sign_Mirror = -1, determine "Inside the mirror". //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); //Invert if it's "inside the mirror". 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 = UnpackNormalScale(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); //If it is "inside the mirror", flip the UV left and right. if(_sign_Mirror < 0){ _Rot_MatCapUV_var.x = 1-_Rot_MatCapUV_var.x; }else{ _Rot_MatCapUV_var = _Rot_MatCapUV_var; } float4 _MatCap_Sampler_var = tex2Dlod(_MatCap_Sampler, float4(TRANSFORM_TEX(_Rot_MatCapUV_var, _MatCap_Sampler), 0.0, _BlurLevelMatcap)); float4 _Set_MatcapMask_var = tex2D(_Set_MatcapMask, TRANSFORM_TEX(Set_UV0, _Set_MatcapMask)); ``` ## UniversalToonBodyShadingGradeMap 合成公式: $$1-\frac{( HalfLambert - (Step-Feather))}{Feather}$$ ### 初始化数据 初始化表面数据、InputData与Varyings并且填充数据。 ### 灯光与环境光数据 ```c# //计算间接照明值,使用间接Diffuse乘以SurfaceDiffuse,间接Specular乘以SurfaceSpecular,最后两者叠加。 half3 envColor = GlobalIlluminationUTS(brdfData, inputData.bakedGI, surfaceData.occlusion, inputData.normalWS, inputData.viewDirectionWS); envColor *= 1.8f; //取得主光参数,direction、color、distanceAttenuation、shadowAttenuation、type UtsLight mainLight = GetMainUtsLightByID(i.mainLightID, i.posWorld.xyz, inputData.shadowCoord, i.positionCS); half3 mainLightColor = GetLightColor(mainLight); real shadowAttenuation = 1.0; # ifdef _MAIN_LIGHT_SHADOWS shadowAttenuation = mainLight.shadowAttenuation; # endif ``` ### 开启裁剪功能 ```c# float4 _ClippingMask_var = SAMPLE_TEXTURE2D(_ClippingMask, sampler_MainTex, 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); ``` ### 计算灯光方向与灯光颜色 ```c# 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)); //通过外部传入的_Offset_X_Axis_BLD、_Offset_Y_Axis_BLD、_Offset_Z_Axis_BLD来创建自定义灯光方向 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); //HLSL内置函数Any(),用于测试变量是否为非零值 float3 lightDirection = normalize(lerp(defaultLightDirection, mainLight.direction.xyz,any(mainLight.direction.xyz))); lightDirection = lerp(lightDirection, customLightDirection, _Is_BLD); //v.2.0.5: half3 originalLightColor = mainLightColor.rgb; float3 lightColor = lerp(max(defaultLightColor, originalLightColor), max(defaultLightColor, saturate(originalLightColor)), _Is_Filter_LightColor); ``` ### 计算1、2、3 ShadowMask与插值后的BaseColor值,之后合并到一起 ### 计算高光并且合并到一起 ### 计算天使环并且合并到一起 ### 计算Matcap并且合成到一起 ### 叠加自发光贴图结果 ### 灯光循环 ### 最终合成 ```c# finalColor = SATURATE_IF_SDR(finalColor) + (envLightColor*envLightIntensity*_GI_Intensity*smoothstep(1,0,envLightIntensity/2)) + emissive; finalColor += pointLightColor; ``` ## 完整代码 ```c# float4 fragShadingGradeMap(VertexOutput i, fixed facing : VFACE) : SV_TARGET { //计算世界法线值与摄像机朝向 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 = UnpackNormalScale(SAMPLE_TEXTURE2D(_NormalMap, sampler_MainTex, TRANSFORM_TEX(Set_UV0, _NormalMap)), _BumpScale); float3 normalLocal = _NormalMap_var.rgb; float3 normalDirection = normalize(mul( normalLocal, tangentTransform )); // Perturbed normals // todo. not necessary to calc gi factor in shadowcaster pass. //初始化表面数据、InputData与Varyings并且填充数据。 //input数据位于render-pipelines.universal,包含positionWS、normalWS、viewDirectionWS、shadowCoord、fogCoord、vertexLighting、bakedGI,Varyings input用来计算InputData。Vrayings位于LitForwardPass中 //inputData主要用来计算envColor(GI)、主灯光数据与AdditionalUtsLight数据 SurfaceData surfaceData; InitializeStandardLitSurfaceDataUTS(i.uv0, surfaceData); InputData inputData; Varyings input = (Varyings)0; // todo. it has to be cared more. UNITY_SETUP_INSTANCE_ID(input); UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); # ifdef LIGHTMAP_ON # else input.vertexSH = i.vertexSH; # endif input.uv = i.uv0; # if defined(_ADDITIONAL_LIGHTS_VERTEX) || (VERSION_LOWER(12, 0)) input.fogFactorAndVertexLight = i.fogFactorAndVertexLight; # else input.fogFactor = i.fogFactor; # endif # ifdef REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR input.shadowCoord = i.shadowCoord; # endif # ifdef REQUIRES_WORLD_SPACE_POS_INTERPOLATOR input.positionWS = i.posWorld.xyz; # endif # ifdef _NORMALMAP input.normalWS = half4(i.normalDir, viewDirection.x); // xyz: normal, w: viewDir.x input.tangentWS = half4(i.tangentDir, viewDirection.y); // xyz: tangent, w: viewDir.y # if (VERSION_LOWER(7, 5)) input.bitangentWS = half4(i.bitangentDir, viewDirection.z); // xyz: bitangent, w: viewDir.z #endif // # else input.normalWS = half3(i.normalDir); # if (VERSION_LOWER(12, 0)) input.viewDirWS = half3(viewDirection); # endif //(VERSION_LOWER(12, 0)) # endif //位于LitForwardPass中,其中SAMPLE_GI()采样LightMap或者SH。 InitializeInputData(input, surfaceData.normalTS, inputData); //位于Lighting中,使用前几个参数初始化最后一个brdfData形参 BRDFData brdfData; InitializeBRDFData(surfaceData.albedo, surfaceData.metallic, surfaceData.specular, surfaceData.smoothness, surfaceData.alpha, brdfData); //计算间接照明值,使用间接Diffuse乘以SurfaceDiffuse,间接Specular乘以SurfaceSpecular,最后两者叠加。 half3 envColor = GlobalIlluminationUTS(brdfData, inputData.bakedGI, surfaceData.occlusion, inputData.normalWS, inputData.viewDirectionWS); envColor *= 1.8f; //取得主光参数,direction、color、distanceAttenuation、shadowAttenuation、type UtsLight mainLight = GetMainUtsLightByID(i.mainLightID, i.posWorld.xyz, inputData.shadowCoord, i.positionCS); half3 mainLightColor = GetLightColor(mainLight); float4 _MainTex_var = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, TRANSFORM_TEX(Set_UV0, _MainTex)); //v.2.0.4 #ifdef _IS_TRANSCLIPPING_OFF // #elif _IS_TRANSCLIPPING_ON //开启裁剪功能 float4 _ClippingMask_var = SAMPLE_TEXTURE2D(_ClippingMask, sampler_MainTex, 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); #endif real shadowAttenuation = 1.0; # ifdef _MAIN_LIGHT_SHADOWS shadowAttenuation = mainLight.shadowAttenuation; # endif //v.2.0.4 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)); //通过外部传入的_Offset_X_Axis_BLD、_Offset_Y_Axis_BLD、_Offset_Z_Axis_BLD来创建自定义灯光方向 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); //HLSL内置函数Any(),用于测试变量是否为非零值 float3 lightDirection = normalize(lerp(defaultLightDirection, mainLight.direction.xyz,any(mainLight.direction.xyz))); lightDirection = lerp(lightDirection, customLightDirection, _Is_BLD); //v.2.0.5: half3 originalLightColor = mainLightColor.rgb; float3 lightColor = lerp(max(defaultLightColor, originalLightColor), max(defaultLightColor, saturate(originalLightColor)), _Is_Filter_LightColor); ////// Lighting: //计算View与主Light的半向量 float3 halfDirection = normalize(viewDirection+lightDirection); //v.2.0.5 _Color = _BaseColor; #ifdef _IS_PASS_FWDBASE //取得设置的LightColor、BaseColor(设置的灯光颜色or主贴图采样结果)、1st_ShadeMap_var,最后计算_Is_LightColor_1st_Shade_var与半兰伯特值。 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(SAMPLE_TEXTURE2D(_1st_ShadeMap,sampler_MainTex, TRANSFORM_TEX(Set_UV0, _1st_ShadeMap)),_MainTex_var,_Use_BaseAs1st); //_1st_ShadeMap_var为确定区域,颜色为设置的颜色。_1st_ShadeMap_var.rgb*_1st_ShadeColor.rgb*Set_LightColor,可设置为不受LightColor影响。 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 //v.2.0.6 float4 _ShadingGradeMap_var = tex2Dlod(_ShadingGradeMap, float4(TRANSFORM_TEX(Set_UV0, _ShadingGradeMap), 0.0, _BlurLevelSGM)); //the value of shadowAttenuation is darker than legacy and it cuases noise in terminaters. #if !defined (UTS_USE_RAYTRACING_SHADOW) shadowAttenuation *= 2.0f; shadowAttenuation = saturate(shadowAttenuation); #endif //v.2.0.6 //Minmimum value is same as the Minimum Feather's value with the Minimum Step's value as threshold. //_Tweak_SystemShadowsLevel控制 Unity 的系统阴影级别。默认为 0,级别可调整为 ±0.5。 //使用_Tweak_SystemShadowsLevel来偏移ShadingGradeMap中定义的阴影范围 //最后计算ShadowMask:Set_ShadingGrade=_HalfLambert_var*saturate(_SystemShadowsLevel_var)的值。 float _SystemShadowsLevel_var = (shadowAttenuation *0.5)+0.5+_Tweak_SystemShadowsLevel > 0.001 ? (shadowAttenuation *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_ShadingGrade = saturate(_ShadingGradeMapLevel_var)*lerp( _HalfLambert_var, (_HalfLambert_var*saturate(1.0+_Tweak_SystemShadowsLevel)), _Set_SystemShadowsToBase ); //计算1、2、3 ShadowMask与插值后的BaseColor值,之后合并到一起。 //lerp( (_2nd_ShadeMap_var.rgb*_2nd_ShadeColor.rgb), ((_2nd_ShadeMap_var.rgb*_2nd_ShadeColor.rgb)*Set_LightColor), _Is_LightColor_2nd_Shade ) //lerp(_Is_LightColor_1st_Shade_var,上一次插值结果,Set_ShadeShadowMask) //lerp(_BaseColor_var,上一次插值结果,Set_FinalShadowMask) //合成方式为: 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(SAMPLE_TEXTURE2D(_2nd_ShadeMap,sampler_MainTex, 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); //采样高光Mask float4 _Set_HighColorMask_var = tex2D(_Set_HighColorMask, TRANSFORM_TEX(Set_UV0, _Set_HighColorMask)); //半影值计算高光Mask(半兰伯特模型) float _Specular_var = 0.5*dot(halfDirection,lerp( i.normalDir, normalDirection, _Is_NormalMapToHighColor ))+0.5; // Specular //Step(a,x) => x>=a ? 1 : 0,计算高光Mask float _TweakHighColorMask_var = (saturate((_Set_HighColorMask_var.g+_Tweak_HighColorMaskLevel))*lerp( (1.0 - step(_Specular_var,(1.0 - pow(abs(_HighColor_Power),5)))), pow(abs(_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_IF_SDR((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 )); //开始计算边缘光 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 = abs(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_IF_SDR((_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 //v.2.0.6 : CameraRolling Stabilizer //Mirror Script Determination: if sign_Mirror = -1, determine "Inside the mirror". //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); //Invert if it's "inside the mirror". 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 = UnpackNormalScale(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); //If it is "inside the mirror", flip the UV left and right. if(_sign_Mirror < 0){ _Rot_MatCapUV_var.x = 1-_Rot_MatCapUV_var.x; }else{ _Rot_MatCapUV_var = _Rot_MatCapUV_var; } float4 _MatCap_Sampler_var = tex2Dlod(_MatCap_Sampler, float4(TRANSFORM_TEX(_Rot_MatCapUV_var, _MatCap_Sampler), 0.0, _BlurLevelMatcap)); float4 _Set_MatcapMask_var = tex2D(_Set_MatcapMask, TRANSFORM_TEX(Set_UV0, _Set_MatcapMask)); // //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 ); // //v.2.0.6 //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, (1 - (Set_FinalShadowMask)*(1 - _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); //v.2.0.4 #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 //计算UV,将表面法线转换到视角坐标,将(-1,1)=》(0,1)之后,按照摄像机的 -(_Camera_Dir*_Camera_Roll)旋转坐标后,采样贴图 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 //v.2.0.7 #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; #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 // //v.2.0.6: GI_Intensity with Intensity Multiplier Filter float3 envLightColor = envColor.rgb; float envLightIntensity = 0.299*envLightColor.r + 0.587*envLightColor.g + 0.114*envLightColor.b <1 ? (0.299*envLightColor.r + 0.587*envLightColor.g + 0.114*envLightColor.b) : 1; float3 pointLightColor = 0; #ifdef _ADDITIONAL_LIGHTS int pixelLightCount = GetAdditionalLightsCount(); // determine main light inorder to apply light culling properly // when the loop counter start from negative value, MAINLIGHT_IS_MAINLIGHT = -1, some compiler doesn't work well. // for (int iLight = MAINLIGHT_IS_MAINLIGHT; iLight < pixelLightCount ; ++iLight) for (int loopCounter = 0; loopCounter < pixelLightCount - MAINLIGHT_IS_MAINLIGHT; ++loopCounter) { int iLight = loopCounter + MAINLIGHT_IS_MAINLIGHT; if (iLight != i.mainLightID) { float notDirectional = 1.0f; //_WorldSpaceLightPos0.w of the legacy code. UtsLight additionalLight = GetUrpMainUtsLight(0,0); if (iLight != MAINLIGHT_IS_MAINLIGHT) { additionalLight = GetAdditionalUtsLight(iLight, inputData.positionWS, i.positionCS); } half3 additionalLightColor = GetLightColor(additionalLight); float3 lightDirection = additionalLight.direction; //v.2.0.5: float3 addPassLightColor = (0.5*dot(lerp(i.normalDir, normalDirection, _Is_NormalMapToBase), lightDirection) + 0.5) * additionalLightColor.rgb; float pureIntencity = max(0.001, (0.299*additionalLightColor.r + 0.587*additionalLightColor.g + 0.114*additionalLightColor.b)); float3 lightColor = max(0, lerp(addPassLightColor, lerp(0, min(addPassLightColor, addPassLightColor / pureIntencity), notDirectional), _Is_Filter_LightColor)); float3 halfDirection = normalize(viewDirection + lightDirection); // has to be recalced here. //v.2.0.5: _1st_ShadeColor_Step = saturate(_1st_ShadeColor_Step + _StepOffset); _2nd_ShadeColor_Step = saturate(_2nd_ShadeColor_Step + _StepOffset); // //v.2.0.5: If Added lights is directional, set 0 as _LightIntensity float _LightIntensity = lerp(0, (0.299*additionalLightColor.r + 0.587*additionalLightColor.g + 0.114*additionalLightColor.b), notDirectional); //v.2.0.5: Filtering the high intensity zone of PointLights //计算灯光颜色 float3 Set_LightColor = lerp(lightColor, lerp(lightColor, min(lightColor, additionalLightColor.rgb*_1st_ShadeColor_Step), notDirectional), _Is_Filter_HiCutPointLightColor); //计算BaseColor与,采样_1st_ShadeMap_var与_2nd_ShadeMap_varMask。之后计算Set_FinalShadowMask与Set_ShadeShadowMask,用于一次灯光循环的插值。 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(SAMPLE_TEXTURE2D(_1st_ShadeMap, sampler_MainTex,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(SAMPLE_TEXTURE2D(_2nd_ShadeMap, sampler_MainTex,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) - (_1st_ShadeColor_Step - _1st_ShadeColor_Feather)) * ((1.0 - _Set_1st_ShadePosition_var.rgb).r - 1.0)) / (_1st_ShadeColor_Step - (_1st_ShadeColor_Step - _1st_ShadeColor_Feather)))); //SGM //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_ShadingGrade = saturate(_ShadingGradeMapLevel_var)*lerp(_HalfLambert_var, (_HalfLambert_var*saturate(1.0 + _Tweak_SystemShadowsLevel)), _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)))); 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 //SGM // //Composition: 3 Basic Colors as finalColor // float3 finalColor = // lerp( // Set_BaseColor, // lerp( // Set_1st_ShadeColor, // Set_2nd_ShadeColor, // saturate( // (1.0 + ((_HalfLambert_var - (_2nd_ShadeColor_Step - _2nd_Shades_Feather)) * ((1.0 - _Set_2nd_ShadePosition_var.rgb).r - 1.0)) / (_2nd_ShadeColor_Step - (_2nd_ShadeColor_Step - _2nd_Shades_Feather)))) // ), // Set_FinalShadowMask); // Final Color //Composition: 3 Basic Colors as finalColor float3 finalColor = lerp( Set_BaseColor, //_BaseColor_var*(Set_LightColor*1.5), lerp( Set_1st_ShadeColor, Set_2nd_ShadeColor, Set_ShadeShadowMask ), Set_FinalShadowMask); //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(abs(_HighColor_Power), 5)))), pow(abs(_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_IF_SDR(finalColor); pointLightColor += finalColor; // pointLightColor += lightColor; } } #endif // _ADDITIONAL_LIGHTS // //Final Composition finalColor = SATURATE_IF_SDR(finalColor) + (envLightColor*envLightIntensity*_GI_Intensity*smoothstep(1,0,envLightIntensity/2)) + emissive; finalColor += pointLightColor; #endif //v.2.0.4 #ifdef _IS_TRANSCLIPPING_OFF fixed4 finalRGBA = fixed4(finalColor,1); #elif _IS_TRANSCLIPPING_ON float Set_Opacity = SATURATE_IF_SDR((_Inverse_Clipping_var+_Tweak_transparency)); fixed4 finalRGBA = fixed4(finalColor,Set_Opacity); #endif return finalRGBA; } ``` ```c++ else if (stencilMode == _UTS_StencilMode.StencilMask) { material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.AlphaTest - 1; } else if (stencilMode == _UTS_StencilMode.StencilOut) { material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.AlphaTest; } void ApplyStencilMode(Material material) { _UTS_StencilMode mode = (_UTS_StencilMode)(material.GetInt(ShaderPropStencilMode)); switch (mode) { case _UTS_StencilMode.Off: // material.SetInt(ShaderPropStencilNo,0); material.SetInt(ShaderPropStencilComp, (int)_StencilCompFunction.Disabled); material.SetInt(ShaderPropStencilOpPass, (int)_StencilOperation.Keep); material.SetInt(ShaderPropStencilOpFail, (int)_StencilOperation.Keep); break; case _UTS_StencilMode.StencilMask: // material.SetInt(ShaderPropStencilNo,0); material.SetInt(ShaderPropStencilComp, (int)_StencilCompFunction.Always); material.SetInt(ShaderPropStencilOpPass, (int)_StencilOperation.Replace); material.SetInt(ShaderPropStencilOpFail, (int)_StencilOperation.Replace); break; case _UTS_StencilMode.StencilOut: // material.SetInt(ShaderPropStencilNo,0); material.SetInt(ShaderPropStencilComp, (int)_StencilCompFunction.NotEqual); material.SetInt(ShaderPropStencilOpPass, (int)_StencilOperation.Keep); material.SetInt(ShaderPropStencilOpFail, (int)_StencilOperation.Keep); break; } } ``` ![](https://github.com/unity3d-jp/UnityChanToonShaderVer2_Project/raw/release/urp/2.3.0/Documentation~/Images_jpg/URP_image036.jpg)