208 lines
9.0 KiB
HLSL
208 lines
9.0 KiB
HLSL
// SPDX-License-Identifier: (Not available for this version, you are only allowed to use this software if you have express permission from the copyright holder and agreed to the latest NiloToonURP EULA)
|
|
// Copyright (c) 2021 Kuroneko ShaderLab Limited
|
|
|
|
#pragma once
|
|
|
|
#if _SHADOW_MODE_LILTOON
|
|
struct NiloToonLilToonShadowModeResult
|
|
{
|
|
half3 lightColorIndependentLitColor;
|
|
half finalShadowAreaForNiloEffects;
|
|
};
|
|
|
|
float NiloToonLilToonTooningNoSaturateScale(float aaStrength, float value, float border, float blur)
|
|
{
|
|
float borderMin = saturate(border - blur * 0.5);
|
|
float borderMax = saturate(border + blur * 0.5);
|
|
return (value - borderMin) / saturate(borderMax - borderMin + fwidth(value) * aaStrength);
|
|
}
|
|
|
|
float NiloToonLilToonTooningNoSaturateScale(float aaStrength, float value, float border, float blur, float borderRange)
|
|
{
|
|
float borderMin = saturate(border - blur * 0.5 - borderRange);
|
|
float borderMax = saturate(border + blur * 0.5);
|
|
return (value - borderMin) / saturate(borderMax - borderMin + fwidth(value) * aaStrength);
|
|
}
|
|
|
|
float NiloToonLilToonTooningScale(float aaStrength, float value, float border, float blur)
|
|
{
|
|
return saturate(NiloToonLilToonTooningNoSaturateScale(aaStrength, value, border, blur));
|
|
}
|
|
|
|
float NiloToonLilToonTooningScale(float aaStrength, float value, float border, float blur, float borderRange)
|
|
{
|
|
return saturate(NiloToonLilToonTooningNoSaturateScale(aaStrength, value, border, blur, borderRange));
|
|
}
|
|
|
|
float3 NiloToonLilToonLinearToSRGB(float3 col)
|
|
{
|
|
float3 low = col * 12.92;
|
|
float3 high = 1.055 * pow(max(col, 0.0), 1.0 / 2.4) - 0.055;
|
|
return lerp(low, high, step(0.0031308, col));
|
|
}
|
|
|
|
void NiloToonLilToonCalcLUTUV(float3 col, float resX, float resY, out float4 uv, out float factor)
|
|
{
|
|
#if !UNITY_COLORSPACE_GAMMA
|
|
col = NiloToonLilToonLinearToSRGB(col);
|
|
#endif
|
|
float3 res = float3(resX, resY, resX * resY);
|
|
float3 resInv = float3(1.0, -1.0, 1.0) / res;
|
|
|
|
float3 col2 = (col - col * resInv.z) + 0.5 * resInv.z;
|
|
float4 b2 = saturate(col2.b + resInv.z * float2(-0.5, 0.5)).xxyy * res.zyzy;
|
|
float4 b3 = floor(b2);
|
|
uv = float4(0, 1, 0, 1) + (col2.rgrg + b3) * resInv.xyxy;
|
|
factor = abs(b2.x - b3.x);
|
|
}
|
|
|
|
// Match lilToon's shared sampler behavior for shadow masks.
|
|
#define NILO_LIL_SAMPLE_SHADOW_MASK_WITH_LOD(textureName, uv, lod) \
|
|
((lod) > 0 ? SAMPLE_TEXTURE2D_GRAD(textureName, sampler_linear_repeat, uv, max(abs(ddx(uv)), lod), max(abs(ddy(uv)), lod)) : SAMPLE_TEXTURE2D(textureName, sampler_linear_repeat, uv))
|
|
|
|
#define NILO_LIL_SAMPLE_SHADOW_COLOR_TEX(textureName, uv, lutUv, lutFactor) \
|
|
(_lilShadowColorType == 1 ? lerp(SAMPLE_TEXTURE2D_LOD(textureName, sampler_linear_clamp, (lutUv).xy, 0), SAMPLE_TEXTURE2D_LOD(textureName, sampler_linear_clamp, (lutUv).zw, 0), lutFactor) : SAMPLE_TEXTURE2D(textureName, sampler_BaseMap, uv))
|
|
|
|
half NiloToonLilToonRemapAO(half value, half minValue, half maxValue)
|
|
{
|
|
return invLerpClamp(minValue, maxValue, value);
|
|
}
|
|
|
|
NiloToonLilToonShadowModeResult CalculateNiloToonLilToonShadowMode(
|
|
ToonSurfaceData surfaceData,
|
|
ToonLightingData lightingData,
|
|
Light light,
|
|
half selfShadowMapShadow,
|
|
half depthDiffShadow,
|
|
half finalNiloShadowArea)
|
|
{
|
|
NiloToonLilToonShadowModeResult result;
|
|
|
|
if (!_EnableShadowColor)
|
|
{
|
|
result.lightColorIndependentLitColor = surfaceData.albedo;
|
|
result.finalShadowAreaForNiloEffects = finalNiloShadowArea;
|
|
return result;
|
|
}
|
|
|
|
const float2 uv = lightingData.uv;
|
|
const half3 rawAlbedo = surfaceData.albedo;
|
|
const half3 L = light.direction;
|
|
|
|
// lilToon also adds distance(fd.L, fd.origL) for _LightDirectionOverride; intentionally skipped here.
|
|
half receivedShadow = saturate(light.shadowAttenuation);
|
|
#if _NILOTOON_RECEIVE_SELF_SHADOW
|
|
receivedShadow *= selfShadowMapShadow;
|
|
#endif
|
|
receivedShadow *= depthDiffShadow;
|
|
receivedShadow = saturate(receivedShadow);
|
|
|
|
half3 N1 = lerp(lightingData.normalWS_NoNormalMap, lightingData.normalWS, _lilShadowNormalStrength);
|
|
half3 N2 = lerp(lightingData.normalWS_NoNormalMap, lightingData.normalWS, _lilShadow2ndNormalStrength);
|
|
half3 N3 = lerp(lightingData.normalWS_NoNormalMap, lightingData.normalWS, _lilShadow3rdNormalStrength);
|
|
|
|
half4 shadowStrengthMask = NILO_LIL_SAMPLE_SHADOW_MASK_WITH_LOD(_lilShadowStrengthMask, uv, _lilShadowStrengthMaskLOD);
|
|
|
|
half4 lns = 1.0;
|
|
lns.x = saturate(dot(L, N1) * 0.5 + 0.5);
|
|
lns.y = saturate(dot(L, N2) * 0.5 + 0.5);
|
|
lns.z = saturate(dot(L, N3) * 0.5 + 0.5);
|
|
lns.w = lns.x;
|
|
|
|
half aaStrength = _lilAAStrength;
|
|
|
|
if (_lilShadowMaskType == 2)
|
|
{
|
|
float3 faceR = mul((float3x3)UNITY_MATRIX_M, float3(-1.0, 0.0, 0.0));
|
|
float LdotR = dot(L.xz, faceR.xz);
|
|
half sdf = LdotR < 0 ? shadowStrengthMask.g : shadowStrengthMask.r;
|
|
|
|
float3 faceF = mul((float3x3)UNITY_MATRIX_M, float3(0.0, 0.0, 1.0));
|
|
faceF.y *= _lilShadowFlatBlur;
|
|
faceF = SafeNormalize(faceF);
|
|
|
|
float3 faceL = L;
|
|
faceL.y *= _lilShadowFlatBlur;
|
|
faceL = SafeNormalize(faceL);
|
|
|
|
half lnSDF = dot(faceL, faceF);
|
|
lns = lerp(saturate(lnSDF * 0.5 + sdf * 0.5 + 0.25), lns, shadowStrengthMask.b);
|
|
aaStrength = 0;
|
|
shadowStrengthMask.r = shadowStrengthMask.a;
|
|
}
|
|
|
|
lns.x *= lerp(1.0, receivedShadow, _lilShadowReceive);
|
|
lns.y *= lerp(1.0, receivedShadow, _lilShadow2ndReceive);
|
|
lns.z *= lerp(1.0, receivedShadow, _lilShadow3rdReceive);
|
|
|
|
half shadowBlur = _lilShadowBlur;
|
|
half shadow2ndBlur = _lilShadow2ndBlur;
|
|
half shadow3rdBlur = _lilShadow3rdBlur;
|
|
half4 shadowBlurMask = NILO_LIL_SAMPLE_SHADOW_MASK_WITH_LOD(_lilShadowBlurMask, uv, _lilShadowBlurMaskLOD);
|
|
shadowBlur *= shadowBlurMask.r;
|
|
shadow2ndBlur *= shadowBlurMask.g;
|
|
shadow3rdBlur *= shadowBlurMask.b;
|
|
|
|
half4 shadowBorderMask = NILO_LIL_SAMPLE_SHADOW_MASK_WITH_LOD(_lilShadowBorderMask, uv, _lilShadowBorderMaskLOD);
|
|
shadowBorderMask.r = NiloToonLilToonRemapAO(shadowBorderMask.r, _lilShadowAO1Min, _lilShadowAO1Max);
|
|
shadowBorderMask.g = NiloToonLilToonRemapAO(shadowBorderMask.g, _lilShadowAO2Min, _lilShadowAO2Max);
|
|
shadowBorderMask.b = NiloToonLilToonRemapAO(shadowBorderMask.b, _lilShadowAO3Min, _lilShadowAO3Max);
|
|
|
|
lns.xyz = _lilShadowPostAO ? lns.xyz : lns.xyz * shadowBorderMask.rgb;
|
|
lns.w = lns.x;
|
|
lns.x = NiloToonLilToonTooningNoSaturateScale(aaStrength, lns.x, _lilShadowBorder, shadowBlur);
|
|
lns.y = NiloToonLilToonTooningNoSaturateScale(aaStrength, lns.y, _lilShadow2ndBorder, shadow2ndBlur);
|
|
lns.w = NiloToonLilToonTooningNoSaturateScale(aaStrength, lns.w, _lilShadowBorder, shadowBlur, _lilShadowBorderRange);
|
|
lns.z = NiloToonLilToonTooningNoSaturateScale(aaStrength, lns.z, _lilShadow3rdBorder, shadow3rdBlur);
|
|
lns = _lilShadowPostAO ? lns * shadowBorderMask.rgbr : lns;
|
|
lns = saturate(lns);
|
|
|
|
half backfaceShadow = lightingData.facing < 0.0 ? 1.0 - _BackFaceForceShadow : 1.0;
|
|
lns.x *= backfaceShadow;
|
|
lns.y *= backfaceShadow;
|
|
lns.z *= backfaceShadow;
|
|
lns.w *= backfaceShadow;
|
|
|
|
half shadowStrength = _lilShadowStrength;
|
|
if (_lilShadowMaskType == 1)
|
|
{
|
|
half3 flatN = normalize(mul((float3x3)UNITY_MATRIX_M, float3(0.0, 0.25, 1.0)));
|
|
half lnFlat = saturate((dot(flatN, L) + _lilShadowFlatBorder) / _lilShadowFlatBlur);
|
|
lnFlat *= lerp(1.0, receivedShadow, _lilShadowReceive);
|
|
lns = lerp(lnFlat, lns, shadowStrengthMask.r);
|
|
}
|
|
else
|
|
{
|
|
shadowStrength *= shadowStrengthMask.r;
|
|
}
|
|
lns.x = lerp(1.0, lns.x, shadowStrength);
|
|
|
|
float4 shadowLutUv;
|
|
float shadowLutFactor;
|
|
NiloToonLilToonCalcLUTUV(rawAlbedo, 16, 1, shadowLutUv, shadowLutFactor);
|
|
|
|
half4 shadowColorTex = NILO_LIL_SAMPLE_SHADOW_COLOR_TEX(_lilShadowColorTex, uv, shadowLutUv, shadowLutFactor);
|
|
half4 shadow2ndColorTex = NILO_LIL_SAMPLE_SHADOW_COLOR_TEX(_lilShadow2ndColorTex, uv, shadowLutUv, shadowLutFactor);
|
|
half4 shadow3rdColorTex = NILO_LIL_SAMPLE_SHADOW_COLOR_TEX(_lilShadow3rdColorTex, uv, shadowLutUv, shadowLutFactor);
|
|
|
|
half3 indirectColor = lerp(rawAlbedo, shadowColorTex.rgb, shadowColorTex.a) * _lilShadowColor.rgb;
|
|
|
|
half3 shadow2ndColor = lerp(rawAlbedo, shadow2ndColorTex.rgb, shadow2ndColorTex.a) * _lilShadow2ndColor.rgb;
|
|
lns.y = _lilShadow2ndColor.a - lns.y * _lilShadow2ndColor.a;
|
|
indirectColor = lerp(indirectColor, shadow2ndColor, lns.y);
|
|
|
|
half3 shadow3rdColor = lerp(rawAlbedo, shadow3rdColorTex.rgb, shadow3rdColorTex.a) * _lilShadow3rdColor.rgb;
|
|
lns.z = _lilShadow3rdColor.a - lns.z * _lilShadow3rdColor.a;
|
|
indirectColor = lerp(indirectColor, shadow3rdColor, lns.z);
|
|
|
|
indirectColor = lerp(indirectColor, indirectColor * rawAlbedo, _lilShadowMainStrength);
|
|
indirectColor = lerp(indirectColor, rawAlbedo, saturate(Luminance(lightingData.SH) * _lilShadowEnvStrength));
|
|
indirectColor = min(indirectColor, rawAlbedo);
|
|
indirectColor = lerp(indirectColor, rawAlbedo, lns.w * _lilShadowBorderColor.rgb);
|
|
|
|
result.lightColorIndependentLitColor = lerp(indirectColor, rawAlbedo, lns.x);
|
|
result.finalShadowAreaForNiloEffects = saturate(lns.x);
|
|
return result;
|
|
}
|
|
#endif
|