From f64e16f7d87acfc5917b5fad3a52b93203f6a3b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Sun, 5 Dec 2021 17:03:08 +0100 Subject: [PATCH] Demo/DeferredShading: Add tone-mapping (without automatic exposure for now) --- bin/resources/bloom_bright.nzsl | 2 +- bin/resources/tone_mapping.nzsl | 66 ++++++++++++++++++ examples/DeferredShading/main.cpp | 111 ++++++++++++++++++++++-------- 3 files changed, 151 insertions(+), 28 deletions(-) create mode 100644 bin/resources/tone_mapping.nzsl diff --git a/bin/resources/bloom_bright.nzsl b/bin/resources/bloom_bright.nzsl index eeb831f55..3a97698c7 100644 --- a/bin/resources/bloom_bright.nzsl +++ b/bin/resources/bloom_bright.nzsl @@ -54,7 +54,7 @@ fn main(input: FragIn) -> FragOut color /= vec3(1.0, 1.0, 1.0) + color; let output: FragOut; - output.color = vec4(color, 1.0); + output.color = vec4(max(color, vec3(0.0, 0.0, 0.0)), 1.0); return output; } diff --git a/bin/resources/tone_mapping.nzsl b/bin/resources/tone_mapping.nzsl new file mode 100644 index 000000000..4938797b5 --- /dev/null +++ b/bin/resources/tone_mapping.nzsl @@ -0,0 +1,66 @@ +[layout(std140)] +struct ViewerData +{ + projectionMatrix: mat4, + invProjectionMatrix: mat4, + viewMatrix: mat4, + invViewMatrix: mat4, + viewProjMatrix: mat4, + invViewProjMatrix: mat4, + renderTargetSize: vec2, + invRenderTargetSize: vec2, + eyePosition: vec3 +} + +external +{ + [set(0), binding(0)] viewerData: uniform, + [set(0), binding(1)] inputTexture: sampler2D +} + +struct FragIn +{ + [builtin(fragcoord)] fragcoord: vec4 +} + +struct FragOut +{ + [location(0)] color: vec4 +} + +struct VertIn +{ + [location(0)] pos: vec3 +} + +struct VertOut +{ + [builtin(position)] position: vec4 +} + +[entry(frag)] +fn main(input: FragIn) -> FragOut +{ + let exposure = 0.8; + + let fragcoord = input.fragcoord.xy * viewerData.invRenderTargetSize; + + let hdrColor = inputTexture.Sample(fragcoord).rgb; + + // reinhard tone mapping + let mapped = vec3(1.0, 1.0, 1.0) - exp(-hdrColor * exposure); + + let output: FragOut; + output.color = vec4(mapped, 1.0); + + return output; +} + +[entry(vert)] +fn main(input: VertIn) -> VertOut +{ + let output: VertOut; + output.position = vec4(input.pos, 1.0); + + return output; +} diff --git a/examples/DeferredShading/main.cpp b/examples/DeferredShading/main.cpp index 649ae0d18..4ae8375ef 100644 --- a/examples/DeferredShading/main.cpp +++ b/examples/DeferredShading/main.cpp @@ -333,33 +333,45 @@ int main() // Bloom data - Nz::RenderPipelineLayoutInfo bloomPipelineLayoutInfo; - Nz::Graphics::FillViewerPipelineLayout(bloomPipelineLayoutInfo, 0); + Nz::RenderPipelineLayoutInfo fullscreenPipelineLayoutInfoViewer; + Nz::Graphics::FillViewerPipelineLayout(fullscreenPipelineLayoutInfoViewer, 0); - bloomPipelineLayoutInfo.bindings.push_back({ + fullscreenPipelineLayoutInfoViewer.bindings.push_back({ 0, 1, Nz::ShaderBindingType::Texture, Nz::ShaderStageType::Fragment, }); - Nz::RenderPipelineInfo bloomPipelineInfo; - bloomPipelineInfo.primitiveMode = Nz::PrimitiveMode::TriangleList; - bloomPipelineInfo.pipelineLayout = device->InstantiateRenderPipelineLayout(bloomPipelineLayoutInfo); - bloomPipelineInfo.vertexBuffers.push_back({ + Nz::RenderPipelineInfo fullscreenPipelineInfoViewer; + fullscreenPipelineInfoViewer.primitiveMode = Nz::PrimitiveMode::TriangleList; + fullscreenPipelineInfoViewer.pipelineLayout = device->InstantiateRenderPipelineLayout(fullscreenPipelineLayoutInfoViewer); + fullscreenPipelineInfoViewer.vertexBuffers.push_back({ 0, fullscreenVertexDeclaration }); - bloomPipelineInfo.shaderModules.push_back(device->InstantiateShaderModule(Nz::ShaderStageType::Fragment | Nz::ShaderStageType::Vertex, Nz::ShaderLanguage::NazaraShader, resourceDir / "bloom_bright.nzsl", {})); + fullscreenPipelineInfoViewer.shaderModules.push_back(device->InstantiateShaderModule(Nz::ShaderStageType::Fragment | Nz::ShaderStageType::Vertex, Nz::ShaderLanguage::NazaraShader, resourceDir / "bloom_bright.nzsl", {})); std::shared_ptr bloomBrightShaderBinding; std::shared_ptr gaussianBlurShaderBinding; - std::shared_ptr bloomBrightPipeline = device->InstantiateRenderPipeline(bloomPipelineInfo); + std::shared_ptr bloomBrightPipeline = device->InstantiateRenderPipeline(fullscreenPipelineInfoViewer); - bloomPipelineInfo.shaderModules.clear(); - bloomPipelineInfo.shaderModules.push_back(device->InstantiateShaderModule(Nz::ShaderStageType::Fragment | Nz::ShaderStageType::Vertex, Nz::ShaderLanguage::NazaraShader, resourceDir / "gaussian_blur.nzsl", {})); - + // Gaussian Blur + fullscreenPipelineInfoViewer.shaderModules.clear(); + fullscreenPipelineInfoViewer.shaderModules.push_back(device->InstantiateShaderModule(Nz::ShaderStageType::Fragment | Nz::ShaderStageType::Vertex, Nz::ShaderLanguage::NazaraShader, resourceDir / "gaussian_blur.nzsl", {})); + + std::shared_ptr gaussianBlurPipeline = device->InstantiateRenderPipeline(fullscreenPipelineInfoViewer); + + // Tone mapping + std::shared_ptr toneMappingShaderBinding; + + fullscreenPipelineInfoViewer.shaderModules.clear(); + fullscreenPipelineInfoViewer.shaderModules.push_back(device->InstantiateShaderModule(Nz::ShaderStageType::Fragment | Nz::ShaderStageType::Vertex, Nz::ShaderLanguage::NazaraShader, resourceDir / "tone_mapping.nzsl", {})); + + std::shared_ptr toneMappingPipeline = device->InstantiateRenderPipeline(fullscreenPipelineInfoViewer); + + // Bloom blend Nz::RenderPipelineLayoutInfo bloomBlendPipelineLayoutInfo; Nz::Graphics::FillViewerPipelineLayout(bloomBlendPipelineLayoutInfo, 0); @@ -377,8 +389,6 @@ int main() }); - std::shared_ptr gaussianBlurPipeline = device->InstantiateRenderPipeline(bloomPipelineInfo); - Nz::RenderPipelineInfo bloomBlendPipelineInfo; bloomBlendPipelineInfo.primitiveMode = Nz::PrimitiveMode::TriangleList; bloomBlendPipelineInfo.pipelineLayout = device->InstantiateRenderPipelineLayout(bloomBlendPipelineLayoutInfo); @@ -548,11 +558,13 @@ int main() std::size_t positionTexture; std::size_t depthBuffer1; std::size_t depthBuffer2; - std::size_t backbuffer; + std::size_t bloomOutput; std::size_t bloomTextureA; std::size_t bloomTextureB; std::size_t lightOutput; + std::size_t toneMappingOutput; + Nz::SubmeshRenderer submeshRenderer; std::unique_ptr submeshRendererData = submeshRenderer.InstanciateData(); @@ -605,28 +617,35 @@ int main() lightOutput = graph.AddAttachment({ "Light output", - Nz::PixelFormat::RGBA8 + Nz::PixelFormat::RGBA16F }); - backbuffer = graph.AddAttachment({ + bloomOutput = graph.AddAttachment({ "Backbuffer", - Nz::PixelFormat::RGBA8 + Nz::PixelFormat::RGBA16F }); bloomTextureA = graph.AddAttachment({ "Bloom texture A", - Nz::PixelFormat::RGBA8, + Nz::PixelFormat::RGBA16F, 10'000, 10'000 }); bloomTextureB = graph.AddAttachment({ "Bloom texture B", - Nz::PixelFormat::RGBA8, + Nz::PixelFormat::RGBA16F, 10'000, 10'000 }); + toneMappingOutput = graph.AddAttachment({ + "Tone mapping", + Nz::PixelFormat::RGBA8, + 100'000, + 100'000 + }); + Nz::FramePass& gbufferPass = graph.AddPass("GBuffer"); std::size_t geometryAlbedo = gbufferPass.AddOutput(colorTexture); @@ -649,9 +668,11 @@ int main() gbufferPass.SetCommandCallback([&](Nz::CommandBufferBuilder& builder, const Nz::Recti& renderArea) { - builder.SetScissor(renderArea); builder.SetViewport(renderArea); + spaceshipModel.UpdateScissorBox(renderArea); + planeModel.UpdateScissorBox(renderArea); + std::vector> elements; spaceshipModel.BuildElement(forwardPassIndex, modelInstance1, elements); spaceshipModel.BuildElement(forwardPassIndex, modelInstance2, elements); @@ -781,6 +802,7 @@ int main() builder.Draw(3); }); + bloomBlendPass.SetExecutionCallback([&] { return (bloomEnabled) ? Nz::FramePassExecution::Execute : Nz::FramePassExecution::Skip; @@ -788,9 +810,24 @@ int main() bloomBlendPass.AddInput(lightOutput); bloomBlendPass.AddInput(bloomTextureB); - bloomBlendPass.AddOutput(backbuffer); + bloomBlendPass.AddOutput(bloomOutput); - graph.AddBackbufferOutput(backbuffer); + Nz::FramePass& toneMappingPass = graph.AddPass("Tone mapping"); + toneMappingPass.AddInput(bloomOutput); + toneMappingPass.AddOutput(toneMappingOutput); + toneMappingPass.SetCommandCallback([&](Nz::CommandBufferBuilder& builder, const Nz::Recti& renderArea) + { + builder.SetScissor(renderArea); + builder.SetViewport(renderArea); + + builder.BindShaderBinding(0, *toneMappingShaderBinding); + builder.BindPipeline(*toneMappingPipeline); + builder.BindVertexBuffer(0, *fullscreenVertexBuffer); + + builder.Draw(3); + }); + + graph.AddBackbufferOutput(toneMappingOutput); return graph.Bake(); }(); @@ -993,7 +1030,7 @@ int main() frame.PushForRelease(std::move(bloomBrightShaderBinding)); - bloomBrightShaderBinding = bloomPipelineInfo.pipelineLayout->AllocateShaderBinding(0); + bloomBrightShaderBinding = fullscreenPipelineInfoViewer.pipelineLayout->AllocateShaderBinding(0); bloomBrightShaderBinding->Update({ { 0, @@ -1013,7 +1050,7 @@ int main() frame.PushForRelease(std::move(gaussianBlurShaderBinding)); - gaussianBlurShaderBinding = bloomPipelineInfo.pipelineLayout->AllocateShaderBinding(0); + gaussianBlurShaderBinding = fullscreenPipelineInfoViewer.pipelineLayout->AllocateShaderBinding(0); gaussianBlurShaderBinding->Update({ { 0, @@ -1071,6 +1108,26 @@ int main() } }); + frame.PushForRelease(std::move(toneMappingShaderBinding)); + + toneMappingShaderBinding = fullscreenPipelineInfoViewer.pipelineLayout->AllocateShaderBinding(0); + toneMappingShaderBinding->Update({ + { + 0, + Nz::ShaderBinding::UniformBufferBinding { + viewerInstance.GetViewerBuffer().get(), + 0, viewerInstance.GetViewerBuffer()->GetSize() + } + }, + { + 1, + Nz::ShaderBinding::TextureBinding { + bakedGraph.GetAttachmentTexture(bloomOutput).get(), + textureSampler.get() + } + } + }); + frame.PushForRelease(std::move(finalBlitBinding)); finalBlitBinding = fullscreenPipelineInfo.pipelineLayout->AllocateShaderBinding(0); @@ -1078,7 +1135,7 @@ int main() { 0, Nz::ShaderBinding::TextureBinding { - bakedGraph.GetAttachmentTexture(backbuffer).get(), + bakedGraph.GetAttachmentTexture(toneMappingOutput).get(), textureSampler.get() } } @@ -1144,7 +1201,7 @@ int main() { Nz::Recti windowRenderRect(0, 0, window.GetSize().x, window.GetSize().y); - builder.TextureBarrier(Nz::PipelineStage::ColorOutput, Nz::PipelineStage::FragmentShader, Nz::MemoryAccess::ColorWrite, Nz::MemoryAccess::ShaderRead, Nz::TextureLayout::ColorOutput, Nz::TextureLayout::ColorInput, *bakedGraph.GetAttachmentTexture(backbuffer)); + builder.TextureBarrier(Nz::PipelineStage::ColorOutput, Nz::PipelineStage::FragmentShader, Nz::MemoryAccess::ColorWrite, Nz::MemoryAccess::ShaderRead, Nz::TextureLayout::ColorOutput, Nz::TextureLayout::ColorInput, *bakedGraph.GetAttachmentTexture(toneMappingOutput)); builder.BeginRenderPass(windowRT->GetFramebuffer(frame.GetFramebufferIndex()), windowRT->GetRenderPass(), windowRenderRect); {