Demo/DeferredShading: Add tone-mapping (without automatic exposure for now)

This commit is contained in:
Jérôme Leclercq 2021-12-05 17:03:08 +01:00
parent 0aec863300
commit f64e16f7d8
3 changed files with 151 additions and 28 deletions

View File

@ -54,7 +54,7 @@ fn main(input: FragIn) -> FragOut
color /= vec3<f32>(1.0, 1.0, 1.0) + color; color /= vec3<f32>(1.0, 1.0, 1.0) + color;
let output: FragOut; let output: FragOut;
output.color = vec4<f32>(color, 1.0); output.color = vec4<f32>(max(color, vec3<f32>(0.0, 0.0, 0.0)), 1.0);
return output; return output;
} }

View File

@ -0,0 +1,66 @@
[layout(std140)]
struct ViewerData
{
projectionMatrix: mat4<f32>,
invProjectionMatrix: mat4<f32>,
viewMatrix: mat4<f32>,
invViewMatrix: mat4<f32>,
viewProjMatrix: mat4<f32>,
invViewProjMatrix: mat4<f32>,
renderTargetSize: vec2<f32>,
invRenderTargetSize: vec2<f32>,
eyePosition: vec3<f32>
}
external
{
[set(0), binding(0)] viewerData: uniform<ViewerData>,
[set(0), binding(1)] inputTexture: sampler2D<f32>
}
struct FragIn
{
[builtin(fragcoord)] fragcoord: vec4<f32>
}
struct FragOut
{
[location(0)] color: vec4<f32>
}
struct VertIn
{
[location(0)] pos: vec3<f32>
}
struct VertOut
{
[builtin(position)] position: vec4<f32>
}
[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<f32>(1.0, 1.0, 1.0) - exp(-hdrColor * exposure);
let output: FragOut;
output.color = vec4<f32>(mapped, 1.0);
return output;
}
[entry(vert)]
fn main(input: VertIn) -> VertOut
{
let output: VertOut;
output.position = vec4<f32>(input.pos, 1.0);
return output;
}

View File

@ -333,33 +333,45 @@ int main()
// Bloom data // Bloom data
Nz::RenderPipelineLayoutInfo bloomPipelineLayoutInfo; Nz::RenderPipelineLayoutInfo fullscreenPipelineLayoutInfoViewer;
Nz::Graphics::FillViewerPipelineLayout(bloomPipelineLayoutInfo, 0); Nz::Graphics::FillViewerPipelineLayout(fullscreenPipelineLayoutInfoViewer, 0);
bloomPipelineLayoutInfo.bindings.push_back({ fullscreenPipelineLayoutInfoViewer.bindings.push_back({
0, 1, 0, 1,
Nz::ShaderBindingType::Texture, Nz::ShaderBindingType::Texture,
Nz::ShaderStageType::Fragment, Nz::ShaderStageType::Fragment,
}); });
Nz::RenderPipelineInfo bloomPipelineInfo; Nz::RenderPipelineInfo fullscreenPipelineInfoViewer;
bloomPipelineInfo.primitiveMode = Nz::PrimitiveMode::TriangleList; fullscreenPipelineInfoViewer.primitiveMode = Nz::PrimitiveMode::TriangleList;
bloomPipelineInfo.pipelineLayout = device->InstantiateRenderPipelineLayout(bloomPipelineLayoutInfo); fullscreenPipelineInfoViewer.pipelineLayout = device->InstantiateRenderPipelineLayout(fullscreenPipelineLayoutInfoViewer);
bloomPipelineInfo.vertexBuffers.push_back({ fullscreenPipelineInfoViewer.vertexBuffers.push_back({
0, 0,
fullscreenVertexDeclaration 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<Nz::ShaderBinding> bloomBrightShaderBinding; std::shared_ptr<Nz::ShaderBinding> bloomBrightShaderBinding;
std::shared_ptr<Nz::ShaderBinding> gaussianBlurShaderBinding; std::shared_ptr<Nz::ShaderBinding> gaussianBlurShaderBinding;
std::shared_ptr<Nz::RenderPipeline> bloomBrightPipeline = device->InstantiateRenderPipeline(bloomPipelineInfo); std::shared_ptr<Nz::RenderPipeline> bloomBrightPipeline = device->InstantiateRenderPipeline(fullscreenPipelineInfoViewer);
bloomPipelineInfo.shaderModules.clear(); // Gaussian Blur
bloomPipelineInfo.shaderModules.push_back(device->InstantiateShaderModule(Nz::ShaderStageType::Fragment | Nz::ShaderStageType::Vertex, Nz::ShaderLanguage::NazaraShader, resourceDir / "gaussian_blur.nzsl", {})); 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<Nz::RenderPipeline> gaussianBlurPipeline = device->InstantiateRenderPipeline(fullscreenPipelineInfoViewer);
// Tone mapping
std::shared_ptr<Nz::ShaderBinding> 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<Nz::RenderPipeline> toneMappingPipeline = device->InstantiateRenderPipeline(fullscreenPipelineInfoViewer);
// Bloom blend
Nz::RenderPipelineLayoutInfo bloomBlendPipelineLayoutInfo; Nz::RenderPipelineLayoutInfo bloomBlendPipelineLayoutInfo;
Nz::Graphics::FillViewerPipelineLayout(bloomBlendPipelineLayoutInfo, 0); Nz::Graphics::FillViewerPipelineLayout(bloomBlendPipelineLayoutInfo, 0);
@ -377,8 +389,6 @@ int main()
}); });
std::shared_ptr<Nz::RenderPipeline> gaussianBlurPipeline = device->InstantiateRenderPipeline(bloomPipelineInfo);
Nz::RenderPipelineInfo bloomBlendPipelineInfo; Nz::RenderPipelineInfo bloomBlendPipelineInfo;
bloomBlendPipelineInfo.primitiveMode = Nz::PrimitiveMode::TriangleList; bloomBlendPipelineInfo.primitiveMode = Nz::PrimitiveMode::TriangleList;
bloomBlendPipelineInfo.pipelineLayout = device->InstantiateRenderPipelineLayout(bloomBlendPipelineLayoutInfo); bloomBlendPipelineInfo.pipelineLayout = device->InstantiateRenderPipelineLayout(bloomBlendPipelineLayoutInfo);
@ -548,11 +558,13 @@ int main()
std::size_t positionTexture; std::size_t positionTexture;
std::size_t depthBuffer1; std::size_t depthBuffer1;
std::size_t depthBuffer2; std::size_t depthBuffer2;
std::size_t backbuffer; std::size_t bloomOutput;
std::size_t bloomTextureA; std::size_t bloomTextureA;
std::size_t bloomTextureB; std::size_t bloomTextureB;
std::size_t lightOutput; std::size_t lightOutput;
std::size_t toneMappingOutput;
Nz::SubmeshRenderer submeshRenderer; Nz::SubmeshRenderer submeshRenderer;
std::unique_ptr<Nz::ElementRendererData> submeshRendererData = submeshRenderer.InstanciateData(); std::unique_ptr<Nz::ElementRendererData> submeshRendererData = submeshRenderer.InstanciateData();
@ -605,28 +617,35 @@ int main()
lightOutput = graph.AddAttachment({ lightOutput = graph.AddAttachment({
"Light output", "Light output",
Nz::PixelFormat::RGBA8 Nz::PixelFormat::RGBA16F
}); });
backbuffer = graph.AddAttachment({ bloomOutput = graph.AddAttachment({
"Backbuffer", "Backbuffer",
Nz::PixelFormat::RGBA8 Nz::PixelFormat::RGBA16F
}); });
bloomTextureA = graph.AddAttachment({ bloomTextureA = graph.AddAttachment({
"Bloom texture A", "Bloom texture A",
Nz::PixelFormat::RGBA8, Nz::PixelFormat::RGBA16F,
10'000, 10'000,
10'000 10'000
}); });
bloomTextureB = graph.AddAttachment({ bloomTextureB = graph.AddAttachment({
"Bloom texture B", "Bloom texture B",
Nz::PixelFormat::RGBA8, Nz::PixelFormat::RGBA16F,
10'000, 10'000,
10'000 10'000
}); });
toneMappingOutput = graph.AddAttachment({
"Tone mapping",
Nz::PixelFormat::RGBA8,
100'000,
100'000
});
Nz::FramePass& gbufferPass = graph.AddPass("GBuffer"); Nz::FramePass& gbufferPass = graph.AddPass("GBuffer");
std::size_t geometryAlbedo = gbufferPass.AddOutput(colorTexture); std::size_t geometryAlbedo = gbufferPass.AddOutput(colorTexture);
@ -649,9 +668,11 @@ int main()
gbufferPass.SetCommandCallback([&](Nz::CommandBufferBuilder& builder, const Nz::Recti& renderArea) gbufferPass.SetCommandCallback([&](Nz::CommandBufferBuilder& builder, const Nz::Recti& renderArea)
{ {
builder.SetScissor(renderArea);
builder.SetViewport(renderArea); builder.SetViewport(renderArea);
spaceshipModel.UpdateScissorBox(renderArea);
planeModel.UpdateScissorBox(renderArea);
std::vector<std::unique_ptr<Nz::RenderElement>> elements; std::vector<std::unique_ptr<Nz::RenderElement>> elements;
spaceshipModel.BuildElement(forwardPassIndex, modelInstance1, elements); spaceshipModel.BuildElement(forwardPassIndex, modelInstance1, elements);
spaceshipModel.BuildElement(forwardPassIndex, modelInstance2, elements); spaceshipModel.BuildElement(forwardPassIndex, modelInstance2, elements);
@ -781,6 +802,7 @@ int main()
builder.Draw(3); builder.Draw(3);
}); });
bloomBlendPass.SetExecutionCallback([&] bloomBlendPass.SetExecutionCallback([&]
{ {
return (bloomEnabled) ? Nz::FramePassExecution::Execute : Nz::FramePassExecution::Skip; return (bloomEnabled) ? Nz::FramePassExecution::Execute : Nz::FramePassExecution::Skip;
@ -788,9 +810,24 @@ int main()
bloomBlendPass.AddInput(lightOutput); bloomBlendPass.AddInput(lightOutput);
bloomBlendPass.AddInput(bloomTextureB); 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(); return graph.Bake();
}(); }();
@ -993,7 +1030,7 @@ int main()
frame.PushForRelease(std::move(bloomBrightShaderBinding)); frame.PushForRelease(std::move(bloomBrightShaderBinding));
bloomBrightShaderBinding = bloomPipelineInfo.pipelineLayout->AllocateShaderBinding(0); bloomBrightShaderBinding = fullscreenPipelineInfoViewer.pipelineLayout->AllocateShaderBinding(0);
bloomBrightShaderBinding->Update({ bloomBrightShaderBinding->Update({
{ {
0, 0,
@ -1013,7 +1050,7 @@ int main()
frame.PushForRelease(std::move(gaussianBlurShaderBinding)); frame.PushForRelease(std::move(gaussianBlurShaderBinding));
gaussianBlurShaderBinding = bloomPipelineInfo.pipelineLayout->AllocateShaderBinding(0); gaussianBlurShaderBinding = fullscreenPipelineInfoViewer.pipelineLayout->AllocateShaderBinding(0);
gaussianBlurShaderBinding->Update({ gaussianBlurShaderBinding->Update({
{ {
0, 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)); frame.PushForRelease(std::move(finalBlitBinding));
finalBlitBinding = fullscreenPipelineInfo.pipelineLayout->AllocateShaderBinding(0); finalBlitBinding = fullscreenPipelineInfo.pipelineLayout->AllocateShaderBinding(0);
@ -1078,7 +1135,7 @@ int main()
{ {
0, 0,
Nz::ShaderBinding::TextureBinding { Nz::ShaderBinding::TextureBinding {
bakedGraph.GetAttachmentTexture(backbuffer).get(), bakedGraph.GetAttachmentTexture(toneMappingOutput).get(),
textureSampler.get() textureSampler.get()
} }
} }
@ -1144,7 +1201,7 @@ int main()
{ {
Nz::Recti windowRenderRect(0, 0, window.GetSize().x, window.GetSize().y); 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); builder.BeginRenderPass(windowRT->GetFramebuffer(frame.GetFramebufferIndex()), windowRT->GetRenderPass(), windowRenderRect);
{ {