231 lines
9.5 KiB
HLSL
231 lines
9.5 KiB
HLSL
#ifndef UTS_ENV
|
|
#define UTS_ENV
|
|
|
|
#include "Packages/com.misaki.hdrp-toon/Runtime/HDRP/Shaders/Includes/Common/UtsCommon.hlsl"
|
|
|
|
// _preIntegratedFGD and _CubemapLD are unique for each BRDF
|
|
float3 EvaluateBSDF_ReflectionProbe(LightLoopContext lightLoopContext,
|
|
float3 V, PositionInputs posInput,
|
|
PreLightData preLightData, EnvLightData lightData, UtsBSDFData bsdfData,
|
|
int influenceShapeType,
|
|
inout float hierarchyWeight)
|
|
{
|
|
float weight = 1.0;
|
|
|
|
float3 R = reflect(-V, bsdfData.normalWS);
|
|
|
|
EvaluateLight_EnvIntersection(posInput.positionWS, bsdfData.normalWS, lightData, influenceShapeType, R, weight);
|
|
|
|
// No distance based roughness for simple lit
|
|
float4 preLD = SampleEnv(lightLoopContext, lightData.envIndex, R, PerceptualRoughnessToMipmapLevel(preLightData.iblPerceptualRoughness) * lightData.roughReflections, lightData.rangeCompressionFactorCompensation, posInput.positionNDC);
|
|
weight *= preLD.a; // Used by planar reflection to discard pixel
|
|
|
|
//envLighting = F_Schlick(bsdfData.fresnel0, dot(bsdfData.normalWS, V)) * preLD.rgb;
|
|
float3 envLighting = preLD.rgb;
|
|
|
|
UpdateLightingHierarchyWeights(hierarchyWeight, weight);
|
|
envLighting *= weight * lightData.multiplier;
|
|
|
|
return envLighting;
|
|
}
|
|
|
|
float4 ComputeReflection(LightLoopContext context, PositionInputs posInput, PreLightData preLightData, BuiltinData builtinData, UtsBSDFData bsdfData, float3 V)
|
|
{
|
|
float3 refcolor = 0;
|
|
float reflectionHierarchyWeight = 0.0; // Max: 1.0
|
|
|
|
uint envLightStart, envLightCount;
|
|
|
|
// Fetch first env light to provide the scene proxy for screen space computation
|
|
#ifndef LIGHTLOOP_DISABLE_TILE_AND_CLUSTER
|
|
GetCountAndStart(posInput, LIGHTCATEGORY_ENV, envLightStart, envLightCount);
|
|
#else // LIGHTLOOP_DISABLE_TILE_AND_CLUSTER
|
|
envLightCount = _EnvLightCount;
|
|
envLightStart = 0;
|
|
#endif
|
|
|
|
bool fastPath = false;
|
|
#if SCALARIZE_LIGHT_LOOP
|
|
uint envStartFirstLane;
|
|
fastPath = IsFastPath(envLightStart, envStartFirstLane);
|
|
#endif
|
|
|
|
context.sampleReflection = SINGLE_PASS_CONTEXT_SAMPLE_REFLECTION_PROBES;
|
|
|
|
#if SCALARIZE_LIGHT_LOOP
|
|
if (fastPath)
|
|
{
|
|
envLightStart = envStartFirstLane;
|
|
}
|
|
#endif
|
|
|
|
// Scalarized loop, same rationale of the punctual light version
|
|
uint v_envLightListOffset = 0;
|
|
uint v_envLightIdx = envLightStart;
|
|
#if NEED_TO_CHECK_HELPER_LANE
|
|
// On some platform helper lanes don't behave as we'd expect, therefore we prevent them from entering the loop altogether.
|
|
// IMPORTANT! This has implications if ddx/ddy is used on results derived from lighting, however given Lightloop is called in compute we should be
|
|
// sure it will not happen.
|
|
bool isHelperLane = WaveIsHelperLane();
|
|
while (!isHelperLane && v_envLightListOffset < envLightCount)
|
|
#else
|
|
while (v_envLightListOffset < envLightCount)
|
|
#endif
|
|
{
|
|
v_envLightIdx = FetchIndex(envLightStart, v_envLightListOffset);
|
|
#if SCALARIZE_LIGHT_LOOP
|
|
uint s_envLightIdx = ScalarizeElementIndex(v_envLightIdx, fastPath);
|
|
#else
|
|
uint s_envLightIdx = v_envLightIdx;
|
|
#endif
|
|
if (s_envLightIdx == -1)
|
|
break;
|
|
|
|
EnvLightData s_envLightData = FetchEnvLight(s_envLightIdx); // Scalar load.
|
|
|
|
// If current scalar and vector light index match, we process the light. The v_envLightListOffset for current thread is increased.
|
|
// Note that the following should really be ==, however, since helper lanes are not considered by WaveActiveMin, such helper lanes could
|
|
// end up with a unique v_envLightIdx value that is smaller than s_envLightIdx hence being stuck in a loop. All the active lanes will not have this problem.
|
|
if (s_envLightIdx >= v_envLightIdx)
|
|
{
|
|
v_envLightListOffset++;
|
|
if (reflectionHierarchyWeight < 1.0)
|
|
{
|
|
if (IsMatchingLightLayer(s_envLightData.lightLayers, builtinData.renderingLayers))
|
|
{
|
|
float RefProbeLighting = EvaluateBSDF_ReflectionProbe(context, V, posInput, preLightData, s_envLightData, bsdfData, s_envLightData.influenceShapeType, reflectionHierarchyWeight);
|
|
#if defined(PROBE_VOLUMES_L1) || defined(PROBE_VOLUMES_L2)
|
|
float3 lightInReflDir = float3(-1, -1, -1);
|
|
if (s_envLightData.normalizeWithAPV > 0 && all(lightInReflDir >= 0))
|
|
{
|
|
float factor = GetReflectionProbeNormalizationFactor(lightInReflDir, bsdfData.normalWS, s_envLightData.L0L1, s_envLightData.L2_1, s_envLightData.L2_2);
|
|
RefProbeLighting *= factor;
|
|
}
|
|
#endif
|
|
refcolor += RefProbeLighting;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return float4(refcolor.r, refcolor.g, refcolor.b, reflectionHierarchyWeight);
|
|
}
|
|
|
|
float3 ComputeFresnelLerp(float3 c0, float3 c1, float cosA)
|
|
{
|
|
float t = pow(1 - cosA, 5);
|
|
return lerp(c0, c1, t);
|
|
}
|
|
|
|
float3 EvaluateIndirectDiffusePBR(PositionInputs posInput, UtsBSDFData bsdfData, float3 V)
|
|
{
|
|
float3 indirectDiffuse = 0.0;
|
|
|
|
#ifdef _PBR_Mode_ANISO
|
|
GetGGXAnisotropicModifiedNormalAndRoughness(bsdfData.bitangentWS, bsdfData.tangentWS , bsdfData.normalWS, V, bsdfData.anisotropy, bsdfData.perceptualRoughness, bsdfData.normalWS, bsdfData.perceptualRoughness);
|
|
#endif
|
|
|
|
float NdotV = saturate(dot(bsdfData.normalWS, V));
|
|
|
|
#if defined(PROBE_VOLUMES_L1) || defined(PROBE_VOLUMES_L2)
|
|
BuiltinData apvBuiltinData;
|
|
ZERO_INITIALIZE(BuiltinData, apvBuiltinData);
|
|
|
|
#if defined(_PBR_Mode_OFF) || defined(_PBR_Mode_TOON)
|
|
EvaluateAdaptiveProbeVolume(GetAbsolutePositionWS(posInput.positionWS), 0.0, 0.0, V, posInput.positionSS, apvBuiltinData.bakeDiffuseLighting, apvBuiltinData.backBakeDiffuseLighting);
|
|
#else
|
|
EvaluateAdaptiveProbeVolume(GetAbsolutePositionWS(posInput.positionWS), bsdfData.normalWS, -bsdfData.normalWS, V, posInput.positionSS, apvBuiltinData.bakeDiffuseLighting, apvBuiltinData.backBakeDiffuseLighting);
|
|
#endif
|
|
|
|
float3 probeDiffuse = apvBuiltinData.bakeDiffuseLighting * GetCurrentExposureMultiplier();
|
|
|
|
indirectDiffuse = probeDiffuse;
|
|
#else
|
|
#if defined(_PBR_Mode_OFF) || defined(_PBR_Mode_TOON)
|
|
indirectDiffuse = EvaluateAmbientProbe(0.0) * GetCurrentExposureMultiplier();
|
|
#else
|
|
indirectDiffuse = EvaluateAmbientProbe(bsdfData.normalWS) * GetCurrentExposureMultiplier();
|
|
#endif
|
|
#endif
|
|
|
|
//SSGI
|
|
if(_ReceivesSSGI == 1)
|
|
{
|
|
float4 ssgiLighting = LOAD_TEXTURE2D_X(_IndirectDiffuseTexture, posInput.positionSS);
|
|
ssgiLighting *= _GIMultiplier;
|
|
indirectDiffuse = lerp(indirectDiffuse, ssgiLighting.rgb, ssgiLighting.a);
|
|
}
|
|
|
|
//Complete the indirect lighting
|
|
indirectDiffuse *= bsdfData.diffuseColor.rgb * _BaseColor.rgb;
|
|
|
|
//SSAO
|
|
if(_ReceivesSSAO == 1)
|
|
{
|
|
AmbientOcclusionFactor aoFactor;
|
|
GetScreenSpaceAmbientOcclusionMultibounce(posInput.positionSS, NdotV, bsdfData.perceptualRoughness, bsdfData.ambientOcclusion, bsdfData.specularOcclusion, bsdfData.diffuseColor, bsdfData.fresnel0, aoFactor);
|
|
indirectDiffuse *= lerp(_AO_Factor, 1, aoFactor.indirectAmbientOcclusion);
|
|
}
|
|
indirectDiffuse *= bsdfData.ambientOcclusion;
|
|
|
|
return indirectDiffuse;
|
|
}
|
|
|
|
float3 EvaluateIndirectDiffuse(PositionInputs posInput, UtsBSDFData bsdfData, float3 V)
|
|
{
|
|
float3 indirectDiffuse = 0.0;
|
|
|
|
indirectDiffuse = EvaluateIndirectDiffusePBR(posInput, bsdfData,V);
|
|
|
|
return indirectDiffuse * _ID_Intensity;
|
|
}
|
|
|
|
float3 EvaluateIndirectSpecular(LightLoopContext lightLoopContext, PositionInputs posInput, PreLightData preLightData, UtsBSDFData bsdfData, BuiltinData builtinData, float3 V)
|
|
{
|
|
#if defined(_PBR_Mode_OFF) || defined(_PBR_Mode_TOON)
|
|
return 0;
|
|
#else
|
|
float3 indirectSpecular = 0;
|
|
|
|
#ifdef _PBR_Mode_ANISO
|
|
GetGGXAnisotropicModifiedNormalAndRoughness(bsdfData.bitangentWS, bsdfData.tangentWS , bsdfData.normalWS, V, bsdfData.anisotropy, bsdfData.perceptualRoughness, bsdfData.normalWS, bsdfData.perceptualRoughness);
|
|
#endif
|
|
|
|
float mip = PerceptualRoughnessToMipmapLevel(bsdfData.perceptualRoughness);
|
|
float NdotV = saturate(dot(bsdfData.normalWS, V));
|
|
|
|
indirectSpecular = SampleSkyTexture(reflect(-V, bsdfData.normalWS), mip, 0).rgb;\
|
|
|
|
//Reflection Probe
|
|
float4 refProbe = ComputeReflection(lightLoopContext, posInput, preLightData, builtinData, bsdfData, V);
|
|
indirectSpecular = lerp(indirectSpecular, refProbe.rgb, refProbe.a);
|
|
|
|
//SSR
|
|
if(_ReceivesSSR == 1)
|
|
{
|
|
float4 ssrLighting = LOAD_TEXTURE2D_X(_SsrLightingTexture, posInput.positionSS);
|
|
InversePreExposeSsrLighting(ssrLighting);
|
|
ApplyScreenSpaceReflectionWeight(ssrLighting);
|
|
indirectSpecular = lerp(indirectSpecular, ssrLighting.rgb * preLightData.specularFGD, ssrLighting.a);
|
|
}
|
|
|
|
//Complete the indirect lighting
|
|
float grazingTerm = saturate((1 - bsdfData.perceptualRoughness) + (1 - bsdfData.reflectivity));
|
|
indirectSpecular *= ComputeFresnelLerp(bsdfData.fresnel0, grazingTerm, NdotV) * GetCurrentExposureMultiplier();
|
|
|
|
// Occlusion
|
|
if(_ReceivesSSAO == 1)
|
|
{
|
|
AmbientOcclusionFactor aoFactor;
|
|
GetScreenSpaceAmbientOcclusionMultibounce(posInput.positionSS, NdotV, bsdfData.perceptualRoughness, bsdfData.ambientOcclusion, bsdfData.specularOcclusion, bsdfData.diffuseColor, bsdfData.fresnel0, aoFactor);
|
|
|
|
indirectSpecular *= lerp(_AO_Factor, 1, aoFactor.indirectSpecularOcclusion);
|
|
}
|
|
indirectSpecular *= bsdfData.specularOcclusion;
|
|
|
|
return indirectSpecular * _IR_Intensity;
|
|
#endif
|
|
}
|
|
|
|
#endif |