From e39e832e522fe7f6b7f49769e03a917c0a9eb36c Mon Sep 17 00:00:00 2001 From: Razakhel Date: Fri, 30 Aug 2024 19:00:13 +0200 Subject: [PATCH] [Examples/FullDemo] Added Sobel, Canny & blend passes to the demo - These are used to enhance the edges of the rendered scene - Removed the overlay texture to save vertical space --- examples/fullDemo.cpp | 81 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 75 insertions(+), 6 deletions(-) diff --git a/examples/fullDemo.cpp b/examples/fullDemo.cpp index 6973c5be..8b001ef8 100644 --- a/examples/fullDemo.cpp +++ b/examples/fullDemo.cpp @@ -60,6 +60,10 @@ int main() { // Note though that a buffer cannot be set as both read & write in the same pass or process const auto depthBuffer = Raz::Texture2D::create(window.getWidth(), window.getHeight(), Raz::TextureColorspace::DEPTH); const auto colorBuffer = Raz::Texture2D::create(window.getWidth(), window.getHeight(), Raz::TextureColorspace::RGB); + const auto gradientBuffer = Raz::Texture2D::create(window.getWidth(), window.getHeight(), Raz::TextureColorspace::RGB); + const auto gradDirBuffer = Raz::Texture2D::create(window.getWidth(), window.getHeight(), Raz::TextureColorspace::RGB); + const auto edgeBuffer = Raz::Texture2D::create(window.getWidth(), window.getHeight(), Raz::TextureColorspace::GRAY); + const auto edgeBlendBuffer = Raz::Texture2D::create(window.getWidth(), window.getHeight(), Raz::TextureColorspace::RGB); const auto chromAberrBuffer = Raz::Texture2D::create(window.getWidth(), window.getHeight(), Raz::TextureColorspace::RGB); const auto blurredBuffer = Raz::Texture2D::create(window.getWidth(), window.getHeight(), Raz::TextureColorspace::RGB); const auto vignetteBuffer = Raz::Texture2D::create(window.getWidth(), window.getHeight(), Raz::TextureColorspace::RGB); @@ -69,6 +73,10 @@ int main() { if (Raz::Renderer::checkVersion(4, 3)) { Raz::Renderer::setLabel(Raz::RenderObjectType::TEXTURE, depthBuffer->getIndex(), "Depth buffer"); Raz::Renderer::setLabel(Raz::RenderObjectType::TEXTURE, colorBuffer->getIndex(), "Color buffer"); + Raz::Renderer::setLabel(Raz::RenderObjectType::TEXTURE, gradientBuffer->getIndex(), "Gradient buffer"); + Raz::Renderer::setLabel(Raz::RenderObjectType::TEXTURE, gradDirBuffer->getIndex(), "Gradient direction buffer"); + Raz::Renderer::setLabel(Raz::RenderObjectType::TEXTURE, edgeBuffer->getIndex(), "Edge buffer"); + Raz::Renderer::setLabel(Raz::RenderObjectType::TEXTURE, edgeBlendBuffer->getIndex(), "Edge blend buffer"); Raz::Renderer::setLabel(Raz::RenderObjectType::TEXTURE, chromAberrBuffer->getIndex(), "Chrom. aberr. buffer"); Raz::Renderer::setLabel(Raz::RenderObjectType::TEXTURE, blurredBuffer->getIndex(), "Blurred buffer"); Raz::Renderer::setLabel(Raz::RenderObjectType::TEXTURE, vignetteBuffer->getIndex(), "Vignette buffer"); @@ -79,12 +87,58 @@ int main() { geometryPass.setWriteDepthTexture(depthBuffer); // A depth buffer is always needed geometryPass.addWriteColorTexture(colorBuffer, 0); + // Sobel + + auto& sobel = renderGraph.addRenderProcess(); + sobel.setInputBuffer(colorBuffer); + sobel.setOutputGradientBuffer(gradientBuffer); + sobel.setOutputGradientDirectionBuffer(gradDirBuffer); + sobel.addParent(geometryPass); + + // Canny + + // Note that in an ordinary Canny edge detection process, the input of the gradient information computing pass (here Sobel) + // should be applied a gaussian blur to attempt removing high frequencies (small details). It's not made here to avoid + // computing another blur, as one is already done further below + + auto& canny = renderGraph.addRenderProcess(); + canny.setInputGradientBuffer(gradientBuffer); + canny.setInputGradientDirectionBuffer(gradDirBuffer); + canny.setOutputBuffer(edgeBuffer); + canny.addParent(sobel); + + // Edge blend + + auto& edgeBlend = renderGraph.addNode(Raz::FragmentShader::loadFromSource(R"( + in vec2 fragTexcoords; + + uniform sampler2D uniColorBuffer; + uniform sampler2D uniEdgeBuffer; + uniform float uniBlendFactor = 0.0; + + layout(location = 0) out vec4 fragColor; + + void main() { + vec3 origColor = texture(uniColorBuffer, fragTexcoords).rgb; + float edge = texture(uniEdgeBuffer, fragTexcoords).r; + + vec3 blendedColor = origColor * (1.0 - edge); + + vec3 finalColor = mix(origColor, blendedColor, uniBlendFactor); + fragColor = vec4(finalColor, 1.0); + } + )")); + edgeBlend.addReadTexture(colorBuffer, "uniColorBuffer"); + edgeBlend.addReadTexture(edgeBuffer, "uniEdgeBuffer"); + edgeBlend.addWriteColorTexture(edgeBlendBuffer, 0); + canny.addChild(edgeBlend); + // Chromatic aberration auto& chromaticAberration = renderGraph.addRenderProcess(); - chromaticAberration.setInputBuffer(colorBuffer); + chromaticAberration.setInputBuffer(edgeBlendBuffer); chromaticAberration.setOutputBuffer(chromAberrBuffer); - chromaticAberration.addParent(geometryPass); + chromaticAberration.addParent(edgeBlend); // Blur @@ -251,6 +305,21 @@ end)"; overlay.addSlider("Sound volume", [&meshSound] (float value) noexcept { meshSound.setGain(value); }, 0.f, 1.f, 0.f); #endif // RAZ_USE_AUDIO + overlay.addSlider("Edge enhanc. strength", + [&edgeBlend] (float value) { + edgeBlend.getProgram().setAttribute(value, "uniBlendFactor"); + edgeBlend.getProgram().sendAttributes(); + }, + 0.f, 1.f, 0.f); + + overlay.addSlider("Canny lower bound", + [&canny] (float value) { canny.setLowerBound(value); }, + 0.f, 1.f, 0.1f); + + overlay.addSlider("Canny upper bound", + [&canny] (float value) { canny.setUpperBound(value); }, + 0.f, 1.f, 0.3f); + overlay.addSlider("Chrom. aberr. strength", [&chromaticAberration] (float value) { chromaticAberration.setStrength(value); }, -15.f, 15.f, 0.f); @@ -275,15 +344,13 @@ end)"; [&pixelization] (float value) { pixelization.setStrength(value); }, 0.f, 1.f, 0.f); - overlay.addSeparator(); - - overlay.addTexture(static_cast(meshRenderComp.getMaterials().front().getProgram().getTexture(0)), 100, 100); - #if !defined(USE_OPENGL_ES) // GPU timing capabilities are not available with OpenGL ES overlay.addSeparator(); Raz::OverlayPlot& plot = overlay.addPlot("Profiler", 100, {}, "Time (ms)", 0.f, 100.f, false, 200.f); Raz::OverlayPlotEntry& geomPlot = plot.addEntry("Geometry"); + Raz::OverlayPlotEntry& sobelPlot = plot.addEntry("Sobel"); + Raz::OverlayPlotEntry& cannyPlot = plot.addEntry("Canny"); Raz::OverlayPlotEntry& chromAberrPlot = plot.addEntry("Chrom. aberr."); Raz::OverlayPlotEntry& blurPlot = plot.addEntry("Blur"); Raz::OverlayPlotEntry& vignettePlot = plot.addEntry("Vignette"); @@ -303,6 +370,8 @@ end)"; #if !defined(USE_OPENGL_ES) app.run([&] (const Raz::FrameTimeInfo&) { geomPlot.push(geometryPass.recoverElapsedTime()); + sobelPlot.push(sobel.recoverElapsedTime()); + cannyPlot.push(canny.recoverElapsedTime()); chromAberrPlot.push(chromaticAberration.recoverElapsedTime()); blurPlot.push(boxBlur.recoverElapsedTime()); vignettePlot.push(vignette.recoverElapsedTime());