Files
beyond/Assets/ThirdParty/Lux URP Essentials/Shader Graphs/Includes/Lux_Lighting_Skin.hlsl
2024-11-20 15:21:28 +01:00

324 lines
11 KiB
HLSL

#ifndef LIGHTWEIGHT_SKINLIGHTING_INCLUDED
#define LIGHTWEIGHT_SKINLIGHTING_INCLUDED
#if !defined(SHADERGRAPH_PREVIEW) || defined(LIGHTWEIGHT_LIGHTING_INCLUDED)
// As we do not have access to the vertex lights we will make the shader always sample add lights per pixel
#if defined(_ADDITIONAL_LIGHTS_VERTEX)
#undef _ADDITIONAL_LIGHTS_VERTEX
#define _ADDITIONAL_LIGHTS
#endif
#endif
//TEXTURE2D(_SkinLUT); SAMPLER(sampler_SkinLUT); float4 _SkinLUT_TexelSize;
#if !defined(SHADERGRAPH_PREVIEW) || defined(LIGHTWEIGHT_LIGHTING_INCLUDED)
half3 DirectBDRF_Lux(BRDFData brdfData, half3 normalWS, half3 lightDirectionWS, half3 viewDirectionWS)
{
#ifndef _SPECULARHIGHLIGHTS_OFF
float3 halfDir = SafeNormalize(lightDirectionWS + viewDirectionWS);
float NoH = saturate(dot(normalWS, halfDir));
half LoH = saturate(dot(lightDirectionWS, halfDir));
// GGX Distribution multiplied by combined approximation of Visibility and Fresnel
// BRDFspec = (D * V * F) / 4.0
// D = roughness² / ( NoH² * (roughness² - 1) + 1 )²
// V * F = 1.0 / ( LoH² * (roughness + 0.5) )
// See "Optimizing PBR for Mobile" from Siggraph 2015 moving mobile graphics course
// https://community.arm.com/events/1155
// Final BRDFspec = roughness² / ( NoH² * (roughness² - 1) + 1 )² * (LoH² * (roughness + 0.5) * 4.0)
// We further optimize a few light invariant terms
// brdfData.normalizationTerm = (roughness + 0.5) * 4.0 rewritten as roughness * 4.0 + 2.0 to a fit a MAD.
float d = NoH * NoH * brdfData.roughness2MinusOne + 1.00001f;
half LoH2 = LoH * LoH;
half specularTerm = brdfData.roughness2 / ((d * d) * max(0.1h, LoH2) * brdfData.normalizationTerm);
// On platforms where half actually means something, the denominator has a risk of overflow
// clamp below was added specifically to "fix" that, but dx compiler (we convert bytecode to metal/gles)
// sees that specularTerm have only non-negative terms, so it skips max(0,..) in clamp (leaving only min(100,...))
#if defined (SHADER_API_MOBILE) || defined (SHADER_API_SWITCH)
specularTerm = specularTerm - HALF_MIN;
specularTerm = clamp(specularTerm, 0.0, 100.0); // Prevent FP16 overflow on mobiles
#endif
half3 color = specularTerm * brdfData.specular; // + brdfData.diffuse;
return color;
#else
return 0; //brdfData.diffuse;
#endif
}
half3 GlobalIllumination_Lux(BRDFData brdfData, half3 bakedGI, half occlusion, half3 normalWS, half3 viewDirectionWS,
half specOccluison)
{
half fresnelTerm = 0;
half3 indirectSpecular = 0;
if(specOccluison > 0) {
half3 reflectVector = reflect(-viewDirectionWS, normalWS);
fresnelTerm = Pow4(1.0 - saturate(dot(normalWS, viewDirectionWS)));
indirectSpecular = GlossyEnvironmentReflection(reflectVector, brdfData.perceptualRoughness, occlusion) * specOccluison;
}
half3 indirectDiffuse = bakedGI * occlusion;
return EnvironmentBRDF(brdfData, indirectDiffuse, indirectSpecular, fresnelTerm);
}
half3 LightingPhysicallyBasedSkin(BRDFData brdfData, half3 lightColor, half3 lightDirectionWS, half lightAttenuation, half3 normalWS, half3 viewDirectionWS, half NdotL, half NdotLUnclamped, half curvature, half skinMask)
{
//half3 radiance = lightColor * NdotL;
half3 diffuseLighting = brdfData.diffuse * SAMPLE_TEXTURE2D_LOD(_SkinLUT, sampler_SkinLUT, float2( (NdotLUnclamped * 0.5 + 0.5), curvature), 0).rgb;
diffuseLighting = lerp(brdfData.diffuse * NdotL, diffuseLighting, skinMask);
return ( DirectBDRF_Lux(brdfData, normalWS, lightDirectionWS, viewDirectionWS) * NdotL + diffuseLighting ) * lightColor * lightAttenuation;
}
half3 LightingPhysicallyBasedSkin(BRDFData brdfData, Light light, half3 normalWS, half3 viewDirectionWS, half NdotL, half NdotLUnclamped, half curvature, half skinMask)
{
return LightingPhysicallyBasedSkin(brdfData, light.color, light.direction, light.distanceAttenuation * light.shadowAttenuation, normalWS, viewDirectionWS, NdotL, NdotLUnclamped, curvature, skinMask);
}
#endif
void Lighting_half(
// Base inputs
half3 positionWS,
half3 viewDirectionWS,
// Normal inputs
half3 normalWS,
half3 tangentWS,
half3 bitangentWS,
bool enableNormalMapping,
bool enableDiffuseNormalMapping,
bool enableBackScattering,
bool useVertexNormal,
// Surface description
half3 albedo,
half metallic,
half3 specular,
half smoothness,
half occlusion,
half3 emission,
half alpha,
half4 translucency,
half AmbientReflection,
half3 subsurfaceColor,
half curvature,
half skinMask,
half maskbyshadowstrength,
half backScattering,
Texture2D normalMap,
SamplerState sampler_Normal,
float2 UV,
float bumpScale,
float diffuseBias,
// Lightmapping
float2 lightMapUV,
// Final lit color
out half3 MetaAlbedo,
out half3 FinalLighting,
out half3 MetaSpecular
)
{
#if defined(SHADERGRAPH_PREVIEW) || ( !defined(LIGHTWEIGHT_LIGHTING_INCLUDED) && !defined(UNIVERSAL_LIGHTING_INCLUDED) )
FinalLighting = albedo;
MetaAlbedo = half3(0,0,0);
MetaSpecular = half3(0,0,0);
#else
half3 diffuseNormalWS;
if (enableNormalMapping) {
half3x3 ToW = half3x3(tangentWS.xyz, bitangentWS.xyz, normalWS.xyz);
half4 sampleNormal = SAMPLE_TEXTURE2D(normalMap, sampler_Normal, UV);
half3 normalTS = UnpackNormalScale(sampleNormal, bumpScale);
// Get specular normal
half3 snormalWS = TransformTangentToWorld(normalTS, ToW);
snormalWS = NormalizeNormalPerPixel(snormalWS);
// Get diffuse normal
if(enableDiffuseNormalMapping) {
half4 sampleNormalDiffuse = SAMPLE_TEXTURE2D_BIAS(normalMap, sampler_Normal, UV, diffuseBias);
// Do not manually unpack the normal map as it might use RGB.
half3 diffuseNormalTS = UnpackNormal(sampleNormalDiffuse);
// Get diffuseNormalWS
diffuseNormalWS = TransformTangentToWorld(diffuseNormalTS, ToW);
diffuseNormalWS = NormalizeNormalPerPixel(diffuseNormalWS);
}
else {
diffuseNormalWS = (useVertexNormal) ? normalWS : snormalWS;
}
// Set specular normal
normalWS = snormalWS;
}
else {
normalWS = NormalizeNormalPerPixel(normalWS);
diffuseNormalWS = normalWS;
}
viewDirectionWS = SafeNormalize(viewDirectionWS);
// GI Lighting
half3 bakedGI;
#ifdef LIGHTMAP_ON
lightMapUV = lightMapUV * unity_LightmapST.xy + unity_LightmapST.zw;
bakedGI = SAMPLE_GI(lightMapUV, half3(0,0,0), diffuseNormalWS);
#else
bakedGI = SampleSH(diffuseNormalWS);
#endif
BRDFData brdfData;
InitializeBRDFData(albedo, metallic, specular, smoothness, alpha, brdfData);
FinalLighting = GlobalIllumination_Lux(brdfData, bakedGI, occlusion, normalWS, viewDirectionWS, AmbientReflection);
// Backscattering
if (enableBackScattering) {
FinalLighting += backScattering * SampleSH(-diffuseNormalWS) * albedo * occlusion * translucency.x * subsurfaceColor * skinMask;
}
// Get Shadow Sampling Coords
#if SHADOWS_SCREEN
float4 clipPos = TransformWorldToHClip(positionWS);
float4 shadowCoord = ComputeScreenPos(clipPos);
#else
float4 shadowCoord = TransformWorldToShadowCoord(positionWS);
#endif
Light mainLight = GetMainLight(shadowCoord);
MixRealtimeAndBakedGI(mainLight, normalWS, bakedGI, half4(0, 0, 0, 0));
half NdotLUnclamped = dot(diffuseNormalWS, mainLight.direction);
half NdotL = saturate( dot(normalWS, mainLight.direction) );
FinalLighting += LightingPhysicallyBasedSkin(brdfData, mainLight, normalWS, viewDirectionWS, NdotL, NdotLUnclamped, curvature, skinMask);
// Subsurface Scattering
half transPower = translucency.y;
half3 transLightDir = mainLight.direction + normalWS * translucency.w;
half transDot = dot( transLightDir, -viewDirectionWS );
transDot = exp2(saturate(transDot) * transPower - transPower);
FinalLighting += skinMask * subsurfaceColor * transDot * (1.0 - saturate(NdotLUnclamped)) * mainLight.color * lerp(1.0h, mainLight.shadowAttenuation, translucency.z) * translucency.x;
#ifdef _ADDITIONAL_LIGHTS
uint pixelLightCount = GetAdditionalLightsCount();
for (uint i = 0u; i < pixelLightCount; ++i)
{
//Light light = GetAdditionalLight(i, inputData.positionWS);
// Get index upfront as we need it for GetAdditionalLightShadowParams();
int index = GetPerObjectLightIndex(i);
Light light = GetAdditionalPerObjectLight(index, positionWS);
half NdotLUnclamped = dot(diffuseNormalWS, light.direction);
NdotL = saturate( dot(normalWS, light.direction) );
FinalLighting += LightingPhysicallyBasedSkin(brdfData, light, normalWS, viewDirectionWS, NdotL, NdotLUnclamped, curvature, skinMask);
half4 shadowParams = GetAdditionalLightShadowParams(index);
light.color *= lerp(1, shadowParams.x, maskbyshadowstrength); // shadowParams.x == shadow strength, which is 0 for point lights
// Subsurface Scattering
transLightDir = light.direction + normalWS * translucency.w;
transDot = dot( transLightDir, -viewDirectionWS );
transDot = exp2(saturate(transDot) * transPower - transPower);
FinalLighting += skinMask * subsurfaceColor * transDot * (1.0 - NdotL) * light.color * lerp(1.0h, light.shadowAttenuation, translucency.z) * light.distanceAttenuation * translucency.x;
}
#endif
#ifdef _ADDITIONAL_LIGHTS_VERTEX
// FinalLighting += inputData.vertexLighting * brdfData.diffuse;
#endif
FinalLighting += emission;
//FinalLighting = bakedGI;
// Set Albedo for meta pass
#if defined(LIGHTWEIGHT_META_PASS_INCLUDED) || defined(UNIVERSAL_META_PASS_INCLUDED)
FinalLighting = half3(0,0,0);
MetaAlbedo = albedo;
MetaSpecular = specular;
#else
MetaAlbedo = half3(0,0,0);
MetaSpecular = half3(0,0,0);
#endif
#endif
}
// Unity 2019.1. needs a float version
void Lighting_float(
// Base inputs
half3 positionWS,
half3 viewDirectionWS,
// Normal inputs
half3 normalWS,
half3 tangentWS,
half3 bitangentWS,
bool enableNormalMapping,
bool enableDiffuseNormalMapping,
bool enableBackScattering,
bool useVertexNormal,
// Surface description
half3 albedo,
half metallic,
half3 specular,
half smoothness,
half occlusion,
half3 emission,
half alpha,
half4 translucency,
half AmbientReflection,
half3 subsurfaceColor,
half curvature,
half skinMask,
half maskbyshadowstrength,
half backScattering,
Texture2D normalMap,
SamplerState sampler_Normal,
float2 UV,
float bumpScale,
float diffuseBias,
// Lightmapping
float2 lightMapUV,
// Final lit color
out half3 MetaAlbedo,
out half3 FinalLighting,
out half3 MetaSpecular
)
{
Lighting_half(
positionWS, viewDirectionWS, normalWS, tangentWS, bitangentWS, enableNormalMapping, enableDiffuseNormalMapping, enableBackScattering, useVertexNormal,
albedo, metallic, specular, smoothness, occlusion, emission, alpha,
translucency, AmbientReflection, subsurfaceColor, curvature, skinMask, maskbyshadowstrength,
backScattering,
normalMap, sampler_Normal, UV, bumpScale, diffuseBias,
lightMapUV, MetaAlbedo, FinalLighting, MetaSpecular
);
}
#endif