TextureHandle RaytracingRecursiveRender(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle colorBuffer, TextureHandle depthPyramid, TextureHandle flagMask, TextureHandle rayCountTexture) { // If ray tracing is disabled in the frame settings or the effect is not enabled RecursiveRendering recursiveSettings = hdCamera.volumeStack.GetComponent <RecursiveRendering>(); if (!hdCamera.frameSettings.IsEnabled(FrameSettingsField.RayTracing) || !recursiveSettings.enable.value) { return(colorBuffer); } // Build the parameter structure RecursiveRendererParameters rrParams = PrepareRecursiveRendererParameters(hdCamera, recursiveSettings); using (var builder = renderGraph.AddRenderPass <RecursiveRenderingPassData>("Recursive Rendering Evaluation", out var passData, ProfilingSampler.Get(HDProfileId.RayTracingRecursiveRendering))) { builder.EnableAsyncCompute(false); passData.parameters = rrParams; passData.depthStencilBuffer = builder.ReadTexture(depthPyramid); passData.flagMask = builder.ReadTexture(flagMask); passData.rayCountTexture = builder.ReadWriteTexture(rayCountTexture); passData.outputBuffer = builder.ReadWriteTexture(colorBuffer); // Right now the debug buffer is written to independently of what is happening. This must be changed // TODO RENDERGRAPH passData.debugBuffer = builder.WriteTexture(renderGraph.CreateTexture(new TextureDesc(Vector2.one, true, true) { colorFormat = GraphicsFormat.R16G16B16A16_SFloat, enableRandomWrite = true, name = "Recursive Rendering Debug Texture" })); builder.SetRenderFunc( (RecursiveRenderingPassData data, RenderGraphContext ctx) => { RecursiveRendererResources rrResources = new RecursiveRendererResources(); rrResources.depthStencilBuffer = data.depthStencilBuffer; rrResources.flagMask = data.flagMask; rrResources.debugBuffer = data.debugBuffer; rrResources.rayCountTexture = data.rayCountTexture; rrResources.outputBuffer = data.outputBuffer; ExecuteRecursiveRendering(ctx.cmd, data.parameters, rrResources); }); PushFullScreenDebugTexture(m_RenderGraph, passData.debugBuffer, FullScreenDebugMode.RecursiveRayTracing); return(passData.outputBuffer); } }
// Recursive rendering works as follow: // - Shader have a _RayTracing property // When this property is setup to true, a RayTracingPrepass pass on the material is enabled (otherwise it is disabled) // - Before prepass we render all object with a RayTracingPrepass pass enabled into the depth buffer for performance saving. // Note that we will exclude from the rendering of DepthPrepass, GBuffer and Forward pass the raytraced objects but not from // motion vector pass, so we can still benefit from motion vector. This is handled in VertMesh.hlsl (see below). // However currently when rendering motion vector this will tag the stencil for deferred lighting, and thus could produce overshading. // - After Transparent Depth pass we render all object with a RayTracingPrepass pass enabled into output a mask buffer (need to depth test but not to write depth) // Note: we render two times: one to save performance and the other to write the mask, otherwise if we write the mask in the first pass it // will not take into account the objects which could render on top of the raytracing one (If we want to do that we need to perform the pass after that // the depth buffer is ready, which is after the Gbuffer pass, so we can't save performance). // - During RaytracingRecursiveRender we perform a RayTracingRendering.raytrace call on all pixel tag in the mask // It is require to exclude mesh from regular pass to save performance (for opaque) and get correct result (for transparent) // For this we cull the mesh by setuping their position to NaN if _RayTracing is true and _EnableRecursiveRayTracing true. // We use this method to avoid to have to deal with RenderQueue and it allow to dynamically disabled Recursive rendering // and fallback to classic rasterize transparent this way. The code for the culling is in VertMesh() // If raytracing is disable _EnableRecursiveRayTracing is set to false and no culling happen. // Objects are still render in shadow and motion vector pass to keep their properties. // We render Recursive render object before transparent, so transparent object can be overlayed on top // like lens flare on top of headlight. We write the depth, so it correctly z-test object behind as recursive rendering // re-render everything (Mean we should also support fog and sky into it). void RaytracingRecursiveRender(HDCamera hdCamera, CommandBuffer cmd) { // If ray tracing is disabled in the frame settings or the effect is not enabled RecursiveRendering recursiveSettings = hdCamera.volumeStack.GetComponent<RecursiveRendering>(); if (!hdCamera.frameSettings.IsEnabled(FrameSettingsField.RayTracing) || !recursiveSettings.enable.value) return; using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.RayTracingRecursiveRendering))) { RTHandle debugBuffer = GetRayTracingBuffer(InternalRayTracingBuffers.RGBA0); RecursiveRendererParameters rrParams = PrepareRecursiveRendererParameters(hdCamera, recursiveSettings); RecursiveRendererResources rrResources = PrepareRecursiveRendererResources(debugBuffer); ExecuteRecursiveRendering(cmd, rrParams, rrResources); PushFullScreenDebugTexture(hdCamera, cmd, debugBuffer, FullScreenDebugMode.RecursiveRayTracing); } }
RecursiveRendererResources PrepareRecursiveRendererResources(RTHandle debugBuffer) { RecursiveRendererResources rrResources = new RecursiveRendererResources(); // Input buffers rrResources.depthStencilBuffer = m_SharedRTManager.GetDepthStencilBuffer(); rrResources.flagMask = m_FlagMaskTextureRT; // Debug buffer rrResources.debugBuffer = debugBuffer; RayCountManager rayCountManager = GetRayCountManager(); rrResources.rayCountTexture = rayCountManager.GetRayCountTexture(); // Output buffer rrResources.outputBuffer = m_CameraColorBuffer; return rrResources; }
void RaytracingRecursiveRender(HDCamera hdCamera, CommandBuffer cmd, ScriptableRenderContext renderContext, CullingResults cull) { // If ray tracing is disabled in the frame settings or the effect is not enabled RecursiveRendering recursiveSettings = hdCamera.volumeStack.GetComponent <RecursiveRendering>(); if (!hdCamera.frameSettings.IsEnabled(FrameSettingsField.RayTracing) || !recursiveSettings.enable.value) { return; } // Recursive rendering works as follow: // - Shader have a _RayTracing property // When this property is setup to true, a RayTracingPrepass pass on the material is enabled (otherwise it is disabled) // - Before prepass we render all object with a RayTracingPrepass pass enabled into the depth buffer for performance saving. // Note that we will exclude from the rendering of DepthPrepass, GBuffer and Forward pass the raytraced objects but not from // motion vector pass, so we can still benefit from motion vector. This is handled in VertMesh.hlsl (see below). // However currently when rendering motion vector this will tag the stencil for deferred lighting, and thus could produce overshading. // - After Transparent Depth pass we render all object with a RayTracingPrepass pass enabled into output a mask buffer (need to depth test but not to write depth) // Note: we render two times: one to save performance and the other to write the mask, otherwise if we write the mask in the first pass it // will not take into account the objects which could render on top of the raytracing one (If we want to do that we need to perform the pass after that // the depth buffer is ready, which is after the Gbuffer pass, so we can't save performance). // - During RaytracingRecursiveRender we perform a RayTracingRendering.raytrace call on all pixel tag in the mask // It is require to exclude mesh from regular pass to save performance (for opaque) and get correct result (for transparent) // For this we cull the mesh by setuping their position to NaN if _RayTracing is true and _EnableRecursiveRayTracing true. // We use this method to avoid to have to deal with RenderQueue and it allow to dynamically disabled Recursive rendering // and fallback to classic rasterize transparent this way. The code for the culling is in VertMesh() // If raytracing is disable _EnableRecursiveRayTracing is set to false and no culling happen. // Objects are still render in shadow and motion vector pass to keep their properties. // We render Recursive render object before transparent, so transparent object can be overlayed on top // like lens flare on top of headlight. We write the depth, so it correctly z-test object behind as recursive rendering // re-render everything (Mean we should also support fog and sky into it). using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.RayTracingRecursiveRendering))) { RTHandle debugBuffer = GetRayTracingBuffer(InternalRayTracingBuffers.RGBA0); RecursiveRendererParameters rrParams = PrepareRecursiveRendererParameters(hdCamera, recursiveSettings); RecursiveRendererResources rrResources = PrepareRecursiveRendererResources(debugBuffer); ExecuteRecursiveRendering(cmd, rrParams, rrResources); PushFullScreenDebugTexture(hdCamera, cmd, debugBuffer, FullScreenDebugMode.RecursiveRayTracing); } }
static void ExecuteRecursiveRendering(CommandBuffer cmd, RecursiveRendererParameters rrParams, RecursiveRendererResources rrResources) { // Define the shader pass to use for the reflection pass cmd.SetRayTracingShaderPass(rrParams.recursiveRenderingRT, "ForwardDXR"); // Set the acceleration structure for the pass cmd.SetRayTracingAccelerationStructure(rrParams.recursiveRenderingRT, HDShaderIDs._RaytracingAccelerationStructureName, rrParams.accelerationStructure); // Inject the ray-tracing sampling data BlueNoise.BindDitheredTextureSet(cmd, rrParams.ditheredTextureSet); // Update Global Constant Buffer. rrParams.shaderVariablesRayTracingCB._RaytracingRayMaxLength = rrParams.rayLength; rrParams.shaderVariablesRayTracingCB._RaytracingMaxRecursion = rrParams.maxDepth; rrParams.shaderVariablesRayTracingCB._RaytracingReflectionMinSmoothness = rrParams.minSmoothness; ConstantBuffer.PushGlobal(cmd, rrParams.shaderVariablesRayTracingCB, HDShaderIDs._ShaderVariablesRaytracing); // Fecth the temporary buffers we shall be using cmd.SetRayTracingTextureParam(rrParams.recursiveRenderingRT, HDShaderIDs._RaytracingFlagMask, rrResources.flagMask); cmd.SetRayTracingTextureParam(rrParams.recursiveRenderingRT, HDShaderIDs._DepthTexture, rrResources.depthStencilBuffer); cmd.SetRayTracingTextureParam(rrParams.recursiveRenderingRT, HDShaderIDs._CameraColorTextureRW, rrResources.outputBuffer); // Set ray count texture cmd.SetRayTracingTextureParam(rrParams.recursiveRenderingRT, HDShaderIDs._RayCountTexture, rrResources.rayCountTexture); // LightLoop data rrParams.lightCluster.BindLightClusterData(cmd); // Set the data for the ray miss cmd.SetRayTracingTextureParam(rrParams.recursiveRenderingRT, HDShaderIDs._SkyTexture, rrParams.skyTexture); // If this is the right debug mode and we have at least one light, write the first shadow to the de-noised texture cmd.SetRayTracingTextureParam(rrParams.recursiveRenderingRT, HDShaderIDs._RaytracingPrimaryDebug, rrResources.debugBuffer); // Run the computation cmd.DispatchRays(rrParams.recursiveRenderingRT, m_RayGenShaderName, (uint)rrParams.texWidth, (uint)rrParams.texHeight, (uint)rrParams.viewCount); }