#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