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
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<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
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 blurFB1 = task.addJob<render::BlurGaussian>("BloomBlur1", halfBlurFB0, true);
const auto halfBlurFB1 = task.addJob<render::HalfDownsample>("BloomHalfBlur1", blurFB1);
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& frameBuffer = input[1];

View file

@ -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<DeferredFrameTransformPointer, gpu::FramebufferPointer>;
using Outputs = gpu::FramebufferPointer;
using Config = ThresholdConfig;
using JobModel = render::Job::ModelIO<ThresholdAndDownsampleJob, Inputs, Outputs, Config>;
using Config = BloomThresholdConfig;
using JobModel = render::Job::ModelIO<BloomThreshold, Inputs, Outputs, Config>;
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();

View file

@ -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);
}

View file

@ -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);
});
}