#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
struct Attributes
{
float4 positionOS : POSITION;
float3 normalOS : NORMAL;
float4 tangentOS : TANGENT;
float4 color : COLOR;
float2 uv : TEXCOORD0;
float2 backUV : TEXCOORD1;
};
struct Varyings
{
float2 uv : TEXCOORD0;
float2 backUV : TEXCOORD1;
float3 positionWS : TEXCOORD2;
half3 tangentWS : TEXCOORD3;
half3 bitangentWS : TEXCOORD4;
half3 normalWS : TEXCOORD5;
float4 positionNDC : TEXCOORD6;
half4 color : COLOR;
float4 positionCS : SV_POSITION;
};
half GetShadow(Varyings input, half3 lightDirection, half aoFactor)
{
half NDotL = dot(input.normalWS, lightDirection);
half halfLambert = 0.5 * NDotL + 0.5;
half shadow = saturate(2.0 * halfLambert * aoFactor);
return lerp(shadow, 1.0, step(0.9, aoFactor));
}
half GetFaceShadow(Varyings input, half3 lightDirection)
{
half3 F = SafeNormalize(half3(_FaceDirection.x, 0.0, _FaceDirection.z));
half3 L = SafeNormalize(half3(lightDirection.x, 0.0, lightDirection.z));
half FDotL = dot(F, L);
half FCrossL = cross(F, L).y;
half2 shadowUV = input.uv;
shadowUV.x = lerp(shadowUV.x, 1.0 - shadowUV.x, step(0.0, FCrossL));
half faceShadowMap = SAMPLE_TEXTURE2D(_FaceLightMap, sampler_FaceLightMap, shadowUV).r;
half faceShadow = step(-0.5 * FDotL + 0.5 + _FaceShadowOffset, faceShadowMap);
half faceMask = SAMPLE_TEXTURE2D(_FaceShadow, sampler_FaceShadow, input.uv).a;
half maskedFaceShadow = lerp(faceShadow, 1.0, faceMask);
return maskedFaceShadow;
}
half3 GetShadowColor(half shadow, half material, half day)
{
int index = 4;
index = lerp(index, 1, step(0.2, material));
index = lerp(index, 2, step(0.4, material));
index = lerp(index, 0, step(0.6, material));
index = lerp(index, 3, step(0.8, material));
half rangeMin = 0.5 + _ShadowOffset - _ShadowSmoothness;
half rangeMax = 0.5 + _ShadowOffset;
half2 rampUV = half2(smoothstep(rangeMin, rangeMax, shadow), index / 10.0 + 0.5 * day + 0.05);
half3 shadowRamp = SAMPLE_TEXTURE2D(_ShadowRamp, sampler_ShadowRamp, rampUV);
half3 shadowColor = shadowRamp * lerp(_ShadowColor, 1.0, smoothstep(0.9, 1.0, rampUV.x));
shadowColor = lerp(shadowColor, 1.0, step(rangeMax, shadow));
return shadowColor;
}
half3 GetSpecular(Varyings input, half3 lightDirection, half3 albedo, half3 lightMap)
{
half3 V = GetWorldSpaceNormalizeViewDir(input.positionWS);
half3 H = SafeNormalize(lightDirection + V);
half NDotH = dot(input.normalWS, H);
half blinnPhong = pow(saturate(NDotH), _SpecularSmoothness);
half3 normalVS = TransformWorldToViewNormal(input.normalWS, true);
half2 matcapUV = 0.5 * normalVS.xy + 0.5;
half3 metalMap = SAMPLE_TEXTURE2D(_MetalMap, sampler_MetalMap, matcapUV);
half3 nonMetallic = step(1.1, lightMap.b + blinnPhong) * lightMap.r * _NonmetallicIntensity;
half3 metallic = blinnPhong * lightMap.b * albedo * metalMap * _MetallicIntensity;
half3 specular = lerp(nonMetallic, metallic, step(0.9, lightMap.r));
return specular;
}
half GetRim(Varyings input)
{
half3 normalVS = TransformWorldToViewNormal(input.normalWS, true);
float2 uv = input.positionNDC.xy / input.positionNDC.w;
float2 offset = float2(_RimOffset * normalVS.x / _ScreenParams.x, 0.0);
float depth = LinearEyeDepth(SampleSceneDepth(uv), _ZBufferParams);
float offsetDepth = LinearEyeDepth(SampleSceneDepth(uv + offset), _ZBufferParams);
half rim = smoothstep(0.0, _RimThreshold, offsetDepth - depth) * _RimIntensity;
half3 V = GetWorldSpaceNormalizeViewDir(input.positionWS);
half NDotV = dot(input.normalWS, V);
half fresnel = pow(saturate(1.0 - NDotV), 5.0);
return rim * fresnel;
}
Varyings ForwardPassVertex(Attributes input)
{
VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz);
VertexNormalInputs normalInput = GetVertexNormalInputs(input.normalOS, input.tangentOS);
Varyings output = (Varyings)0;
output.uv = TRANSFORM_TEX(input.uv, _BaseMap);
output.backUV = TRANSFORM_TEX(input.backUV, _BaseMap);
output.positionWS = vertexInput.positionWS;
output.tangentWS = normalInput.tangentWS;
output.bitangentWS = normalInput.bitangentWS;
output.normalWS = normalInput.normalWS;
output.color = input.color;
output.positionNDC = vertexInput.positionNDC;
output.positionCS = vertexInput.positionCS;
output.positionCS.xy += _ScreenOffset.xy * output.positionCS.w;
return output;
}
half4 ForwardPassFragment(Varyings input, FRONT_FACE_TYPE facing : FRONT_FACE_SEMANTIC) : SV_TARGET
{
#if _DOUBLE_SIDED
input.uv = lerp(input.uv, input.backUV, IS_FRONT_VFACE(facing, 0.0, 1.0));
#endif
half4 baseMap = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.uv);
half3 albedo = baseMap.rgb * _BaseColor.rgb;
half alpha = baseMap.a;
#if _IS_FACE
albedo = lerp(albedo, _FaceBlushColor.rgb, _FaceBlushStrength * alpha);
#endif
#if _NORMAL_MAP
half3x3 tangentToWorld = half3x3(input.tangentWS, input.bitangentWS, input.normalWS);
half4 normalMap = SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, input.uv);
half3 normalTS = UnpackNormal(normalMap);
half3 normalWS = TransformTangentToWorld(normalTS, tangentToWorld, true);
input.normalWS = normalWS;
#endif
Light mainLight = GetMainLight();
half3 lightDirection = SafeNormalize(mainLight.direction * _LightDirectionMultiplier);
half4 lightMap = SAMPLE_TEXTURE2D(_LightMap, sampler_LightMap, input.uv);
half material = lerp(lightMap.a, _CustomMaterialType, _UseCustomMaterialType);
#if _IS_FACE
half shadow = GetFaceShadow(input, lightDirection);
#else
half aoFactor = lightMap.g * input.color.r;
half shadow = GetShadow(input, lightDirection, aoFactor);
#endif
half3 shadowColor = GetShadowColor(shadow, material, _IsDay);
half3 specular = 0.0;
#if _SPECULAR
specular = GetSpecular(input, lightDirection, albedo, lightMap.rgb);
#endif
half3 emission = 0.0;
#if _EMISSION
emission = albedo * _EmissionIntensity * alpha;
#endif
half3 rim = 0.0;
#if _RIM
rim = albedo * GetRim(input);
#endif
half3 finalColor = albedo * shadowColor + specular + rim + emission;
half finalAlpha = 1.0;
return half4(finalColor, finalAlpha);
}