找回密码
 立即注册
查看: 362|回复: 0

【unity】卡通渲染--unity-chan解析1(光照系列)

[复制链接]
发表于 2023-1-13 10:16 | 显示全部楼层 |阅读模式
【前言】

自学制作的笔记,删除很多多余的代码,可能有所小错误(大体效果对过,发现基本没影响)



随心截个图

因为二次元渲染感觉挺火的,所以还是有必要对其有一定的了解,所以把unity-chan的工程下了下来,看看官网的相关光照代码,并且能够对其的数学原理能够有一定的了解,方便未来如果真的需要动到到二次元,或者需要对二次元相关游戏进行画面修改或者统一能够有一定的积累。
当然肯定没全啃完,我删了很多无用或者暂时没使用的代码:把工程shader给修改了一下,把大多数默认为0或者默认为1,以及还有AR,vrc等设置删除,并且移除了关于matcap还有rimlight以及环境光,因为这些在demo中并没有使用到或者效果不明显所以暂时移除掉,然后把整体代码降低大概一半的量,方便进行阅读与解析使用。
提前说个结论:在unity-chan的代码整体阅读下来之后,能够总结它使用的是半兰伯特模型的光照,接着汇入阴影贴图来定义阴影色,围绕阴影色和半兰伯特模型之间进行光照阴影的插值,还有第二阴影色和第一阴影色进行光照插值来实现整体的效果。Lit.shader也用到一些,但主要用来制作(全黑色)的环境光哈哈。算法偏美术trick居多,以及还有大量使用lerp来进行不同光照区分定义,看上去就像是一边调试一边写的shader,连续看了半天多,差点儿把脑子看晕了,幸亏写了注释、、
参考的demo:
当然二次元有很多做法,有NPR,有手绘,有很多不同的方案,所以就慢慢来呗,饭要一口口吃。后续会尝试把这个shader搬运过去到原神模型,看看能不能弄一个好看的效果,然后再研究雕刻,加入rim或者matcap之前移除的玩意儿。
对了,二次元灵魂在建模与贴图制作,只会写shader的TA不是一个好的二次元TA。
【正文】

本文将会围绕主要光照展开进行介绍,后续将会尝试自制一个shader作为本人二次元实践用的shader,以方便后续的渲染测试使用,源代码为:UniversalToonBodyShadingGradeMap.hlsl。
在渲染光照着色器前面代码比较简单,基本都是数据准备,大多数用到lit.shader,我们在这边便简单过一下即可:
数据准备:

准备法线:(在Demo中几乎没有法线,大多数顶点法线搞出来的效果)



准备法线,TBN矩阵转换以及法线贴图采样

但法线可以看到整体法线是偏平的,和一般写实法线区别比较大,为了与光照的效果进行相关同步使用:



颜色区分鲜明的法线

准备SurfaceData,InputData,Varyings,主要为了初始化相关数据,以及计算环境光使用(结果给我算出个全黑色),还有计算shadowcoord用于汇入光照中去正确采样光照贴图使用:



初始化各种数据

贴图采样与传递基础光照信息:

完成完一堆(看上去好多数据都可以删掉)的数据准备之后,我们开始进行贴图采样与光照的初步运算,首先是采样主贴图得到基础颜色:当然有例如头发皮肤等颜色是通过颜色通道开放来定义。



贴图颜色定义(经典KTV粉不是bug,是真的粉而已)

同时也将阴影结果传递下来进行保存:



主光源阴影保存

完成这一步之后,unity-chan对于光照运算加了个默认的摄像机上前的视角中值作为默认值,如果没有获取到主光源则使用default默认光来进行呈现,如果有获取到主光源方向,则根据用户定义是否需要使用自定义光源来进行处理:(感觉后续如果我自己弄的话,会继续删一些内容,例如把自定义光照删除,以及默认灰度删除开放出来等等)



光照算法效果



纯纯白色的光照

完成这一步之后,我们需要定义半程向量,这将在我们的高光运算中会使用到,接着将基础色传递进来:



半程向量定义与基础色

基础两层颜色与半兰伯特结果:

在这里我单列出来,因为后面大量的计算都围绕该展开,而且特别trick,比较偏画画而不是物理计算,首先是把我们之前计算的基础色传递进来,并且与光照进行乘积得到我们的第一层色:



第一层基础色效果

接着,我们需要采样第二张maintex作为我们的第二层基础色,也就是第一层阴影色:



采样第二张基础色贴图与预先定义好的光照进行乘积混合

完成这两步之后,我们在这里计算出半兰伯特光照结果,为了和后续阴影混合做准备使用:



半兰伯特模型计算光照效果

贴图阴影采样:

主要准备一样基础阴影贴图,为了后续进行阴影调整使用:



手绘阴影,为了后续阴影叠加使用做准备

在这边有对手绘阴影做了个优化,主要判断是否是超过阈值的白色,如果超出阈值则使用1来作为阴影结果:



手绘阴影优化



超出阈值的阴影设置为1

光照阴影优化:




代码备注

接着对阴影效果进行一定的美学处理,主要方案是通过对阴影贴图结果进行*2saturate之后,*0.5然后再校色回来,主要作用能够压平阴影,让阴影能够更加柔滑一些:



原阴影与压平阴影的效果

结合材质的参数,可以将不同部位的阴影进行相关调整:



材质参数调整阴影效果

完成阴影准备之后,我们把光照处理后的阴影结果、半兰伯特阴影结果,以及手绘贴图调整阴影结果进行乘积叠加,得到细节度丰富的阴影结果:



细节度丰富的阴影细节结果

完成这一步之后,由于是二次元渲染,所以我们需要对阴影进行锐化操作,在这里有很多方法,有数学推导,也有通过采样ramp贴图实现。
在这里的demo是通过数学推导来实现:这里trick的原理是通过step来调整整体阴影曲线,通过简单的加减来实现左右曲线平移,而Feather通过除法来放大整体阴影细节,也就是把整体曲线往上拉,通过saturate来限定,来达到阴影软硬效果,在这里我用曲线来解释:(官方的算法被我改了一下,结果没有变化)



代码图



PS演示效果


step和Feather区别
https://www.zhihu.com/video/1596639231786500096
在阴影原生规定中,白色为亮色,黑色为暗色,但由于在计算过程中用了《1-》导致整体阴影发生翻转,所以我们需要同步更近,将规则改为黑色为亮色,白色为暗色:



阴影对应颜色变化

完成完这一步之后,为了加深细节,使用第二层阴影作为阴影色1-2的变换,也就是在上文,我们使用的是basecolor和阴影色1作为两者的对比插值,那么在这里便是阴影色1和阴影色2的插值,当然在这里主要运用在皮肤上面:



代码注释



第二层阴影色的效果,当然有材质作为区分是否使用第二层阴影色,如果不是用则为第一层阴影色

和上文的基色和第一层阴影混合相同,在这里也是同样方法进行混合,通过step来进行整体阴影调整,通过feather与saturate配合对阴影进行锐化:



同样原理,step调整亮暗,feature调整软硬

完成这一步之后,我们进行混合lerp,来把第二层阴影叠加上去:来这里使用两个lerp,一个lerp用于进行第一层和第二层阴影过渡使用,一个lerp用于基础色和阴影过渡结果进行混合使用:



第一层和第二层阴影色混合效果



基础色和阴影色混合

高光效果:个人感觉该官方工程高光可能不太好,因为高光最终计算下来就一小块有作用

在高光制作中,主要通过高光遮罩来限制对应的高光范围,以及半兰伯特的高光来实现整体的高光效果,首先是高光遮罩与半兰伯特的高光(NOH),这两者比较简单,呈现效果图即可:



半兰伯特与高光遮罩

接着在高光运算中,主要采用两个方式,一个方式是通过半兰伯特高光进行step抠图得到高光位置,一个方法是通过默认的pow函数来进行高光制作:



两种高光模式,根据材质进行lerp区分(toggle的lerp)

将其叠加到高光遮罩中得到如下的效果:



叠加高光遮罩效果

完成之后,由于需要呈现高光,所以我们在这里汇入高光的颜色贴图(调侃一下,这里竟然是黑白遮罩,应该还是得要绘制一下,等后面自己写shader注意一下)



汇入高光颜色贴图

接着通过lerp进行运算,设置是否汇入光照并且汇入相关高光遮罩与高光颜色混合,得到如下的效果:



进行lerp过渡去混合高光



个人把高光贴图换成全1的效果,感觉还是得要做一下高光图会好看一些

最后便是需要混合高光结果,首先由于是高光,所以在之前我们得到高光的遮罩,我们需要进行互补操作,主要通过lerp来定义是否使用全漫反射加和,还是互补加和模式:



漫反射lerp代码对应的三个效果



漫反射结果(感觉遮罩好像也没起到作用)

接着我们需要进行高光处理,主要有被阴影遮挡的高光与没被阴影遮挡的高光区分,该参数通过材质来进行区分这两者:



通过材质去区分高光效果



得到最终的高光效果

自发光:

这一部分简单,主要加入自发光贴图、遮罩和颜色修饰即可:



采样自发光进行颜色混合即可

平行光结果:

我们把自发光与之前算好的高光漫反射相加,可以得到平行光结果:



平行光效果图

点光源简介:

但我们会发现角色整体的润泽度比较低,感觉皮肤不够红,所以在这里我们可以通过加入一盏红色点光源来进行补光,而补光的具体光照算法和上面相差并不大,阴影色通过lerp来进行分层,高光遮罩算法并没有任何变化。
点光源数据初始化:

首先我们需要准备好点光源,通过GetLightColor汇入相关点光源来实现,而点光源获取和URP的算法类似,也是通过汇入世界空间坐标重新计算衰减,输出到颜色上面:



获取光照颜色进行半兰伯特计算,同时准备光照颜色、光强和半程向量

在数据准备之余,还对之前的step(阴影整体亮暗)参数进行调整,专门给点光源定制使用:



调整step函数

点光源阴影色准备:

完成这一步之后,接着的阴影色处理和上文基本差不了太多,区别在于之前用的是主光源阴影做区分,但我们知道点光源阴影是不存在的,所以需要进行另外参数的定义,所以我们引入光强来进行阴影色区分:



光强

和上文一样,准备基础色,与光照叠加得到基色,在这里用了个trick,通过step来进行基色的明暗调整:



step校色效果



基色效果

接着和上文一样,我们准备第一层阴影图,主要通过颜色校正与阴影图乘积,接着和光照乘积得到第一层阴影图:



第一层阴影图效果

同样方法,我们准备第二层阴影图:



第二层阴影图

点光源光照阴影优化:

完成阴影图与基色准备之后,和上文基本同样的方法,首先汇入事前绘制好的阴影贴图作为阴影校色遮罩,同样也进行阈值判断输出:



手绘阴影效果

完成手绘阴影采样与阈值处理在之后,接着乘积半兰伯特结果与材质校色可以得到如下效果:



阴影图效果

接着根据阴影图,和平行光一样的方法,通过step调整颜色整体曲线,通过feather调整整体颜色软硬,接着进行《1-》来得到最终的反转阴影图:(为了方便大家查找,我直接CV在这里了)



PS演示效果



效果演示视频



点光源的过渡遮罩效果

最终在颜色中,我们记得由于阴影是反转过的,所以0对应亮色,1对应暗色,我们将其lerp输出:



进行lerp输出阴影色与基色混合结果

点光源高光效果:

高光计算方法和平行光基本没多大差别,只是最后全用加和方式去处理高光,在这边便简要赘述一下:首先是处理高光遮罩与高光半兰伯特结果:



半兰伯特高光与高光遮罩

接着根据不同高光的选择,去制定高光的方案,是通过半兰伯特的step抠图显示,还是通过指数放缩方式呈现:



高光呈现逻辑



高光遮罩效果

完成这一步之后,我们需要加入高光颜色,通过采样高光贴图,结合材质的参数混合达到高光贴图颜色呈现效果



高光颜色贴图采样与光照颜色混合

接着与之前的高光遮罩进行乘积,得到最终的高光结果:



最终的高光结果

结合阴影处理可以得到如下的效果:



阴影方法处理

完成之后,也是同样的方法进行高光汇入,在这边由于参数设置,导致高光被取消掉,点光源是没有高光的:



材质没有高光

于是我们可以得到点光源的效果:

点光源效果
https://www.zhihu.com/video/1596675552080789504
接着整合到一起,得到最终的效果:



颜色结果进行加和


最终效果
https://www.zhihu.com/video/1596675988011847680
【所遇到的缺陷与未来计划】
在研究该shader的时候,主要运用半兰伯特光照,而且需要一定的建模上色能力来对阴影图进行绘制,偏手绘比较多,可能需要比较多的美术量,但整体美术自由度会比较高,因为阴影是美术来决定的。
但由于该demo并没有放入matcap与rimlight的效果,本人在后续会尝试将该shader使用在原神上用,并且手绘对应的光照贴图跑一下该流程,并且接入matcap和rimlight看看能不能再提升一下整体的效果。
麻了,原本上班事情做完了想稍微研究一下,结果一口气研究了11个小时才把整体渲染流程与代码理清楚,并写下一篇笔记作为留存。
【代码修改】(如果想替换shader,请替换该路径下的文件:Packages\com.unity.universaltoonshader.urp\Runtime\Shaders\)
UniversalToonBodyShadingGradeMap.hlsl
//UTS2/UniversalToon
//v.2.2.0
//nobuyuki@unity3d.com
//toshiyuki@unity3d.com (Univerasl RP/HDRP)
//https://github.com/unity3d-jp/UnityChanToonShaderVer2_Project
//(C)Unity Technologies Japan/UCL
//


float4 fragShadingGradeMap(VertexOutput i, fixed facing : VFACE) : SV_TARGET {

    i.normalDir = normalize(i.normalDir);//获取法线方向
    float3x3 tangentTransform = float3x3(i.tangentDir, i.bitangentDir, i.normalDir);//制作法线TBN矩阵
    float3 viewDirection = normalize(_WorldSpaceCameraPos.xyz - i.posWorld.xyz);//视角方向
    float2 Set_UV0 = i.uv0;//UV0
    //v.2.0.6
    float3 _NormalMap_var = UnpackNormalScale(tex2D(_NormalMap, TRANSFORM_TEX(Set_UV0, _NormalMap)), _BumpScale);//法线向量采样
    float3 normalLocal = _NormalMap_var.rgb;//法线
    float3 normalDirection = normalize(mul(normalLocal, tangentTransform)); // Perturbed normals TBN矩阵计算正确法线

    // todo. not necessary to calc gi factor in  shadowcaster pass.
    SurfaceData surfaceData;
    InitializeStandardLitSurfaceDataUTS(i.uv0, surfaceData);//surfaceData.albedo基础色,其余均为初始黑色

    InputData inputData;//初始化input
    Varyings  input;//初始化input

    // todo.  it has to be cared more.
    UNITY_SETUP_INSTANCE_ID(input);//初始化input
    UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);//初始化input
    input.vertexSH = i.vertexSH;//SH并没有出现
    input.uv = i.uv0;//UV传递
    input.fogFactorAndVertexLight = i.fogFactorAndVertexLight;//顶点光和雾效
    #ifdef REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR
        input.shadowCoord = i.shadowCoord;//传递shadowCoord
    #endif

    #ifdef REQUIRES_WORLD_SPACE_POS_INTERPOLATOR
        input.positionWS = i.posWorld.xyz;//传递世界坐标
    #endif
    #ifdef _NORMALMAP //组合TBN的矩阵
        input.normalWS = half4(i.normalDir, viewDirection.x);      // xyz: normal, w: viewDir.x
        input.tangentWS = half4(i.tangentDir, viewDirection.y);        // xyz: tangent, w: viewDir.y
        input.bitangentWS = half4(i.bitangentDir, viewDirection.z);    // xyz: bitangent, w: viewDir.z
    #else //世界空间的法线和视角方向
        input.normalWS = half3(i.normalDir);
        input.viewDirWS = half3(viewDirection);
    #endif
    InitializeInputData(input, surfaceData.normalTS, inputData);//初始化汇入的data,主要计算出input的法线、视角方向、雾效、GI等信息,和unity没差别

    BRDFData brdfData;
    InitializeBRDFData(surfaceData.albedo,
    surfaceData.metallic,
    surfaceData.specular,
    surfaceData.smoothness,
    surfaceData.alpha, brdfData);//初始化BRDF信息,主要用来汇入相关的光照运算使用
   
    UtsLight mainLight = GetMainUtsLightByID(i.mainLightID, i.posWorld.xyz, inputData.shadowCoord, i.positionCS);
    half3 mainLightColor = GetLightColor(mainLight);//获取主光源信息

    float4 _MainTex_var = tex2D(_MainTex, TRANSFORM_TEX(Set_UV0, _MainTex));//采样主贴图算法
   
    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));//这里的SH为0,返回基础的无光照灰色
    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);//bulidin的光照方向
    float3 lightDirection = normalize(lerp(defaultLightDirection, mainLight.direction.xyz, any(mainLight.direction.xyz)));//any判断主光源是否有存在,如果没有则汇入默认光照方向,也就是摄像机中值方向
    lightDirection = lerp(lightDirection, customLightDirection, _Is_BLD);//如果是bulidin则使用后者
    //v.2.0.5:

    half3 originalLightColor = mainLightColor.rgb;

    float3 lightColor = lerp(max(defaultLightColor, originalLightColor), max(defaultLightColor, saturate(originalLightColor)), _Is_Filter_LightColor);//光照是否归一化,如果是VRC则需要开启,得到的光照有个基础的灰色基色


    ////// Lighting:
    float3 halfDirection = normalize(viewDirection + lightDirection);//半程向量
    //v.2.0.5
    _Color = _BaseColor;//基础色传递

    #ifdef _IS_PASS_FWDBASE
        float3 Set_LightColor = lightColor.rgb;//光照计算结果传递
        float3 Set_BaseColor = (_MainTex_var.rgb * _BaseColor.rgb) * Set_LightColor;//根据是否是光照颜色来进行判断光照的结果,看上去是记得和主贴图混合而已

        //v.2.0.5
        float4 _1st_ShadeMap_var = lerp(tex2D(_1st_ShadeMap, TRANSFORM_TEX(Set_UV0, _1st_ShadeMap)), _MainTex_var, _Use_BaseAs1st);//采样第一层shadermap,或者用maintex,基础色为白色
        float3 _Is_LightColor_1st_Shade_var = (_1st_ShadeMap_var.rgb * _1st_ShadeColor.rgb) * Set_LightColor;//获得第一层阴影下的光照情况,主要通过美学进行校色,选择是否加入光照调整
        
        float _HalfLambert_var = 0.5 * dot(i.normalDir, 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));//获得阴影贴图的光照情况
        //the value of shadowAttenuation is darker than legacy and it cuases noise in terminaters.
        #if !defined(UTS_USE_RAYTRACING_SHADOW)
            shadowAttenuation *= 2.0f;//阴影*2,感觉是美学优化使用
            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.
        float _SystemShadowsLevel_var = (shadowAttenuation * 0.5) + 0.5 + _Tweak_SystemShadowsLevel;//阴影计算为saturate(2s)*0.5+0.5,以增强阴影的对比度
        float _ShadingGradeMapLevel_var = _ShadingGradeMap_var.r < 0.95 ? _ShadingGradeMap_var.r + _Tweak_ShadingGradeMapLevel : 1;//阴影校色,主要调黑白问题


        float Set_ShadingGrade = saturate(_ShadingGradeMapLevel_var) * _HalfLambert_var * saturate(_SystemShadowsLevel_var);//半兰伯特加入阴影计算,叠加光照阴影以及手绘阴影

        //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)) / _1st_ShadeColor_Feather)); // Base and 1st Shade Mask 返回反向阴影遮罩,并且接入相应的锐化操作,以及移动平衡线
        float3 _BaseColor_var = lerp(Set_BaseColor, _Is_LightColor_1st_Shade_var, Set_FinalShadowMask);//由于阴影反向,所以1为阴影侧,0为光照侧

        //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))) /  _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, ((_2nd_ShadeMap_var.rgb * _2nd_ShadeColor.rgb) * Set_LightColor), Set_ShadeShadowMask), Set_FinalShadowMask);//第二层阴影计算结果和光照侧进行计算,接着与第一层的阴影进行lerp运算

        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; // 半兰伯特的高光
        float _TweakHighColorMask_var = saturate(_Set_HighColorMask_var.g)* lerp((1.0 - step(_Specular_var, (1.0 - pow(_HighColor_Power, 5)))), pow(_Specular_var, exp2(lerp(11, 1, _HighColor_Power))), _Is_SpecularToHighColor);//设置高光遮罩用,主要通过皮肤和其他的区别,皮肤用后者的pow混合效果,衣服则使用前者的step混合效果,主要进行两者的混合处理达到效果,接着加入高光遮罩进行抠图
        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;//相同的lerp方法,只是在这里加入高光自定义颜色以及高光颜色校正,还有之前所计算的遮罩结果
        //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);//整合高光颜色结果,身体用lerp0,其余用lerp1、、、、、在第一个lerp全部都是基础色、、、、、在第二个lerp主要接入阴影和高光颜色的校正来实现阴影遮挡高光的效果

        float3 finalColor = Set_HighColor;// Final Composition before Emissive

        //v.2.0.7
        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;//采样自发光贴图并且汇入遮罩,遮罩为叠加色
        //
        //v.2.0.6: GI_Intensity with Intensity Multiplier Filter

        //点光源处理
        float3 pointLightColor = 0;
        
        #ifdef _ADDITIONAL_LIGHTS
            int pixelLightCount = GetAdditionalLightsCount();//获取点光源数目

            #if 1 // determine main light inorder to apply light culling properly
                for (int iLight = -1; iLight < pixelLightCount; ++iLight) {
                    int iLight = 0;
                    if (iLight != i.mainLightID) {
                        UtsLight additionalLight = GetMainUtsLight(0, 0);
                        if (iLight != -1) {
                            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, addPassLightColor);//光照颜色
                        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 = (0.299 * additionalLightColor.r + 0.587 * additionalLightColor.g + 0.114 * additionalLightColor.b);//点光源光照强度
                        //v.2.0.5: Filtering the high intensity zone of PointLights
                        float3 Set_LightColor = min(lightColor, additionalLightColor.rgb * _1st_ShadeColor_Step);//设置光照颜色,和阴影色取最小值来呈现
                        //
                        float3 Set_BaseColor = (_BaseColor.rgb * _MainTex_var.rgb) * Set_LightColor;//主贴图颜色校正与光照混合
                        //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 = (_1st_ShadeColor.rgb * _1st_ShadeMap_var.rgb) * Set_LightColor;//获得第一层阴影下的光照情况,主要通过美学进行校色,选择是否加入光照调整
         
                        //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 = (_2nd_ShadeColor.rgb * _2nd_ShadeMap_var.rgb) * Set_LightColor;//获得第一层阴影下的光照情况,主要通过美学进行校色,选择是否加入光照调整
                        float _HalfLambert_var = 0.5 * dot(lerp(i.normalDir, normalDirection, _Is_NormalMapToBase), lightDirection) + 0.5;//半兰伯特计算

                        //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) * _HalfLambert_var * saturate(1.0 + _Tweak_SystemShadowsLevel);//半兰伯特加入阴影计算,叠加光照阴影以及手绘阴影

                        //
                        float Set_FinalShadowMask = saturate(1.0 - (Set_ShadingGrade - (_1st_ShadeColor_Step - _1st_ShadeColor_Feather)) / _1st_ShadeColor_Feather);//返回反向阴影遮罩,并且接入相应的锐化操作,以及移动平衡线
                        float Set_ShadeShadowMask = saturate((1.0 - ((Set_ShadingGrade - (_2nd_ShadeColor_Step - _2nd_ShadeColor_Feather))) /  _2nd_ShadeColor_Feather)); // 1st and 2nd Shades Mask 返回反向阴影遮罩,并且接入相应的锐化操作,以及移动平衡线


                        //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
                            ),//进行1-2颜色混合
                            Set_FinalShadowMask);//进行阴影色和主颜色lerp过渡
                            //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) * lerp((1.0 - step(_Specular_var, (1.0 - pow(_HighColor_Power, 5)))), pow(_Specular_var, exp2(lerp(11, 1, _HighColor_Power))), _Is_SpecularToHighColor);//设置高光遮罩用,主要通过皮肤和其他的区别,皮肤用后者的pow混合效果,衣服则使用前者的step混合效果,主要进行两者的混合处理达到效果,接着加入高光遮罩进行抠图
                            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;//相同的lerp方法,只是在这里加入高光自定义颜色以及高光颜色校正,还有之前所计算的遮罩结果

                            finalColor = finalColor + lerp(lerp(_HighColor_var, (_HighColor_var * ((1.0 - Set_FinalShadowMask) + (Set_FinalShadowMask * _TweakHighColorOnShadow))), _Is_UseTweakHighColorOnShadow), float3(0, 0, 0), _Is_Filter_HiCutPointLightColor);//整合高光颜色结果,身体用lerp0,其余用lerp1、、、、、在第一个lerp全部都是基础色、、、、、在第二个lerp主要接入阴影和高光颜色的校正来实现阴影遮挡高光的效果
                            //

                            finalColor = saturate(finalColor);//归一化处理

                            pointLightColor += finalColor;//点光源结果汇入
                            //        pointLightColor += lightColor;

                        }
                    }
            #endif // determine main light inorder to apply light culling properly
        #endif // _ADDITIONAL_LIGHTS

        //
        //Final Composition


        finalColor = saturate(finalColor) + 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((_Inverse_Clipping_var + _Tweak_transparency));

        fixed4 finalRGBA = fixed4(finalColor, Set_Opacity);

    #endif


    return finalRGBA;
}

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-9-28 07:32 , Processed in 0.176834 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表