Files
beyond/Assets/ThirdParty/Lux URP Essentials/Shaders/Includes/Lux URP Cloth Lighting.hlsl
2024-11-20 15:21:28 +01:00

240 lines
10 KiB
HLSL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// NOTE: Based on URP Lighting.hlsl which replaced some half3 with floats to avoid lighting artifacts on mobile
// Hair lighting functions renamed to solves problems with LWRP 6.x
// https://google.github.io/filament/Filament.md.html#materialsystem/clothmodel
// SheenColor
#ifndef LIGHTWEIGHT_CLOTHLIGHTING_INCLUDED
#define LIGHTWEIGHT_CLOTHLIGHTING_INCLUDED
#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"
// --------- rename!!!!!!!!!
// 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 sheenColor;
};
half3 DirectBDRF_LuxCloth(BRDFData brdfData, AdditionalData addData, half3 normalWS, half3 lightDirectionWS, half3 viewDirectionWS, half NdotL)
{
#ifndef _SPECULARHIGHLIGHTS_OFF
float3 halfDir = SafeNormalize(lightDirectionWS + viewDirectionWS);
float NoH = saturate(dot(normalWS, halfDir));
half LoH = saturate(dot(lightDirectionWS, halfDir));
half NdotV = saturate(dot(normalWS, viewDirectionWS ));
#if defined(_COTTONWOOL)
// NOTE: We use the noPI version here!!!!!!
float D = D_CharlieNoPI_Lux(NoH, brdfData.roughness);
// Unity: V_Charlie is expensive, use approx with V_Ashikhmin instead
// Unity: float Vis = V_Charlie(NdotL, NdotV, bsdfData.roughness);
float Vis = V_Ashikhmin_Lux(NdotL, NdotV);
// Unity: Fabrics are dieletric but we simulate forward scattering effect with colored specular (fuzz tint term)
// Unity: We don't use Fresnel term for CharlieD
// SheenColor seemed way too dark (compared to HDRP) so i multiply it with PI which looked ok and somehow matched HDRP
// Therefore we use the noPI charlie version. As PI is a constant factor the artists can tweak the look by adjusting the sheen color.
float3 F = addData.sheenColor; // * PI;
half3 specularLighting = F * Vis * D;
// Unity: Note: diffuseLighting originally is multiply by color in PostEvaluateBSDF
// So we do it here :)
// Using saturate to get rid of artifacts around the borders.
return saturate(specularLighting) + brdfData.diffuse * FabricLambert_Lux(brdfData.roughness);
#else
float TdotH = dot(addData.tangentWS, halfDir);
float TdotL = dot(addData.tangentWS, lightDirectionWS);
float BdotH = dot(addData.bitangentWS, halfDir);
float BdotL = dot(addData.bitangentWS, lightDirectionWS);
float3 F = F_Schlick(brdfData.specular, LoH);
//float TdotV = dot(addData.tangentWS, viewDirectionWS);
//float BdotV = dot(addData.bitangentWS, viewDirectionWS);
float DV = DV_SmithJointGGXAniso(
TdotH, BdotH, NoH, NdotV, TdotL, BdotL, NdotL,
addData.roughnessT, addData.roughnessB, addData.partLambdaV
);
// Check NdotL gets factores in outside as well.. correct?
half3 specularLighting = F * DV;
return specularLighting + brdfData.diffuse;
#endif
//half3 color = specularTerm * brdfData.specular + brdfData.diffuse;
//return color;
#else
return brdfData.diffuse;
#endif
}
half3 LightingPhysicallyBased_LuxCloth(BRDFData brdfData, AdditionalData addData, half3 lightColor, half3 lightDirectionWS, half lightAttenuation, half3 normalWS, half3 viewDirectionWS, half NdotL)
{
//half NdotL = saturate(dot(normalWS, lightDirectionWS));
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);
}
half4 LuxURPClothFragmentPBR(InputData inputData, half3 albedo, half metallic, half3 specular,
half smoothness, half occlusion, half3 emission, half alpha, half3 tangentWS, half anisotropy, half3 sheenColor, half4 translucency)
{
#if defined(_COTTONWOOL)
smoothness = lerp(0.0h, 0.6h, smoothness);
#endif
BRDFData brdfData;
InitializeBRDFData(albedo, metallic, specular, smoothness, alpha, brdfData);
// Do not apply energy conservtion
brdfData.diffuse = albedo;
brdfData.specular = specular;
AdditionalData addData;
// Adjust tangentWS in case normal mapping is active
#if defined(_NORMALMAP)
tangentWS = Orthonormalize(tangentWS, inputData.normalWS);
#endif
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);
#if !defined(_COTTONWOOL)
float TdotV = dot(addData.tangentWS, inputData.viewDirectionWS);
float BdotV = dot(addData.bitangentWS, inputData.viewDirectionWS);
float NdotV = dot(inputData.normalWS, inputData.viewDirectionWS);
addData.partLambdaV = GetSmithJointGGXAnisoPartLambdaV(TdotV, BdotV, NdotV, addData.roughnessT, addData.roughnessB);
// Set reflection normal and roughness derived from GetGGXAnisotropicModifiedNormalAndRoughness
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));
// Overwrite perceptual roughness for ambient specular reflections
brdfData.perceptualRoughness = iblPerceptualRoughness;
#else
// partLambdaV should be 0.0f in case of cotton wool
addData.partLambdaV = 0.0h;
addData.anisoReflectionNormal = inputData.normalWS;
float NdotV = dot(inputData.normalWS, inputData.viewDirectionWS);
// 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;*/
#endif
addData.sheenColor = sheenColor;
Light mainLight = GetMainLight(inputData.shadowCoord);
MixRealtimeAndBakedGI(mainLight, inputData.normalWS, inputData.bakedGI, half4(0, 0, 0, 0));
half NdotL = saturate(dot(inputData.normalWS, mainLight.direction ));
half3 color = GlobalIllumination(brdfData, inputData.bakedGI, occlusion, addData.anisoReflectionNormal, inputData.viewDirectionWS);
color += LightingPhysicallyBased_LuxCloth(brdfData, addData, mainLight, inputData.normalWS, inputData.viewDirectionWS, NdotL);
#if defined(_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);
color += brdfData.diffuse * transDot * (1.0 - NdotL) * mainLight.color * lerp(1.0h, mainLight.shadowAttenuation, translucency.z) * translucency.x * 4;
#endif
#ifdef _ADDITIONAL_LIGHTS
uint pixelLightCount = GetAdditionalLightsCount();
for (uint i = 0u; i < pixelLightCount; ++i)
{
Light light = GetAdditionalLight(i, inputData.positionWS);
NdotL = saturate(dot(inputData.normalWS, light.direction ));
color += LightingPhysicallyBased_LuxCloth(brdfData, addData, light, inputData.normalWS, inputData.viewDirectionWS, NdotL);
// translucency
#if defined(_SCATTERING)
transPower = translucency.y;
transLightDir = light.direction + inputData.normalWS * translucency.w;
transDot = dot( transLightDir, -inputData.viewDirectionWS );
transDot = exp2(saturate(transDot) * transPower - transPower);
color += brdfData.diffuse * transDot * (1.0 - NdotL) * light.color * lerp(1.0h, light.shadowAttenuation, translucency.z) * light.distanceAttenuation * translucency.x * 4;
#endif
}
#endif
#ifdef _ADDITIONAL_LIGHTS_VERTEX
color += inputData.vertexLighting * brdfData.diffuse;
#endif
color += emission;
return half4(color, alpha);
}
#endif