Files
PrinceOfGlory/Assets/OF3D_LookDev/ShaderTest/Includes/URP Common.hlsl
kridoo 6e91a0c7f0 111
2025-09-15 17:32:08 +08:00

449 lines
20 KiB
HLSL

#ifndef UNIVERSAL_SKINLIGHTING_INCLUDED
#define UNIVERSAL_SKINLIGHTING_INCLUDED
TEXTURE2D(_SkinLUT); SAMPLER(sampler_SkinLUT); float4 _SkinLUT_TexelSize;
half3 GlobalIllumination(BRDFData brdfData, half3 bakedGI, half occlusion, float3 positionWS, half3 normalWS, half3 viewDirectionWS, float2 normalizedScreenSpaceUV,
half specOcclusion)
{
half3 reflectVector = reflect(-viewDirectionWS, normalWS);
half fresnelTerm = Pow4(1.0 - saturate(dot(normalWS, viewDirectionWS)));
half3 indirectDiffuse = bakedGI * occlusion;
half3 indirectSpecular = GlossyEnvironmentReflection(
reflectVector, positionWS, brdfData.perceptualRoughness, occlusion, normalizedScreenSpaceUV) * specOcclusion;
half3 color = EnvironmentBRDF(brdfData, indirectDiffuse, indirectSpecular, fresnelTerm);
// Debug
if (IsOnlyAOLightingFeatureEnabled())
{
color = occlusion.xxx; // "Base white" for AO debug lighting mode // Lux: We return occlusion here
}
return color;
}
inline half GammaToLinearSpace(half sRGB)
{
// Approximate version from http://chilliant.blogspot.com.au/2012/08/srgb-approximations-for-hlsl.html
return sRGB * (sRGB * (sRGB * 0.305306011h + 0.682171111h) + 0.012522878h);
}
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;
#ifndef _SPECULARHIGHLIGHTS_OFF
half specularTerm = DirectBRDFSpecular(brdfData, normalWS, lightDirectionWS, viewDirectionWS);
return ( specularTerm * brdfData.specular * NdotL + diffuseLighting ) * lightColor * lightAttenuation;
#else
return diffuseLighting * lightColor * lightAttenuation;
#endif
}
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);
}
half4 URPSkinFragmentPBR(InputData inputData, SurfaceData surfaceData,
half4 translucency, half AmbientReflection, half3 subsurfaceColor, half curvature, half skinMask, half maskbyshadowstrength, half backScatter)
{
BRDFData brdfData;
InitializeBRDFData(surfaceData, brdfData);
#if defined(DEBUG_DISPLAY)
half4 debugColor;
if (CanDebugOverrideOutputColor(inputData, surfaceData, brdfData, debugColor)) {
return debugColor;
}
#endif
half4 shadowMask = CalculateShadowMask(inputData);
AmbientOcclusionFactor aoFactor = CreateAmbientOcclusionFactor(inputData, surfaceData);
uint meshRenderingLayers = GetMeshRenderingLayer();
Light mainLight = GetMainLight(inputData, shadowMask, aoFactor);
// NOTE: We don't apply AO to the GI here because it's done in the lighting calculation below...
MixRealtimeAndBakedGI(mainLight, inputData.normalWS, inputData.bakedGI);
//MixRealtimeAndBakedGI(mainLight, diffuseNormalWS, inputData.bakedGI);
LightingData lightingData = CreateLightingData(inputData, surfaceData);
lightingData.giColor = GlobalIllumination(
brdfData, inputData.bakedGI, aoFactor.indirectAmbientOcclusion,
inputData.positionWS, inputData.normalWS, inputData.viewDirectionWS, inputData.normalizedScreenSpaceUV, AmbientReflection
);
// Backscattering
#if defined(_BACKSCATTER) && !defined(DEBUG_DISPLAY)
lightingData.giColor += backScatter * SampleSH(-inputData.normalWS) * surfaceData.albedo * aoFactor.indirectAmbientOcclusion * translucency.x * subsurfaceColor * skinMask;
#endif
#if defined(_LIGHT_LAYERS)
if (IsMatchingLightLayer(mainLight.layerMask, meshRenderingLayers))
#endif
{
half3 mainLightColor = mainLight.color;
half NdotLUnclamped = dot(inputData.normalWS, mainLight.direction);
half NdotL = saturate( dot(inputData.normalWS, mainLight.direction) );
lightingData.mainLightColor = LightingPhysicallyBasedSkin(brdfData, mainLight, inputData.normalWS, inputData.viewDirectionWS, NdotL, NdotLUnclamped, curvature, skinMask);
// Subsurface Scattering
half transPower = translucency.y;
half3 transLightDir = mainLight.direction + inputData.normalWS * translucency.w;
half transDot = dot( transLightDir, -inputData.viewDirectionWS );
transDot = exp2(saturate(transDot) * transPower - transPower);
lightingData.mainLightColor += skinMask * subsurfaceColor * transDot * (1.0 - saturate(NdotLUnclamped)) * mainLightColor * lerp(1.0, mainLight.shadowAttenuation, translucency.z) * translucency.x;
}
#if defined(_ADDITIONAL_LIGHTS)
uint pixelLightCount = GetAdditionalLightsCount();
#if USE_FORWARD_PLUS
for (uint lightIndex = 0; lightIndex < min(URP_FP_DIRECTIONAL_LIGHTS_COUNT, MAX_VISIBLE_LIGHTS); lightIndex++)
{
FORWARD_PLUS_SUBTRACTIVE_LIGHT_CHECK
Light light = GetAdditionalLight(lightIndex, inputData, shadowMask, aoFactor);
#ifdef _LIGHT_LAYERS
if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers))
#endif
{
half3 lightColor = light.color;
half NdotLUnclamped = dot(inputData.normalWS, light.direction);
half NdotL = saturate( dot(inputData.normalWS, light.direction) );
lightingData.additionalLightsColor += LightingPhysicallyBasedSkin(brdfData, light, inputData.normalWS, inputData.viewDirectionWS, NdotL, NdotLUnclamped, curvature, skinMask);
// Subsurface Scattering
int index = lightIndex;
half4 shadowParams = GetAdditionalLightShadowParams(index);
#if !defined(ADDITIONAL_LIGHT_CALCULATE_SHADOWS)
lightColor *= lerp(1, 0, maskbyshadowstrength);
#else
// half isPointLight = shadowParams.z;
lightColor *= lerp(1, shadowParams.x, maskbyshadowstrength);
#endif
half transPower = translucency.y;
half3 transLightDirA = light.direction + inputData.normalWS * translucency.w;
half transDotA = dot( transLightDirA, -inputData.viewDirectionWS );
transDotA = exp2(saturate(transDotA) * transPower - transPower);
lightingData.additionalLightsColor += skinMask * subsurfaceColor * transDotA * (1.0 - saturate(NdotLUnclamped)) * lightColor * lerp(1.0, light.shadowAttenuation, translucency.z) * light.distanceAttenuation * translucency.x;
}
}
#endif
LIGHT_LOOP_BEGIN(pixelLightCount)
Light light = GetAdditionalLight(lightIndex, inputData, shadowMask, aoFactor);
#if defined(_LIGHT_LAYERS)
if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers))
#endif
{
half3 lightColor = light.color;
half NdotLUnclamped = dot(inputData.normalWS, light.direction);
half NdotL = saturate( dot(inputData.normalWS, light.direction) );
lightingData.additionalLightsColor += LightingPhysicallyBasedSkin(brdfData, light, inputData.normalWS, inputData.viewDirectionWS, NdotL, NdotLUnclamped, curvature, skinMask);
// Subsurface Scattering
int index = lightIndex;
//int index = GetPerObjectLightIndex(lightIndex);
half4 shadowParams = GetAdditionalLightShadowParams(index);
#if !defined(ADDITIONAL_LIGHT_CALCULATE_SHADOWS)
lightColor *= lerp(1, 0, maskbyshadowstrength);
#else
// half isPointLight = shadowParams.z;
lightColor *= lerp(1, shadowParams.x, maskbyshadowstrength);
#endif
half transPower = translucency.y;
half3 transLightDirA = light.direction + inputData.normalWS * translucency.w;
half transDotA = dot( transLightDirA, -inputData.viewDirectionWS );
transDotA = exp2(saturate(transDotA) * transPower - transPower);
lightingData.additionalLightsColor += skinMask * subsurfaceColor * transDotA * (1.0 - saturate(NdotLUnclamped)) * lightColor * lerp(1.0, light.shadowAttenuation, translucency.z) * light.distanceAttenuation * translucency.x;
}
LIGHT_LOOP_END
#endif
#ifdef _ADDITIONAL_LIGHTS_VERTEX
lightingData.vertexLightingColor += inputData.vertexLighting * brdfData.diffuse;
#endif
return CalculateFinalColor(lightingData, surfaceData.alpha);
}
#endif
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/EntityLighting.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/ImageBasedLighting.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl"
// Ref: https://knarkowicz.wordpress.com/2018/01/04/cloth-shading/
real D_CharlieNoPI_Lux(real NdotH, real roughness)
{
float invR = rcp(roughness);
float cos2h = NdotH * NdotH;
float sin2h = 1.0 - cos2h;
// Note: We have sin^2 so multiply by 0.5 to cancel it
return (2.0 + invR) * PositivePow(sin2h, invR * 0.5) / 2.0;
}
/* real D_Charlie_Lux(real NdotH, real roughness)
{
return INV_PI * D_CharlieNoPI_Lux(NdotH, roughness);
} */
// We use V_Ashikhmin instead of V_Charlie in practice for game due to the cost of V_Charlie
real V_Ashikhmin_Lux(real NdotL, real NdotV)
{
// Use soft visibility term introduce in: Crafting a Next-Gen Material Pipeline for The Order : 1886
return 1.0 / (4.0 * (NdotL + NdotV - NdotL * NdotV));
}
// A diffuse term use with fabric done by tech artist - empirical
real FabricLambertNoPI_Lux(real roughness)
{
return lerp(1.0, 0.5, roughness);
}
real FabricLambert_Lux(real roughness)
{
return INV_PI * FabricLambertNoPI_Lux(roughness);
}
// ---------
struct AdditionalData {
half3 tangentWS;
half3 bitangentWS;
float partLambdaV;
half roughnessT;
half roughnessB;
half3 anisoReflectionNormal;
};
half3 DirectBDRF_LuxCloth(BRDFData brdfData, AdditionalData addData, half3 normalWS, half3 lightDirectionWS, half3 viewDirectionWS, half NdotL)
{
#ifndef _SPECULARHIGHLIGHTS_OFF
float3 lightDirectionWSFloat3 = float3(lightDirectionWS);
float3 halfDir = SafeNormalize(lightDirectionWSFloat3 + float3(viewDirectionWS));
float NoH = saturate(dot(float3(normalWS), halfDir));
half LoH = half(saturate(dot(lightDirectionWSFloat3, halfDir)));
half NdotV = saturate(dot(normalWS, viewDirectionWS ));
float3 tangentWS = float3(addData.tangentWS);
float3 bitangentWS = float3(addData.bitangentWS);
float TdotH = dot(tangentWS, halfDir);
float TdotL = dot(tangentWS, lightDirectionWSFloat3);
float BdotH = dot(bitangentWS, halfDir);
float BdotL = dot(bitangentWS, lightDirectionWSFloat3);
half3 F = F_Schlick(brdfData.specular, LoH); // 1.91: was float3
//float TdotV = dot(tangentWS, viewDirectionWS);
//float BdotV = dot(bitangentWS, viewDirectionWS);
float DV = DV_SmithJointGGXAniso(
TdotH, BdotH, NoH, NdotV, TdotL, BdotL, NdotL,
addData.roughnessT, addData.roughnessB, addData.partLambdaV
);
half3 specularLighting = F * DV;
//return float4(normalWS, 1);
return specularLighting + brdfData.diffuse;
#else
return brdfData.diffuse;
#endif
}
half3 LightingPhysicallyBased_LuxCloth(BRDFData brdfData, AdditionalData addData, half3 lightColor, half3 lightDirectionWS, half lightAttenuation, half3 normalWS, half3 viewDirectionWS, half NdotL)
{
half3 radiance = lightColor * (lightAttenuation * NdotL);
return DirectBDRF_LuxCloth(brdfData, addData, normalWS, lightDirectionWS, viewDirectionWS, NdotL) * radiance;
}
half3 LightingPhysicallyBased_LuxCloth(BRDFData brdfData, AdditionalData addData, Light light, half3 normalWS, half3 viewDirectionWS, half NdotL)
{
return LightingPhysicallyBased_LuxCloth(brdfData, addData, light.color, light.direction, light.distanceAttenuation * light.shadowAttenuation, normalWS, viewDirectionWS, NdotL);
}
// As we need both normals here - otherwise kept in sync with latest URP function
half3 GlobalIllumination_LuxAniso(BRDFData brdfData, BRDFData brdfDataClearCoat, float clearCoatMask,
half3 bakedGI, half occlusion, float3 positionWS,
half3 anisoReflectionNormal,
half3 normalWS, half3 viewDirectionWS, float2 normalizedScreenSpaceUV)
{
half3 reflectVector = reflect(-viewDirectionWS, anisoReflectionNormal);
half NoV = saturate(dot(normalWS, viewDirectionWS));
half fresnelTerm = Pow4(1.0 - NoV);
half3 indirectDiffuse = bakedGI;
half3 indirectSpecular = GlossyEnvironmentReflection(reflectVector, positionWS, brdfData.perceptualRoughness, 1.0h, normalizedScreenSpaceUV);
half3 color = EnvironmentBRDF(brdfData, indirectDiffuse, indirectSpecular, fresnelTerm);
if (IsOnlyAOLightingFeatureEnabled())
{
color = half3(1,1,1); // "Base white" for AO debug lighting mode
}
#if defined(_CLEARCOAT) || defined(_CLEARCOATMAP)
half3 coatIndirectSpecular = GlossyEnvironmentReflection(reflectVector, positionWS, brdfDataClearCoat.perceptualRoughness, 1.0h, normalizedScreenSpaceUV);
// TODO: "grazing term" causes problems on full roughness
half3 coatColor = EnvironmentBRDFClearCoat(brdfDataClearCoat, clearCoatMask, coatIndirectSpecular, fresnelTerm);
// Blend with base layer using khronos glTF recommended way using NoV
// Smooth surface & "ambiguous" lighting
// NOTE: fresnelTerm (above) is pow4 instead of pow5, but should be ok as blend weight.
half coatFresnel = kDielectricSpec.x + kDielectricSpec.a * fresnelTerm;
return (color * (1.0 - coatFresnel * clearCoatMask) + coatColor) * occlusion;
#else
return color * occlusion;
#endif
}
half4 LuxURPClothFragmentPBR(InputData inputData, SurfaceData surfaceData, half3 tangentWS, half anisotropy, half4 translucency, half metallic)
{
BRDFData brdfData;
InitializeBRDFData(surfaceData, brdfData);
// Do not apply energy conservtion
half oneMinusReflectivity = OneMinusReflectivityMetallic(surfaceData.metallic);
half reflectivity = half(1.0) - oneMinusReflectivity;
half3 brdfDiffuse = surfaceData.albedo * oneMinusReflectivity;
half3 brdfSpecular = lerp(kDieletricSpec.rgb * surfaceData.specular, surfaceData.albedo * metallic, surfaceData.metallic);
//half3 brdfSpecular = lerp(float3(1,0,0), float3(0,1,0), surfaceData.metallic);
brdfData.diffuse = brdfDiffuse;
brdfData.specular = brdfSpecular;
// Debugging
#if defined(DEBUG_DISPLAY)
half4 debugColor;
if (CanDebugOverrideOutputColor(inputData, surfaceData, brdfData, debugColor))
{
return debugColor;
}
#endif
AdditionalData addData;
tangentWS = Orthonormalize(tangentWS, inputData.normalWS);
addData.tangentWS = tangentWS;
addData.bitangentWS = cross(inputData.normalWS, tangentWS);
// We do not apply ClampRoughnessForAnalyticalLights here
addData.roughnessT = brdfData.roughness * (1 + anisotropy);
addData.roughnessB = brdfData.roughness * (1 - anisotropy);
float TdotV = dot(addData.tangentWS, inputData.viewDirectionWS);
float BdotV = dot(addData.bitangentWS, inputData.viewDirectionWS);
float NdotV = dot(inputData.normalWS, inputData.viewDirectionWS);
// partLambdaV should be 0.0f in case of cotton wool
addData.partLambdaV = GetSmithJointGGXAnisoPartLambdaV(TdotV, BdotV, NdotV, addData.roughnessT, addData.roughnessB);
half3 grainDirWS = (anisotropy >= 0.0) ? addData.bitangentWS : addData.tangentWS;
half stretch = abs(anisotropy) * saturate(1.5h * sqrt(brdfData.perceptualRoughness));
addData.anisoReflectionNormal = GetAnisotropicModifiedNormal(grainDirWS, inputData.normalWS, inputData.viewDirectionWS, stretch);
half iblPerceptualRoughness = brdfData.perceptualRoughness * saturate(1.2 - abs(anisotropy));
// Override perceptual roughness for ambient specular reflections
brdfData.perceptualRoughness = iblPerceptualRoughness;
// Only used for reflections - so we skip it
/*float3 preFGD = SAMPLE_TEXTURE2D_LOD(_PreIntegratedLUT, sampler_PreIntegratedLUT, float2(NdotV, brdfData.perceptualRoughness), 0).xyz;
// Denormalize the value
preFGD.y = preFGD.y / (1 - preFGD.y);
half3 specularFGD = preFGD.yyy * fresnel0;
// z = FabricLambert
half3 diffuseFGD = preFGD.z;
half reflectivity = preFGD.y;*/
half4 shadowMask = CalculateShadowMask(inputData);
AmbientOcclusionFactor aoFactor = CreateAmbientOcclusionFactor(inputData, surfaceData);
uint meshRenderingLayers = GetMeshRenderingLayer();
Light mainLight = GetMainLight(inputData, shadowMask, aoFactor);
half3 mainLightColor = mainLight.color;
MixRealtimeAndBakedGI(mainLight, inputData.normalWS, inputData.bakedGI);
LightingData lightingData = CreateLightingData(inputData, surfaceData);
// NOTE: We use addData.anisoReflectionNormal here!
lightingData.giColor = GlobalIllumination_LuxAniso(
brdfData,
brdfData, // brdfDataClearCoat
0, // surfaceData.clearCoatMask,
inputData.bakedGI,
aoFactor.indirectAmbientOcclusion,
inputData.positionWS,
addData.anisoReflectionNormal,
inputData.normalWS,
inputData.viewDirectionWS,
inputData.normalizedScreenSpaceUV
);
half NdotL;
#if defined(_LIGHT_LAYERS)
if (IsMatchingLightLayer(mainLight.layerMask, meshRenderingLayers))
#endif
{
NdotL = saturate(dot(inputData.normalWS, mainLight.direction ));
lightingData.mainLightColor = LightingPhysicallyBased_LuxCloth(brdfData, addData, mainLight, inputData.normalWS, inputData.viewDirectionWS, NdotL);
}
#ifdef _ADDITIONAL_LIGHTS
uint pixelLightCount = GetAdditionalLightsCount();
#if USE_FORWARD_PLUS
for (uint lightIndex = 0; lightIndex < min(URP_FP_DIRECTIONAL_LIGHTS_COUNT, MAX_VISIBLE_LIGHTS); lightIndex++)
{
FORWARD_PLUS_SUBTRACTIVE_LIGHT_CHECK
Light light = GetAdditionalLight(lightIndex, inputData, shadowMask, aoFactor);
#ifdef _LIGHT_LAYERS
if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers))
#endif
{
half3 lightColor = light.color;
NdotL = saturate(dot(inputData.normalWS, light.direction ));
lightingData.additionalLightsColor += LightingPhysicallyBased_LuxCloth(brdfData, addData, light, inputData.normalWS, inputData.viewDirectionWS, NdotL);
}
}
#endif
LIGHT_LOOP_BEGIN(pixelLightCount)
Light light = GetAdditionalLight(lightIndex, inputData, shadowMask, aoFactor);
#if defined(_LIGHT_LAYERS)
if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers))
#endif
{
half3 lightColor = light.color;
NdotL = saturate(dot(inputData.normalWS, light.direction ));
lightingData.additionalLightsColor += LightingPhysicallyBased_LuxCloth(brdfData, addData, light, inputData.normalWS, inputData.viewDirectionWS, NdotL);
}
LIGHT_LOOP_END
#endif
#ifdef _ADDITIONAL_LIGHTS_VERTEX
lightingData.vertexLightingColor += inputData.vertexLighting * brdfData.diffuse;
#endif
//return float4(inputData.normalTS, 1);
return CalculateFinalColor(lightingData, surfaceData.alpha);
//return brdfData.perceptualRoughness;
}