diff --git a/libraries/render-utils/src/BloomEffect.cpp b/libraries/render-utils/src/BloomEffect.cpp index c6c30e7ff6..e236b290c2 100644 --- a/libraries/render-utils/src/BloomEffect.cpp +++ b/libraries/render-utils/src/BloomEffect.cpp @@ -21,15 +21,15 @@ #define BLOOM_BLUR_LEVEL_COUNT 3 -ThresholdAndDownsampleJob::ThresholdAndDownsampleJob() { +BloomThreshold::BloomThreshold() { } -void ThresholdAndDownsampleJob::configure(const Config& config) { +void BloomThreshold::configure(const Config& config) { _threshold = config.threshold; } -void ThresholdAndDownsampleJob::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { +void BloomThreshold::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { assert(renderContext->args); assert(renderContext->args->hasViewFrustum()); @@ -40,25 +40,23 @@ void ThresholdAndDownsampleJob::run(const render::RenderContextPointer& renderCo assert(inputFrameBuffer->hasColor()); - auto inputColor = inputFrameBuffer->getRenderBuffer(0); + auto inputBuffer = inputFrameBuffer->getRenderBuffer(0); auto sourceViewport = args->_viewport; - auto fullSize = glm::ivec2(inputColor->getDimensions()); - auto halfSize = fullSize / 2; - auto halfViewport = args->_viewport >> 1; + auto bufferSize = glm::ivec2(inputBuffer->getDimensions()); - if (!_downsampledBuffer || _downsampledBuffer->getSize().x != halfSize.x || _downsampledBuffer->getSize().y != halfSize.y) { - auto colorTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(inputColor->getTexelFormat(), halfSize.x, halfSize.y, + if (!_outputBuffer || _outputBuffer->getSize() != inputFrameBuffer->getSize()) { + auto colorTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(inputBuffer->getTexelFormat(), bufferSize.x, bufferSize.y, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT))); - _downsampledBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("BloomThreshold")); - _downsampledBuffer->setRenderBuffer(0, colorTexture); + _outputBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("BloomThreshold")); + _outputBuffer->setRenderBuffer(0, colorTexture); } static const int COLOR_MAP_SLOT = 0; static const int THRESHOLD_SLOT = 1; if (!_pipeline) { - auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); + auto vs = gpu::StandardShaderLib::getDrawTransformUnitQuadVS(); auto ps = gpu::Shader::createPixel(std::string(BloomThreshold_frag)); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); @@ -74,23 +72,19 @@ void ThresholdAndDownsampleJob::run(const render::RenderContextPointer& renderCo gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { batch.enableStereo(false); - batch.setViewportTransform(halfViewport); + batch.setViewportTransform(args->_viewport); batch.setProjectionTransform(glm::mat4()); batch.resetViewTransform(); - batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(inputFrameBuffer->getSize(), args->_viewport)); + batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(bufferSize, args->_viewport)); batch.setPipeline(_pipeline); - batch.setFramebuffer(_downsampledBuffer); - batch.setResourceTexture(COLOR_MAP_SLOT, inputColor); + batch.setFramebuffer(_outputBuffer); + batch.setResourceTexture(COLOR_MAP_SLOT, inputBuffer); batch._glUniform1f(THRESHOLD_SLOT, _threshold); batch.draw(gpu::TRIANGLE_STRIP, 4); - - batch.setViewportTransform(args->_viewport); - batch.setResourceTexture(COLOR_MAP_SLOT, nullptr); - batch.setFramebuffer(nullptr); }); - outputs = _downsampledBuffer; + outputs = _outputBuffer; } BloomApply::BloomApply() { @@ -287,14 +281,27 @@ void Bloom::configure(const Config& config) { } void Bloom::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs) { - const auto bloomInputBuffer = task.addJob("BloomThreshold", inputs); + const auto bloomInputBuffer = task.addJob("BloomThreshold", inputs); + const auto bloomHalfInputBuffer = task.addJob("BloomHalf", bloomInputBuffer); + const auto bloomQuarterInputBuffer = task.addJob("BloomQuarter", bloomHalfInputBuffer); +#if 1 // Multi-scale blur - const auto blurFB0 = task.addJob("BloomBlur0", bloomInputBuffer); + const auto blurFB0 = task.addJob("BloomBlur0", bloomQuarterInputBuffer); const auto halfBlurFB0 = task.addJob("BloomHalfBlur0", blurFB0); const auto blurFB1 = task.addJob("BloomBlur1", halfBlurFB0, true); const auto halfBlurFB1 = task.addJob("BloomHalfBlur1", blurFB1); const auto blurFB2 = task.addJob("BloomBlur2", halfBlurFB1, true); +#else + // Multi-scale downsampling debug + const auto blurFB0 = bloomQuarterInputBuffer; + const auto blurFB1 = task.addJob("BloomHalfBlur1", blurFB0); + const auto blurFB2 = task.addJob("BloomHalfBlur2", blurFB1); + // This is only needed so as not to crash as we expect to have the three blur jobs + task.addJob("BloomBlur0", bloomHalfInputBuffer, true); + task.addJob("BloomBlur1", blurFB1, true); + task.addJob("BloomBlur2", blurFB2, true); +#endif const auto& input = inputs.get(); const auto& frameBuffer = input[1]; diff --git a/libraries/render-utils/src/BloomEffect.h b/libraries/render-utils/src/BloomEffect.h index 637e37aa04..fdc2d1a0ba 100644 --- a/libraries/render-utils/src/BloomEffect.h +++ b/libraries/render-utils/src/BloomEffect.h @@ -25,7 +25,7 @@ public: BloomConfig() : render::Task::Config(true) {} - float size{ 0.45f }; + float size{ 0.8f }; void setIntensity(float value); float getIntensity() const; @@ -35,7 +35,7 @@ signals: void dirty(); }; -class ThresholdConfig : public render::Job::Config { +class BloomThresholdConfig : public render::Job::Config { Q_OBJECT Q_PROPERTY(float threshold MEMBER threshold NOTIFY dirty) @@ -47,21 +47,21 @@ signals: void dirty(); }; -class ThresholdAndDownsampleJob { +class BloomThreshold { public: using Inputs = render::VaryingSet2; using Outputs = gpu::FramebufferPointer; - using Config = ThresholdConfig; - using JobModel = render::Job::ModelIO; + using Config = BloomThresholdConfig; + using JobModel = render::Job::ModelIO; - ThresholdAndDownsampleJob(); + BloomThreshold(); void configure(const Config& config); void run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs); private: - gpu::FramebufferPointer _downsampledBuffer; + gpu::FramebufferPointer _outputBuffer; gpu::PipelinePointer _pipeline; float _threshold; }; @@ -73,7 +73,7 @@ class BloomApplyConfig : public render::Job::Config { public: - float intensity{ 0.5f }; + float intensity{ 0.8f }; signals: void dirty(); diff --git a/libraries/render-utils/src/BloomThreshold.slf b/libraries/render-utils/src/BloomThreshold.slf index d14da4889d..14d20dd684 100644 --- a/libraries/render-utils/src/BloomThreshold.slf +++ b/libraries/render-utils/src/BloomThreshold.slf @@ -17,29 +17,11 @@ in vec2 varTexCoord0; out vec4 outFragColor; void main(void) { - // Gather 2 by 2 quads from texture, threshold and downsample - vec4 reds = textureGather(colorMap, varTexCoord0, 0); - vec4 greens = textureGather(colorMap, varTexCoord0, 1); - vec4 blues = textureGather(colorMap, varTexCoord0, 2); + vec4 color = texture(colorMap, varTexCoord0); + float luminance = (color.r+color.g+color.b) / 3.0; + float mask = clamp((luminance-threshold)*0.25, 0, 1); - vec3 texel0 = vec3(reds.x, greens.x, blues.x); - vec3 texel1 = vec3(reds.y, greens.y, blues.y); - vec3 texel2 = vec3(reds.z, greens.z, blues.z); - vec3 texel3 = vec3(reds.w, greens.w, blues.w); + color *= mask; - vec4 luminances; - vec3 luminanceWeights = vec3(0.333,0.333,0.333); - - luminances.x = dot(texel0, luminanceWeights); - luminances.y = dot(texel1, luminanceWeights); - luminances.z = dot(texel2, luminanceWeights); - luminances.w = dot(texel0, luminanceWeights); - - vec4 mask = clamp(luminances-threshold, 0, 1); - vec3 color; - - color.x = dot(mask, reds); - color.y = dot(mask, greens); - color.z = dot(mask, blues); - outFragColor = vec4(color/4.0, 1.0); + outFragColor = vec4(color.rgb, 1.0); } diff --git a/libraries/render/src/render/ResampleTask.cpp b/libraries/render/src/render/ResampleTask.cpp index 5d4b5c18cb..ef75b54094 100644 --- a/libraries/render/src/render/ResampleTask.cpp +++ b/libraries/render/src/render/ResampleTask.cpp @@ -48,15 +48,12 @@ void HalfDownsample::run(const RenderContextPointer& renderContext, const gpu::F resampledFrameBuffer = getResampledFrameBuffer(sourceFramebuffer); - static auto TEXCOORD_RECT_SLOT = 1; - if (!_pipeline) { - auto vs = gpu::StandardShaderLib::getDrawTexcoordRectTransformUnitQuadVS(); + auto vs = gpu::StandardShaderLib::getDrawTransformUnitQuadVS(); auto ps = gpu::StandardShaderLib::getDrawTextureOpaquePS(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; - slotBindings.insert(gpu::Shader::Binding(std::string("texcoordRect"), TEXCOORD_RECT_SLOT)); gpu::Shader::makeProgram(*program, slotBindings); gpu::StatePointer state = gpu::StatePointer(new gpu::State()); @@ -80,9 +77,6 @@ void HalfDownsample::run(const RenderContextPointer& renderContext, const gpu::F batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(bufferSize, viewport)); batch.setResourceTexture(0, sourceFramebuffer->getRenderBuffer(0)); - // Add half a texel of offset to be sure to sample in the middle of 4 neighbouring texture pixels - // to perform box filtering. - batch._glUniform4f(TEXCOORD_RECT_SLOT, 0.5f / sourceSize.x, 0.5f / sourceSize.y, 1.f, 1.f); batch.draw(gpu::TRIANGLE_STRIP, 4); }); }