#pragma kernel RaytracingDeferred RAYTRACING_DEFERRED=RaytracingDeferred #pragma kernel RaytracingDeferredHalf RAYTRACING_DEFERRED=RaytracingDeferredHalf HALF_RESOLUTION #pragma kernel RaytracingDiffuseDeferred // Given that the algorithm requires BSDF evaluation, we need to define this macro #define HAS_LIGHTLOOP // Environment data that need to be used, is from WorldLights #define WORLD_ENVIRONMENT_DATA // If you need to change this, be sure to read this comment. // For raytracing we decided to force the shadow quality to low. // - The performance is the first reason, given that it may happen during the ray tracing stage for indirect or in a non-tiled context for deferred // we want to save that cost as it may increase signfiicantly the cost.. // - The second reason is that some filtering modes require the screen space position (at the moment you read this comment high and ultra high), which we cannot provide // in a ray tracing context. // In addition to that, we intentionally disabled dithering for the ray tracing case as it requires the screen space position. #define SHADOW_LOW #pragma only_renderers d3d11 xboxseries ps5 // Needed for the ray miss and the last bounce indirect diffuse lighting #pragma multi_compile _ PROBE_VOLUMES_L1 PROBE_VOLUMES_L2 // Include and define the shader pass #include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPass.cs.hlsl" #define SHADERPASS SHADERPASS_RAYTRACING_INDIRECT // HDRP generic includes #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/Lighting.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Material.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoopDef.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/Lit.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/LitRayTracing.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/BuiltinGIUtilities.hlsl" #include "Packages/com.unity.render-pipelines.core/Runtime/Lighting/ProbeVolume/ProbeVolume.hlsl" // Ray tracing includes #include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/ShaderVariablesRaytracing.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/ShaderVariablesRaytracingLightLoop.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/RaytracingLightLoop.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Common/AtmosphericScatteringRayTracing.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/RayTracingFallbackHierarchy.cs.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/RayTracingCommon.hlsl" #define RAYTRACING_DEFERRED_TILE_SIZE 8 TEXTURE2D_X(_DepthTexture); TEXTURE2D_X(_RaytracingDirectionBuffer); TEXTURE2D_X(_RaytracingDistanceBuffer); RW_TEXTURE2D_X(float4, _RaytracingLitBufferRW); RW_TEXTURE2D_X(float, _RaytracingDistanceBufferRW); [numthreads(RAYTRACING_DEFERRED_TILE_SIZE, RAYTRACING_DEFERRED_TILE_SIZE, 1)] void RAYTRACING_DEFERRED(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 groupThreadId : SV_GroupThreadID, uint2 groupId : SV_GroupID) { UNITY_XR_ASSIGN_VIEW_INDEX(dispatchThreadId.z); // Compute the pixel position to process uint2 currentCoord = groupId * RAYTRACING_DEFERRED_TILE_SIZE + groupThreadId; // Initialize the output buffer _RaytracingLitBufferRW[COORD_TEXTURE2D_X(currentCoord)] = float4(0.0, 0.0, 0.0, 0.0); _RaytracingDistanceBufferRW[COORD_TEXTURE2D_X(currentCoord)] = 0.0; #ifdef HALF_RESOLUTION currentCoord = ComputeSourceCoordinates(currentCoord, _RayTracingCheckerIndex); #endif // Read the depth value float depthValue = LOAD_TEXTURE2D_X(_DepthTexture, currentCoord).x; // If this is a background pixel or an invalid ray, leave right away if (depthValue == UNITY_RAW_FAR_CLIP_VALUE || LOAD_TEXTURE2D_X(_RaytracingDirectionBuffer, currentCoord).w < 0.0f) return; // First let's compute the position of the pixel from which the ray has been shot PositionInputs sourcePosInput = GetPositionInput(currentCoord, _ScreenSize.zw, depthValue, UNITY_MATRIX_I_VP, GetWorldToViewMatrix(), 0); // Fetch the intersection distance of the ray float rayDistance = LOAD_TEXTURE2D_X(_RaytracingDistanceBuffer, currentCoord).x; // Fetch the direction of the ray float3 rayDirection = LOAD_TEXTURE2D_X(_RaytracingDirectionBuffer, currentCoord).xyz; // if the distance is exactly zero, this means we are facing an environement ray that we need to evaluate float3 finalColor = 0.0f; bool rayIsSky = false; if (RayTracingGBufferIsSky(rayDistance)) { // Weight value used to do the blending float weight = 0.0; rayIsSky = true; // Read the pixel normal NormalData normalData; DecodeFromNormalBuffer(currentCoord.xy, normalData); #if defined(PROBE_VOLUMES_L1) || defined(PROBE_VOLUMES_L2) // Try the APV if enabled if(_EnableProbeVolumes && _RayTracingAPVRayMiss) { BuiltinData apvBuiltinData; ZERO_INITIALIZE(BuiltinData, apvBuiltinData); // Read from the APV EvaluateAdaptiveProbeVolume(GetAbsolutePositionWS(sourcePosInput.positionWS), normalData.normalWS, -normalData.normalWS, GetWorldSpaceNormalizeViewDir(sourcePosInput.positionWS), sourcePosInput.positionSS, _RaytracingAPVLayerMask, apvBuiltinData.bakeDiffuseLighting, apvBuiltinData.backBakeDiffuseLighting); // Not used // Propagate the value to the final color and set the weight to 1.0 finalColor = apvBuiltinData.bakeDiffuseLighting; weight = 1.0; } #endif if ((RAYTRACINGFALLBACKHIERACHY_REFLECTION_PROBES & _RayTracingRayMissFallbackHierarchy) && weight < 1.0f) finalColor += RayTraceReflectionProbes(sourcePosInput.positionWS, rayDirection, weight); if((RAYTRACINGFALLBACKHIERACHY_SKY & _RayTracingRayMissFallbackHierarchy) && weight == 0.0f) { if(_RayTracingRayMissUseAmbientProbeAsSky) finalColor = EvaluateAmbientProbe(normalData.normalWS) * (1.0 - weight); else finalColor = SAMPLE_TEXTURECUBE_ARRAY_LOD(_SkyTexture, s_trilinear_clamp_sampler, rayDirection, 0.0, 0).xyz * (1.0 - weight); weight = 1.0; } if (weight > 0.0) { // Apply the fog attenuation ApplyFogAttenuation(sourcePosInput.positionWS, rayDirection, finalColor); // Apply the exposure finalColor *= GetCurrentExposureMultiplier(); // Only clamp if required if (_RayTracingClampingFlag) { // In the case of the sky we always want to operate the clamping in hsv space (reflections and indirect diffuse) finalColor = RayTracingHSVClamp(finalColor, _RaytracingIntensityClamp); } } } else if (RayTracingGBufferIsUnlit(rayDistance)) { finalColor = LOAD_TEXTURE2D_X(_GBufferTexture3, currentCoord).rgb; // Only clamp if required if (_RayTracingClampingFlag) { // Expose, clamp and inverse exposure. Though depending on the signal nature we go for different clamping strategies if (_RaytracingPreExposition) { // Clamp in HSV space finalColor = RayTracingHSVClamp(finalColor, _RaytracingIntensityClamp); } else { finalColor = clamp(finalColor, 0.0, _RaytracingIntensityClamp); } } // For unlit material, the distance is stored negatively so we need to apply an abs to it. rayDistance = abs(rayDistance); } // If the distance is negative, this means it is a sky pixel or an unlit material if (!RayTracingGBufferIsLit(rayDistance)) { #if defined(HALF_RESOLUTION) _RaytracingLitBufferRW[COORD_TEXTURE2D_X(currentCoord / 2)] = float4(finalColor * (_RaytracingPreExposition ? 1.0 : GetInverseCurrentExposureMultiplier()), 0.0); _RaytracingDistanceBufferRW[COORD_TEXTURE2D_X(currentCoord / 2)] = rayIsSky ? _RaytracingRayMaxLength : rayDistance; #else _RaytracingLitBufferRW[COORD_TEXTURE2D_X(currentCoord)] = float4(finalColor * (_RaytracingPreExposition ? 1.0 : GetInverseCurrentExposureMultiplier()), 0.0); _RaytracingDistanceBufferRW[COORD_TEXTURE2D_X(currentCoord)] = rayIsSky ? _RaytracingRayMaxLength : rayDistance; #endif return; } // Then compute the pos input of the intersection vertice float3 intersectionPositionWS = sourcePosInput.positionWS + rayDirection * rayDistance; PositionInputs posInput = GetPositionInput(currentCoord, _ScreenSize.zw, intersectionPositionWS); // Read the bsdf data and builtin data from the gbuffer BSDFData bsdfData; ZERO_INITIALIZE(BSDFData, bsdfData); BuiltinData builtinData; ZERO_INITIALIZE(BuiltinData, builtinData); uint featureFlags = UINT_MAX; DecodeFromGBuffer(currentCoord, featureFlags, bsdfData, builtinData); builtinData.renderingLayers = RENDERING_LAYERS_MASK; builtinData.shadowMask0 = 1.0; builtinData.shadowMask1 = 1.0; builtinData.shadowMask2 = 1.0; builtinData.shadowMask3 = 1.0; PreLightData preLightData = GetPreLightData(-rayDirection, posInput, bsdfData); // Fill the ray context RayContext rayContext; rayContext.reflection = 0.0; rayContext.reflectionWeight = 0.0; rayContext.transmission = 0.0; rayContext.transmissionWeight = 0.0; rayContext.useAPV = 1; // Evaluate the complete lighting LightLoopOutput lightLoopOutput; LightLoop(-rayDirection, posInput, preLightData, bsdfData, builtinData, rayContext, lightLoopOutput); // Alias float3 diffuseLighting = lightLoopOutput.diffuseLighting; float3 specularLighting = lightLoopOutput.specularLighting; finalColor = (diffuseLighting + specularLighting); // Apply fog attenuation ApplyFogAttenuation(sourcePosInput.positionWS, rayDirection, rayDistance, finalColor, true); // Only clamp if required if (_RayTracingClampingFlag) { // Expose, clamp and inverse exposure. Though depending on the signal nature we go for different clamping strategies if (_RaytracingPreExposition) { // Clamp in HSV space finalColor = RayTracingHSVClamp(finalColor * GetCurrentExposureMultiplier(), _RaytracingIntensityClamp); } else { finalColor = clamp(finalColor * GetCurrentExposureMultiplier(), 0.0, _RaytracingIntensityClamp) * GetInverseCurrentExposureMultiplier(); } } #if defined(HALF_RESOLUTION) _RaytracingLitBufferRW[COORD_TEXTURE2D_X(currentCoord / 2)] = float4(finalColor, 1.0); _RaytracingDistanceBufferRW[COORD_TEXTURE2D_X(currentCoord / 2)] = rayDistance; #else _RaytracingLitBufferRW[COORD_TEXTURE2D_X(currentCoord)] = float4(finalColor, 1.0); _RaytracingDistanceBufferRW[COORD_TEXTURE2D_X(currentCoord)] = rayDistance; #endif } // Input textures for the diffuse deferred lightloop that we will be executing // Position at the exit point TEXTURE2D_X(_PositionTextureRW); // Normal value at the exit point TEXTURE2D_X(_NormalTextureRW); // Direction value at the exit point TEXTURE2D_X(_DirectionTextureRW); // Diffuse lighting at the exit point TEXTURE2D_X(_DiffuseLightingTextureRW); // Through put of the walk that was calculated TEXTURE2D_X(_ThroughputTextureRW); [numthreads(RAYTRACING_DEFERRED_TILE_SIZE, RAYTRACING_DEFERRED_TILE_SIZE, 1)] void RaytracingDiffuseDeferred(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 groupThreadId : SV_GroupThreadID, uint2 groupId : SV_GroupID) { UNITY_XR_ASSIGN_VIEW_INDEX(dispatchThreadId.z); // Compute the pixel position to process uint2 currentCoord = groupId * RAYTRACING_DEFERRED_TILE_SIZE + groupThreadId; // Read the depth value float depthValue = LOAD_TEXTURE2D_X(_DepthTexture, currentCoord).x; if (depthValue == UNITY_RAW_FAR_CLIP_VALUE) return; // Read the throughput float3 throughput = LOAD_TEXTURE2D_X(_ThroughputTextureRW, currentCoord).xyz; // If the path is black, no need to light this if (length(throughput) == 0.0) { // Simply propagate the previous value float3 previousValue = _RaytracingLitBufferRW[COORD_TEXTURE2D_X(currentCoord)].xyz; _RaytracingLitBufferRW[COORD_TEXTURE2D_X(currentCoord)] = float4(previousValue, 0.0); return; } // Read the normal float3 normalWS = LOAD_TEXTURE2D_X(_NormalTextureRW, currentCoord).xyz; // Create our diffuse white BSDF Data BSDFData bsdfData; ZERO_INITIALIZE(BSDFData, bsdfData); bsdfData.materialFeatures = MATERIALFEATUREFLAGS_LIT_STANDARD; bsdfData.diffuseColor = float3(1.0, 1.0, 1.0); bsdfData.fresnel0 = DEFAULT_SPECULAR_VALUE; bsdfData.ambientOcclusion = 1.0; bsdfData.perceptualRoughness = 1.0; bsdfData.specularOcclusion = 1.0; bsdfData.normalWS = normalWS; bsdfData.geomNormalWS = normalWS; ConvertAnisotropyToRoughness(bsdfData.perceptualRoughness, bsdfData.anisotropy, bsdfData.roughnessT, bsdfData.roughnessB); // Create the built-in data BuiltinData builtinData; ZERO_INITIALIZE(BuiltinData, builtinData); builtinData.bakeDiffuseLighting = LOAD_TEXTURE2D_X(_DiffuseLightingTextureRW, currentCoord).xyz; // This also contain emissive (and * AO if no lightlayers) builtinData.renderingLayers = RENDERING_LAYERS_MASK; builtinData.shadowMask0 = 1.0; builtinData.shadowMask1 = 1.0; builtinData.shadowMask2 = 1.0; builtinData.shadowMask3 = 1.0; // We are evaluating a diffuse signal so view does not matter, let's pick the one that is guaranteed to be right (for some reason the LTC code fails if V == N) float3 viewWS = LOAD_TEXTURE2D_X(_DirectionTextureRW, currentCoord).xyz; float3 intersectionPositionWS = LOAD_TEXTURE2D_X(_PositionTextureRW, currentCoord).xyz; // Create the pos input PositionInputs posInput = GetPositionInput(currentCoord, _ScreenSize.zw, intersectionPositionWS); // Compute the prelight data PreLightData preLightData = GetPreLightData(viewWS, posInput, bsdfData); // Fill the ray context RayContext rayContext; rayContext.reflection = 0.0; rayContext.reflectionWeight = 0.0; rayContext.transmission = 0.0; rayContext.transmissionWeight = 0.0; rayContext.useAPV = 1; // Evaluate lighting LightLoopOutput lightLoopOutput; LightLoop(viewWS, posInput, preLightData, bsdfData, builtinData, rayContext, lightLoopOutput); // Alias float3 diffuseLighting = lightLoopOutput.diffuseLighting; float3 specularLighting = lightLoopOutput.specularLighting; // Read the previous value and combine with the current lighting float3 previousValue = _RaytracingLitBufferRW[COORD_TEXTURE2D_X(currentCoord)].xyz; _RaytracingLitBufferRW[COORD_TEXTURE2D_X(currentCoord)] = float4(previousValue + throughput * diffuseLighting, 1.0); }