using UnityEngine.Experimental.Rendering; using UnityEngine.Rendering.RenderGraphModule; using UnityEngine.Rendering; namespace UnityEngine.Rendering.HighDefinition { class HDDiffuseDenoiser { // Resources used for the de-noiser ComputeShader m_DiffuseDenoiser; // Runtime Initialization data bool m_DenoiserInitialized; Texture2D m_OwnenScrambledTexture; GraphicsBuffer m_PointDistribution; // Kernels that may be required int m_BilateralFilterSingleKernel; int m_BilateralFilterColorKernel; int m_GatherSingleKernel; int m_GatherColorKernel; public void Init(HDRenderPipeline renderPipeline) { // Keep track of the resources m_DiffuseDenoiser = renderPipeline.runtimeShaders.diffuseDenoiserCS; // Grab all the kernels we'll eventually need m_BilateralFilterSingleKernel = m_DiffuseDenoiser.FindKernel("BilateralFilterSingle"); m_BilateralFilterColorKernel = m_DiffuseDenoiser.FindKernel("BilateralFilterColor"); m_GatherSingleKernel = m_DiffuseDenoiser.FindKernel("GatherSingle"); m_GatherColorKernel = m_DiffuseDenoiser.FindKernel("GatherColor"); // Data required for the online initialization m_DenoiserInitialized = false; m_OwnenScrambledTexture = renderPipeline.runtimeTextures.owenScrambledRGBATex; m_PointDistribution = new GraphicsBuffer(GraphicsBuffer.Target.Structured, 16 * 4, 2 * sizeof(float)); } public void Release() { CoreUtils.SafeRelease(m_PointDistribution); } class DiffuseDenoiserPassData { // Camera parameters public int texWidth; public int texHeight; public int viewCount; // Denoising parameters public bool needInit; public float pixelSpreadTangent; public float kernelSize; public bool halfResolutionFilter; public bool jitterFilter; public int frameIndex; public float resolutionMultiplier; // Kernels public int bilateralFilterKernel; public int gatherKernel; // Other parameters public BufferHandle pointDistribution; public ComputeShader diffuseDenoiserCS; public Texture2D owenScrambledTexture; public TextureHandle depthStencilBuffer; public TextureHandle normalBuffer; public TextureHandle noisyBuffer; public TextureHandle intermediateBuffer; public TextureHandle outputBuffer; } internal struct DiffuseDenoiserParameters { public bool singleChannel; public float kernelSize; public bool halfResolutionFilter; public bool jitterFilter; public float resolutionMultiplier; } public TextureHandle Denoise(RenderGraph renderGraph, HDCamera hdCamera, DiffuseDenoiserParameters denoiserParams, TextureHandle noisyBuffer, TextureHandle depthBuffer, TextureHandle normalBuffer, TextureHandle outputBuffer) { using (var builder = renderGraph.AddRenderPass("DiffuseDenoiser", out var passData, ProfilingSampler.Get(HDProfileId.DiffuseFilter))) { // Cannot run in async builder.EnableAsyncCompute(false); // Initialization data passData.needInit = !m_DenoiserInitialized; m_DenoiserInitialized = true; passData.owenScrambledTexture = m_OwnenScrambledTexture; // Camera parameters passData.texWidth = (int)Mathf.Floor(hdCamera.actualWidth / denoiserParams.resolutionMultiplier); passData.texHeight = (int)Mathf.Floor(hdCamera.actualHeight / denoiserParams.resolutionMultiplier); passData.viewCount = hdCamera.viewCount; // Parameters passData.pixelSpreadTangent = HDRenderPipeline.GetPixelSpreadTangent(hdCamera.camera.fieldOfView, passData.texWidth, passData.texHeight); passData.kernelSize = denoiserParams.kernelSize; passData.halfResolutionFilter = denoiserParams.halfResolutionFilter; passData.jitterFilter = denoiserParams.jitterFilter; passData.frameIndex = HDRenderPipeline.RayTracingFrameIndex(hdCamera); passData.resolutionMultiplier = denoiserParams.resolutionMultiplier; // Kernels passData.bilateralFilterKernel = denoiserParams.singleChannel ? m_BilateralFilterSingleKernel : m_BilateralFilterColorKernel; passData.gatherKernel = denoiserParams.singleChannel ? m_GatherSingleKernel : m_GatherColorKernel; // Other parameters passData.diffuseDenoiserCS = m_DiffuseDenoiser; passData.pointDistribution = builder.ReadBuffer(renderGraph.ImportBuffer(m_PointDistribution)); passData.depthStencilBuffer = builder.ReadTexture(depthBuffer); passData.normalBuffer = builder.ReadTexture(normalBuffer); passData.noisyBuffer = builder.ReadTexture(noisyBuffer); passData.intermediateBuffer = builder.CreateTransientTexture(new TextureDesc(Vector2.one, true, true) { colorFormat = GraphicsFormat.B10G11R11_UFloatPack32, enableRandomWrite = true, name = "DiffuseDenoiserIntermediate" }); passData.outputBuffer = builder.WriteTexture(outputBuffer); builder.SetRenderFunc( (DiffuseDenoiserPassData data, RenderGraphContext ctx) => { // Generate the point distribution if needed (this is only ran once) if (data.needInit) { int m_GeneratePointDistributionKernel = data.diffuseDenoiserCS.FindKernel("GeneratePointDistribution"); ctx.cmd.SetComputeTextureParam(data.diffuseDenoiserCS, m_GeneratePointDistributionKernel, HDShaderIDs._OwenScrambledRGTexture, data.owenScrambledTexture); ctx.cmd.SetComputeBufferParam(data.diffuseDenoiserCS, m_GeneratePointDistributionKernel, "_PointDistributionRW", data.pointDistribution); ctx.cmd.DispatchCompute(data.diffuseDenoiserCS, m_GeneratePointDistributionKernel, 1, 1, 1); } // Evaluate the dispatch parameters int areaTileSize = 8; int numTilesX = (data.texWidth + (areaTileSize - 1)) / areaTileSize; int numTilesY = (data.texHeight + (areaTileSize - 1)) / areaTileSize; // Request the intermediate buffers that we need ctx.cmd.SetComputeFloatParam(data.diffuseDenoiserCS, HDShaderIDs._DenoiserFilterRadius, data.kernelSize); ctx.cmd.SetComputeBufferParam(data.diffuseDenoiserCS, data.bilateralFilterKernel, HDShaderIDs._PointDistribution, data.pointDistribution); ctx.cmd.SetComputeTextureParam(data.diffuseDenoiserCS, data.bilateralFilterKernel, HDShaderIDs._DenoiseInputTexture, data.noisyBuffer); ctx.cmd.SetComputeTextureParam(data.diffuseDenoiserCS, data.bilateralFilterKernel, HDShaderIDs._DepthTexture, data.depthStencilBuffer); ctx.cmd.SetComputeTextureParam(data.diffuseDenoiserCS, data.bilateralFilterKernel, HDShaderIDs._StencilTexture, data.depthStencilBuffer, 0, RenderTextureSubElement.Stencil); ctx.cmd.SetComputeTextureParam(data.diffuseDenoiserCS, data.bilateralFilterKernel, HDShaderIDs._NormalBufferTexture, data.normalBuffer); ctx.cmd.SetComputeTextureParam(data.diffuseDenoiserCS, data.bilateralFilterKernel, HDShaderIDs._DenoiseOutputTextureRW, data.halfResolutionFilter ? data.intermediateBuffer : data.outputBuffer); ctx.cmd.SetComputeIntParam(data.diffuseDenoiserCS, HDShaderIDs._HalfResolutionFilter, data.halfResolutionFilter ? 1 : 0); ctx.cmd.SetComputeFloatParam(data.diffuseDenoiserCS, HDShaderIDs._PixelSpreadAngleTangent, data.pixelSpreadTangent); ctx.cmd.SetComputeVectorParam(data.diffuseDenoiserCS, HDShaderIDs._DenoiserResolutionMultiplierVals, new Vector4(data.resolutionMultiplier, 1.0f / data.resolutionMultiplier, 0.0f, 0.0f)); if (data.jitterFilter) ctx.cmd.SetComputeIntParam(data.diffuseDenoiserCS, HDShaderIDs._JitterFramePeriod, (data.frameIndex % 4)); else ctx.cmd.SetComputeIntParam(data.diffuseDenoiserCS, HDShaderIDs._JitterFramePeriod, -1); ctx.cmd.DispatchCompute(data.diffuseDenoiserCS, data.bilateralFilterKernel, numTilesX, numTilesY, data.viewCount); if (data.halfResolutionFilter) { ctx.cmd.SetComputeTextureParam(data.diffuseDenoiserCS, data.gatherKernel, HDShaderIDs._DenoiseInputTexture, data.intermediateBuffer); ctx.cmd.SetComputeTextureParam(data.diffuseDenoiserCS, data.gatherKernel, HDShaderIDs._DepthTexture, data.depthStencilBuffer); ctx.cmd.SetComputeTextureParam(data.diffuseDenoiserCS, data.gatherKernel, HDShaderIDs._DenoiseOutputTextureRW, data.outputBuffer); ctx.cmd.DispatchCompute(data.diffuseDenoiserCS, data.gatherKernel, numTilesX, numTilesY, data.viewCount); } }); return passData.outputBuffer; } } } }