Shader /*ase_name*/ "Hidden/FZDL_Shader/ASETemplate_CharacterBase" /*end*/ 
{
    Properties
    {
         
        _MainTex("Albedo", 2D) = "white" {}
        _Color("Color", Color) = (1,1,1,1)

        _LightMaskTex("ToonLightMask", 2D) = "white" {}
        _MaskTex("Mask", 2D) = "black" {}

        [Toggle(_USE_Ramp_Num4)]_Ramp_Num4("Ramp_Num4",Float) = 1
        [Toggle]_USE_GrayMask("Use GrayMask", Float) = 0
        [IntRange]_RampNum("RampNum", Range(1,20)) = 10

        _RampTex("RampTex", 2D) = "white" {}
        _RampColor("Ramp Color", Color) = (1,1,1,1)
 
 
        _LightMaskParam("_LightMaskParam", Range(-1.0,1.0)) = 0.7

        //Specular
        [HDR]_SpecColor("Specular Color", Color) = (0.5, 0.5, 0.5, 1)
        _Shininess("Shininess", Range(0.01,4)) = 0.1        
        _SpecSmooth("Smoothness", Range(0,1)) = 0.05
        _SpecStrength("SpecStrength", Range(0,5)) = 1
        
        //HightLight
        _HighLightColor("Highlight Color ",Color) =(1,1,1,1)


        //Rim 
        [HDR]_RimColor("Rim Color", color) = (0,0,0,1)
        _RimWidth("Rim Width", Range(0,1)) = 0
        [HDR]_BackRimColor("Back Rim Color", color) = (0,0,0,1)
        _BackRimMax("Back Rim Max", Range(0,1)) = 1
        _BackRimMin ("Back Rim Min", Range(0,1)) = 1

        //Emission 
        [HDR]_EmissionColor("Emission Color",Color) = (1,1,1,1)



        //Outline
        [Header(Outline)]
        _OutlineWidth ("Outline Width", Range(0, 100)) = 0.04
        _OutlineColor ("Outline Color", Color) = (0, 0, 0, 1)
        _MaxOutlineZOffset ("Max Outline Z Offset", Range(0, 100)) = 1
        _OutlineWidthAdjustZs ("Outline Width Adjust Dist Start (near, middle, far)", Vector) = (0.01, 2, 6, 0)
        _OutlineWidthAdjustScales ("Outline Width Adjust Scale (near, middle, far)", Vector) = (0.105, 0.245, 0.6, 0)


        //GPU Skinning
        [Header(Baked Animation)]
        _Giant_AnimationIndexWeightTexture ("Bones IndexWeight Texture",2D) = "white" {}
        _Giant_AnimationTexture ("Animation Frame Texture",2D) = "white" {}
        _Giant_AnimationTextureBlockWidth ("Animation A Frame Block Width",int) = 0
        _Giant_AnimationTextureBlockHeight  ("Animation A Frame Block Width",int) = 0
        _Giant_AnimationTextureWidth    ("Animation Texture Used Width",int) = 0
        _Giant_AnimationTextureHeight   ("Animation Texture Used Height",int) = 0
        _Giant_AnimationCurrFrame   ("Current Animation Clip Index Index",int) = 0
        _Giant_AnimationPrevFrame   ("Previous Animation Clip Index Index",int) = 0
        _Giant_AnimationTransition  ("Animation Clip Blend",int) = 0


        /*ase_props*/


        [Header(Polygon Offset)]
        _PolygonOffsetFactor ("Polygon Offset Factor", Float) = 0
        _PolygonOffsetUnit ("Polygon Offset Unit", Float) = 0
        _OutlinePolygonOffsetFactor ("Outline Polygon Offset Factor", Float) = 0
        _OutlinePolygonOffsetUnit ("Outline Polygon Offset Unit", Float) = 0


        [Header(CullMode)]
        [Enum(UnityEngine.Rendering.CullMode)]_Cull("剔除模式", float) = 2

        [Header(Depth)]
        [Enum(Off, 0, On, 1)]_ZWrite("是否写入深度", float) = 0

        [Enum(UnityEngine.Rendering.BlendMode)]_Src("源颜色", float) = 5
        [Enum(UnityEngine.Rendering.BlendMode)]_Dst("目标颜色", float) = 10
        [Enum(UnityEngine.Rendering.BlendOp)]_BlendOp("混合模式", float) = 0

    }
    SubShader
    {
        /*ase_subshader_options:Name=Settings
            Option:GPU Instancing:false,true:true
                true:SetDefine:pragma multi_compile_instancing
                false:RemoveDefine:pragma multi_compile_instancing
        */              


        Tags
        {
            "RenderPipeline" = "UniversalPipeline"
            "RenderType"="Opaque"
            "Queue"="Geometry+0" 
        }
        LOD 200

        /*ase_pass*/
        Pass
        {
            /*ase_main_pass*/

            Name "Main"
            Tags{"LightMode" = "UniversalForward"}

            Cull [_Cull]
            ZWrite [_ZWrite]
            Blend [_Src] [_Dst]
            BlendOp [_BlendOp]

            Offset [_PolygonOffsetFactor], [_PolygonOffsetUnit]

            LOD 100

            HLSLPROGRAM





            #pragma vertex character_vert
            #pragma fragment character_frag
            
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
            #include "../ShaderLibrary/Character/SkinInstancing.hlsl"
            /*ase_pragma*/

            //-------------------------------------------------
            //--------------- uniform variables ---------------
            //-------------------------------------------------
            CBUFFER_START(UnityPerMaterial)


            TEXTURE2D(_MainTex);       SAMPLER(sampler_MainTex);
            float4 _Color;
            TEXTURE2D(_LightMaskTex);       SAMPLER(sampler_LightMaskTex);
            TEXTURE2D(_MaskTex);       SAMPLER(sampler_MaskTex);

            float _RampNum;
            float _Ramp_Num4;
            float _USE_GrayMask;
            TEXTURE2D(_RampTex);       SAMPLER(sampler_RampTex);
            float3 _RampColor;

            float _LightMaskParam;


            //specular
            float3 _SpecColor;
            float _Shininess;
            float _SpecSmooth;
            float _SpecStrength;

            //Highlight
            float4 _HighLightColor;

            //Rim 
            float3 _RimColor;
            float _RimWidth;
            float _BackRimMax;
            float _BackRimMin;
            float3 _BackRimColor;

            //Emission
            float4 _EmissionColor;            
            CBUFFER_END
            /*ase_globals*/




            //-------------------------------------------------
            //--------------- functions -----------------------
            //-------------------------------------------------

















            //-------------------------------------------------
            //--------------- appdata -------------------------
            //-------------------------------------------------
            struct character_appdata
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
                float2 uv : TEXCOORD0;
                float4 color : COLOR;
                float4 tangent : TANGENT;
                /*ase_vdata:p=p;n=n;uv0=tc0.xy;c=c;t=t*/


            #if defined(SUPPORT_INSTANCED_SKINNING)
                FZDL_BAKED_SKIN_INSTANCING_ATTRIBUTES
            #endif    

                UNITY_VERTEX_INPUT_INSTANCE_ID
            };


            //-------------------------------------------------
            //--------------- v2f -----------------------------
            //-------------------------------------------------
            struct character_v2f
            {
                float4 position : SV_POSITION;
                half4 color : COLOR0;
                float4 texcoord : TEXCOORD0;
                float4 normalAndDiff : TEXCOORD1;
                float4 screen : TEXCOORD2;
                float3 worldPos : TEXCOORD3;
                float4 shadowCoord : TEXCOORD4;
                //float4 fogCoord : TEXCOORD5;

                /*ase_interp(5,7):sp=sp.xyzw;uv0=tc0.xyzw;uv1=tc1.xyzw;uv2=tc2.xyzw;c=c*/

                UNITY_VERTEX_INPUT_INSTANCE_ID
            };



            //-------------------------------------------------
            //--------------- vert shader ---------------------
            //-------------------------------------------------

            character_v2f character_vert(character_appdata v/*ase_vert_input*/)
            {


                character_v2f o = (character_v2f)0;

                UNITY_SETUP_INSTANCE_ID(v);
                UNITY_TRANSFER_INSTANCE_ID(v, o);


                //---------------------------------------------
                //Do GPU Skin
                //---------------------------------------------
                #if defined(SUPPORT_INSTANCED_SKINNING)
                    DoSkinning(v.vertex,v.normal,v.tangent,EXTRACT_SKIN_BAKED_DATA(v))
                #endif

                // ase common template code
                /*ase_vert_code:v=character_appdata;o=character_v2f*/


                float3 vertexValue = /*ase_vert_out:Vertex Offset;Float3;_Vertex*/0/*end*/;
                VertexPositionInputs vertexInput = GetVertexPositionInputs(v.vertex.xyz + vertexValue);
                VertexNormalInputs normalInput = GetVertexNormalInputs(v.normal, v.tangent);
                float3 viewDirWS = GetCameraPositionWS() - vertexInput.positionWS;
                //half3 vertexLight = VertexLighting(vertexInput.positionWS, normalInput.normalWS);


                o.position = vertexInput.positionCS;
                o.color = v.color;
                o.texcoord.xy = v.uv;
                o.normalAndDiff.xyz = normalInput.normalWS;
                //Diffuse
                // calculate diffuse factor
                //o.normalAndDiff.w = dot()
                o.screen = vertexInput.positionNDC;
                o.worldPos = vertexInput.positionWS;

                o.shadowCoord = GetShadowCoord(vertexInput);
              //  o.fogCoord = VolumetricFog_GetFogCoord(vertexInput.positionNDC, vertexInput.positionVS.z);

                return o;
            }


            //-------------------------------------------------
            //--------------- frag shader ---------------------
            //-------------------------------------------------

            half4 character_frag (character_v2f i /*ase_frag_input*/) : SV_Target
            {

                half4 outColor = 1;


                UNITY_SETUP_INSTANCE_ID(i);

                Light light = GetMainLight(i.shadowCoord);
                half3 lightDir = light.direction;

                #if defined(_ADDITIONAL_LIGHTS)
                //应用其他光源    
                    
                #endif


                // ase common template code
                /*ase_frag_code:i=character_v2f*/


                float2 uv = i.texcoord.xy;

                half3 N = normalize(i.normalAndDiff.xyz);
                half3 V = normalize(GetCameraPositionWS() - i.worldPos);
                half3 H = normalize(lightDir + V);


                #if defined(IS_FACE)
                    N.y = 0;
                #endif

                half dotN_L = dot(N,lightDir);
                half dotN_H = dot(N,H);
                half dotN_V = dot(N,V);


                half4 mainTexColor = SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex,uv);
                half3 tintcolor = _Color.rgb;
                half3 texColor = /*ase_frag_out:Tex Color;Float3;*/mainTexColor.rgb * tintcolor/*end*/;


                //todo ChangeTex ?

                //r是闭塞阴影，g是金属，b是高亮，a可以不用管变色后面要去掉
                //- Light Mask
                //  R   
                //  G   
                //  B   
                //  A   

                /*ase_local_var*/half4 lightMask = SAMPLE_TEXTURE2D(_LightMaskTex,sampler_LightMaskTex, uv);

                /*ase_local_var*/half4 mask = SAMPLE_TEXTURE2D(_MaskTex,sampler_MaskTex, uv);


                //??? Old Code Operation
                half v4 = 0.625 + mask.r * 0.25 - 0.5 * mask.b;
                half v10 = 0.45 + mask.r * 0.1 + mask.g * 0.4 - 0.2 * mask.b;
                half v20 = (_RampNum+1-mask.r*20)/_RampNum-1/_RampNum*0.5;
                half v = lerp(v10,v4,_Ramp_Num4);
                v = /*ase_frag_out:Ramp Channel(Y Axis);Float;*/lerp(v,v20,_USE_GrayMask)/*end*/;

                float ndh_Lut = dotN_L;// lerp(dotN_L,dotN_H,light.shadowAttenuation);
                float w = fwidth(dotN_V) * 2.0;

                ndh_Lut = lerp(lightMask.r * ndh_Lut, ndh_Lut, _LightMaskParam+0.3);
                ndh_Lut = min(ndh_Lut,0.9);


                //light Atten

                half lightAtten = light.shadowAttenuation * light.distanceAttenuation;

                half3 shadowColor = SAMPLE_TEXTURE2D(_RampTex,sampler_RampTex,float2(0,v)).rgb;


                //Specular
                half3 SpecularColor = SAMPLE_TEXTURE2D(_RampTex,sampler_RampTex,float2(1,v)).rgb;

                float spec = pow(saturate(dotN_V),_Shininess * 128) * 2;
                spec = smoothstep(0.5 - _SpecSmooth * 0.5, 0.5 + _SpecSmooth * 0.5, spec);

                half3 specular = spec * _SpecColor * lightMask.g * SpecularColor * _SpecStrength;

                //HightLight
                half3 highlight =  _HighLightColor.a * lightMask.b * lightMask.b * ndh_Lut * ndh_Lut * ndh_Lut *  _HighLightColor.rgb * 0.6;

                highlight = /*ase_frag_out:Highlight;Float3;*/highlight * SpecularColor * lightAtten/*end*/;


                //Ramp
                float2 rampUV = 0;
                rampUV.y = v;
                rampUV.x = /*ase_frag_out:Ramp Step(X Axis);Float;*/ndh_Lut/*end*/;
                half3 ramp = SAMPLE_TEXTURE2D(_RampTex,sampler_RampTex,rampUV).rgb;

                half rampWhiteColor = step(3, ramp.r + ramp.g + ramp.b);
                ramp.rgb = lerp(ramp.rgb * _RampColor, ramp.rgb, rampWhiteColor);
                ramp.rgb = lerp(ramp.rgb,shadowColor,1 - lightAtten);

                half3 ramp4 = ramp.rgb - (1.0 - ramp.rgb) * (1.0 - mask.g);
                ramp.rgb = lerp(ramp.rgb,ramp4,_Ramp_Num4*(1-_USE_GrayMask));

                // outColor.rgb *= ramp.rgb;
                // outColor.rgb *= 1-lerp(0, (1 - lightMask.rrr-outColor.rgb) * 0.6, max(0, -dotN_L));
                ramp.rgb *= 1-lerp(0, (1 - lightMask.rrr-outColor.rgb) * 0.6, max(0, -dotN_L));



                //Rim
                half rim = smoothstep(_BackRimMin,_BackRimMax,1 - dotN_V);
                half3 rimColor = rim * saturate(dotN_L) * _BackRimColor * lightAtten;

                half rimStep = smoothstep(1 - w - _RimWidth, 1, 1 - dotN_V);
                rimColor = /*ase_frag_out:Rim Color;float3;*/rimColor + rimStep * _RimColor/*end*/;


                //Emission
                half3 emission = /*ase_frag_out:Emission Color;float3;*/_EmissionColor.rgb * _EmissionColor.a * mask.a/*end*/;

                outColor.rgb = texColor * ramp + specular + highlight;
                outColor.rgb += emission + rimColor;
                


                return outColor;
            }

            ENDHLSL
        }

        /*ase_pass*/
        Pass
        {

            Name "Outline"
            Tags{"LightMode" = "SRPDefaultUnlit"}

            Cull Back
            ZWrite On
            Blend One Zero
            BlendOp Add
            Offset [_OutlinePolygonOffsetFactor], [_OutlinePolygonOffsetUnit]


            LOD 100

            HLSLPROGRAM

            #pragma vertex character_vert
            #pragma fragment character_frag
            
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
            #include "../ShaderLibrary/Character/SkinInstancing.hlsl"


            /*ase_pragma*/
            
            //------------------------hlsl-------------------------
            //--------------- uniform variables ---------------
            //-------------------------------------------------
            CBUFFER_START(UnityPerMaterial)

            float   _OutlineWidth;
            float4  _OutlineColor;
            float   _MaxOutlineZOffset;
            float4  _OutlineWidthAdjustZs;
            float4  _OutlineWidthAdjustScales;

            CBUFFER_END
            /*ase_globals*/





            //-------------------------------------------------
            //--------------- functions -----------------------
            //-------------------------------------------------



            inline float lerpByZ(float startScale, float endScale, float startZ, float endZ, float z)
            {
                float t = (z - startZ) / max(endZ - startZ, 0.001);
                t = saturate(t);
                return lerp(startScale, endScale, t);
            }




            //-------------------------------------------------
            //--------------- appdata -------------------------
            //-------------------------------------------------
            struct character_appdata
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
                float2 uv : TEXCOORD0;
                float4 color : COLOR;
                float4 tangent : TANGENT;
                /*ase_vdata:p=p;n=n;uv0=tc0.xy;c=c;t=t*/


            #if defined(SUPPORT_INSTANCED_SKINNING)
                FZDL_BAKED_SKIN_INSTANCING_ATTRIBUTES
            #endif    

                UNITY_VERTEX_INPUT_INSTANCE_ID
            };


            //-------------------------------------------------
            //--------------- v2f -----------------------------
            //-------------------------------------------------
            struct character_v2f
            {
                float4 position : SV_POSITION;
                // half4 color : COLOR0;
                // float4 texcoord : TEXCOORD0;
                // float4 normalAndDiff : TEXCOORD1;
                // float4 screen : TEXCOORD2;
                // float3 worldPos : TEXCOORD3;
                // float4 shadowCoord : TEXCOORD4;
                //float4 fogCoord : TEXCOORD5;

                /*ase_interp(0,7):sp=sp.xyzw*/

                UNITY_VERTEX_INPUT_INSTANCE_ID
            };



            //-------------------------------------------------
            //--------------- vert shader ---------------------
            //-------------------------------------------------

            character_v2f character_vert(character_appdata v/*ase_vert_input*/)
            {


                character_v2f o = (character_v2f)0;

                UNITY_SETUP_INSTANCE_ID(v);
                UNITY_TRANSFER_INSTANCE_ID(v, o);


                //---------------------------------------------
                //Do GPU Skin
                //---------------------------------------------
                #if defined(SUPPORT_INSTANCED_SKINNING)
                    DoSkinning(v.vertex,v.normal,v.tangent,EXTRACT_SKIN_BAKED_DATA(v))
                #endif



                // ase common template code 
                /*ase_vert_code:v=character_appdata;o=character_v2f*/    


                //消除误差提高精度
                float4x4 worldMatZero = GetObjectToWorldMatrix();
                worldMatZero._14_24_34 -= GetCameraPositionWS();

                float4x4 viewMatZero = GetWorldToViewMatrix();
                viewMatZero._14_24_34 = 0;

                o.position = mul(viewMatZero,mul(worldMatZero,v.vertex));

                float3 normal = v.normal.xyz;
                half3 N = mul((float3x3)viewMatZero,mul((float3x3)worldMatZero,normal));

                //在View Space 只需要 xy的方向
                N.z = 0.01f;
                N = normalize(N);

                //根据距离计算外廓outline偏移
                half outOffset = 0;

                float fovScale = GetViewToHClipMatrix()._22;    //1/tan(FOV/2)
                // outwidth/(z * tan(FOV/2)) 是定值
                float outWidth = -o.position.z * 2.414/fovScale;       //2.414 对应 fov 45

                //调整
                float2 zRange,scales;
                if(outWidth < _OutlineWidthAdjustZs.y)
                {
                    zRange = _OutlineWidthAdjustZs.xy;
                    scales = _OutlineWidthAdjustScales.xy;
                }
                else
                {
                    zRange = _OutlineWidthAdjustZs.yz;
                    scales = _OutlineWidthAdjustScales.yz;
                }
                float scale = lerpByZ(scales.x, scales.y, zRange.x, zRange.y, outWidth);
                outOffset = _OutlineWidth * scale * 100 / 2.414;

                //应用Z offset
                o.position.xyz += normalize(o.position.xyz) * _MaxOutlineZOffset;
                //应用out offset
                o.position.xy += N.xy * outOffset;

                o.position = TransformWViewToHClip(o.position.xyz);



               // o.shadowCoord = GetShadowCoord(vertexInput);
              //  o.fogCoord = VolumetricFog_GetFogCoord(vertexInput.positionNDC, vertexInput.positionVS.z);

                return o;
            }


            //-------------------------------------------------
            //--------------- frag shader ---------------------
            //-------------------------------------------------
            half4 character_frag (character_v2f i /*ase_frag_input*/) : SV_Target
            {


                // Light light = GetMainLight(i.shadowCoord);

                // half lightAtten = light.shadowAttenuation * light.distanceAttenuation;



                // ase common template code
                /*ase_frag_code:i=character_v2f*/



                return half4(_OutlineColor.rgb,1);
            }


            ENDHLSL
        }

    }



    CustomEditor "FZDL.ShaderDrawer.LWGUI" 
    FallBack "Hidden/InternalErrorShader"
}
