Threshold now doesn't downsample anymore. Done in separate pass

This commit is contained in:
Olivier Prat 2017-10-10 17:49:35 +02:00
parent 76305c5285
commit f55d44dfc3
4 changed files with 44 additions and 61 deletions

View file

@ -21,15 +21,15 @@
#define BLOOM_BLUR_LEVEL_COUNT 3 #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; _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);
assert(renderContext->args->hasViewFrustum()); assert(renderContext->args->hasViewFrustum());
@ -40,25 +40,23 @@ void ThresholdAndDownsampleJob::run(const render::RenderContextPointer& renderCo
assert(inputFrameBuffer->hasColor()); assert(inputFrameBuffer->hasColor());
auto inputColor = inputFrameBuffer->getRenderBuffer(0); auto inputBuffer = inputFrameBuffer->getRenderBuffer(0);
auto sourceViewport = args->_viewport; auto sourceViewport = args->_viewport;
auto fullSize = glm::ivec2(inputColor->getDimensions()); auto bufferSize = glm::ivec2(inputBuffer->getDimensions());
auto halfSize = fullSize / 2;
auto halfViewport = args->_viewport >> 1;
if (!_downsampledBuffer || _downsampledBuffer->getSize().x != halfSize.x || _downsampledBuffer->getSize().y != halfSize.y) { if (!_outputBuffer || _outputBuffer->getSize() != inputFrameBuffer->getSize()) {
auto colorTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(inputColor->getTexelFormat(), halfSize.x, halfSize.y, 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))); gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT)));
_downsampledBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("BloomThreshold")); _outputBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("BloomThreshold"));
_downsampledBuffer->setRenderBuffer(0, colorTexture); _outputBuffer->setRenderBuffer(0, colorTexture);
} }
static const int COLOR_MAP_SLOT = 0; static const int COLOR_MAP_SLOT = 0;
static const int THRESHOLD_SLOT = 1; static const int THRESHOLD_SLOT = 1;
if (!_pipeline) { if (!_pipeline) {
auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); auto vs = gpu::StandardShaderLib::getDrawTransformUnitQuadVS();
auto ps = gpu::Shader::createPixel(std::string(BloomThreshold_frag)); auto ps = gpu::Shader::createPixel(std::string(BloomThreshold_frag));
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); 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) { gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
batch.enableStereo(false); batch.enableStereo(false);
batch.setViewportTransform(halfViewport); batch.setViewportTransform(args->_viewport);
batch.setProjectionTransform(glm::mat4()); batch.setProjectionTransform(glm::mat4());
batch.resetViewTransform(); batch.resetViewTransform();
batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(inputFrameBuffer->getSize(), args->_viewport)); batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(bufferSize, args->_viewport));
batch.setPipeline(_pipeline); batch.setPipeline(_pipeline);
batch.setFramebuffer(_downsampledBuffer); batch.setFramebuffer(_outputBuffer);
batch.setResourceTexture(COLOR_MAP_SLOT, inputColor); batch.setResourceTexture(COLOR_MAP_SLOT, inputBuffer);
batch._glUniform1f(THRESHOLD_SLOT, _threshold); batch._glUniform1f(THRESHOLD_SLOT, _threshold);
batch.draw(gpu::TRIANGLE_STRIP, 4); 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() { BloomApply::BloomApply() {
@ -287,14 +281,27 @@ void Bloom::configure(const Config& config) {
} }
void Bloom::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs) { void Bloom::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs) {
const auto bloomInputBuffer = task.addJob<ThresholdAndDownsampleJob>("BloomThreshold", inputs); const auto bloomInputBuffer = task.addJob<BloomThreshold>("BloomThreshold", inputs);
const auto bloomHalfInputBuffer = task.addJob<render::HalfDownsample>("BloomHalf", bloomInputBuffer);
const auto bloomQuarterInputBuffer = task.addJob<render::HalfDownsample>("BloomQuarter", bloomHalfInputBuffer);
#if 1
// Multi-scale blur // Multi-scale blur
const auto blurFB0 = task.addJob<render::BlurGaussian>("BloomBlur0", bloomInputBuffer); const auto blurFB0 = task.addJob<render::BlurGaussian>("BloomBlur0", bloomQuarterInputBuffer);
const auto halfBlurFB0 = task.addJob<render::HalfDownsample>("BloomHalfBlur0", blurFB0); const auto halfBlurFB0 = task.addJob<render::HalfDownsample>("BloomHalfBlur0", blurFB0);
const auto blurFB1 = task.addJob<render::BlurGaussian>("BloomBlur1", halfBlurFB0, true); const auto blurFB1 = task.addJob<render::BlurGaussian>("BloomBlur1", halfBlurFB0, true);
const auto halfBlurFB1 = task.addJob<render::HalfDownsample>("BloomHalfBlur1", blurFB1); const auto halfBlurFB1 = task.addJob<render::HalfDownsample>("BloomHalfBlur1", blurFB1);
const auto blurFB2 = task.addJob<render::BlurGaussian>("BloomBlur2", halfBlurFB1, true); const auto blurFB2 = task.addJob<render::BlurGaussian>("BloomBlur2", halfBlurFB1, true);
#else
// Multi-scale downsampling debug
const auto blurFB0 = bloomQuarterInputBuffer;
const auto blurFB1 = task.addJob<render::HalfDownsample>("BloomHalfBlur1", blurFB0);
const auto blurFB2 = task.addJob<render::HalfDownsample>("BloomHalfBlur2", blurFB1);
// This is only needed so as not to crash as we expect to have the three blur jobs
task.addJob<render::BlurGaussian>("BloomBlur0", bloomHalfInputBuffer, true);
task.addJob<render::BlurGaussian>("BloomBlur1", blurFB1, true);
task.addJob<render::BlurGaussian>("BloomBlur2", blurFB2, true);
#endif
const auto& input = inputs.get<Inputs>(); const auto& input = inputs.get<Inputs>();
const auto& frameBuffer = input[1]; const auto& frameBuffer = input[1];

View file

@ -25,7 +25,7 @@ public:
BloomConfig() : render::Task::Config(true) {} BloomConfig() : render::Task::Config(true) {}
float size{ 0.45f }; float size{ 0.8f };
void setIntensity(float value); void setIntensity(float value);
float getIntensity() const; float getIntensity() const;
@ -35,7 +35,7 @@ signals:
void dirty(); void dirty();
}; };
class ThresholdConfig : public render::Job::Config { class BloomThresholdConfig : public render::Job::Config {
Q_OBJECT Q_OBJECT
Q_PROPERTY(float threshold MEMBER threshold NOTIFY dirty) Q_PROPERTY(float threshold MEMBER threshold NOTIFY dirty)
@ -47,21 +47,21 @@ signals:
void dirty(); void dirty();
}; };
class ThresholdAndDownsampleJob { class BloomThreshold {
public: public:
using Inputs = render::VaryingSet2<DeferredFrameTransformPointer, gpu::FramebufferPointer>; using Inputs = render::VaryingSet2<DeferredFrameTransformPointer, gpu::FramebufferPointer>;
using Outputs = gpu::FramebufferPointer; using Outputs = gpu::FramebufferPointer;
using Config = ThresholdConfig; using Config = BloomThresholdConfig;
using JobModel = render::Job::ModelIO<ThresholdAndDownsampleJob, Inputs, Outputs, Config>; using JobModel = render::Job::ModelIO<BloomThreshold, Inputs, Outputs, Config>;
ThresholdAndDownsampleJob(); BloomThreshold();
void configure(const Config& config); void configure(const Config& config);
void run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs); void run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs);
private: private:
gpu::FramebufferPointer _downsampledBuffer; gpu::FramebufferPointer _outputBuffer;
gpu::PipelinePointer _pipeline; gpu::PipelinePointer _pipeline;
float _threshold; float _threshold;
}; };
@ -73,7 +73,7 @@ class BloomApplyConfig : public render::Job::Config {
public: public:
float intensity{ 0.5f }; float intensity{ 0.8f };
signals: signals:
void dirty(); void dirty();

View file

@ -17,29 +17,11 @@ in vec2 varTexCoord0;
out vec4 outFragColor; out vec4 outFragColor;
void main(void) { void main(void) {
// Gather 2 by 2 quads from texture, threshold and downsample vec4 color = texture(colorMap, varTexCoord0);
vec4 reds = textureGather(colorMap, varTexCoord0, 0); float luminance = (color.r+color.g+color.b) / 3.0;
vec4 greens = textureGather(colorMap, varTexCoord0, 1); float mask = clamp((luminance-threshold)*0.25, 0, 1);
vec4 blues = textureGather(colorMap, varTexCoord0, 2);
vec3 texel0 = vec3(reds.x, greens.x, blues.x); color *= mask;
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);
vec4 luminances; outFragColor = vec4(color.rgb, 1.0);
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);
} }

View file

@ -48,15 +48,12 @@ void HalfDownsample::run(const RenderContextPointer& renderContext, const gpu::F
resampledFrameBuffer = getResampledFrameBuffer(sourceFramebuffer); resampledFrameBuffer = getResampledFrameBuffer(sourceFramebuffer);
static auto TEXCOORD_RECT_SLOT = 1;
if (!_pipeline) { if (!_pipeline) {
auto vs = gpu::StandardShaderLib::getDrawTexcoordRectTransformUnitQuadVS(); auto vs = gpu::StandardShaderLib::getDrawTransformUnitQuadVS();
auto ps = gpu::StandardShaderLib::getDrawTextureOpaquePS(); auto ps = gpu::StandardShaderLib::getDrawTextureOpaquePS();
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
gpu::Shader::BindingSet slotBindings; gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("texcoordRect"), TEXCOORD_RECT_SLOT));
gpu::Shader::makeProgram(*program, slotBindings); gpu::Shader::makeProgram(*program, slotBindings);
gpu::StatePointer state = gpu::StatePointer(new gpu::State()); 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.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(bufferSize, viewport));
batch.setResourceTexture(0, sourceFramebuffer->getRenderBuffer(0)); 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); batch.draw(gpu::TRIANGLE_STRIP, 4);
}); });
} }