Outline is now drawn with framebuffer with no depth buffer attached to prevent concurrent depth clear on NVidia GPU cards

This commit is contained in:
Olivier Prat 2017-08-11 11:33:46 +02:00
parent d61652f958
commit d86c3c4f2a
4 changed files with 46 additions and 21 deletions

View file

@ -10,6 +10,8 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include DeferredTransform.slh@>
<$declareDeferredFrameTransform()$>
<@include Outline_shared.slh@>
@ -23,22 +25,27 @@ uniform sampler2D outlinedDepthMap;
in vec2 varTexCoord0;
out vec4 outFragColor;
const float FAR_DISTANCE = 1.0;
const float DEPTH_BIAS = 0.0;
const float FAR_Z = 1.0;
const float LINEAR_DEPTH_BIAS = 5e-3;
const float OPACITY_EPSILON = 5e-3;
void main(void) {
float outlinedDepth = texture(outlinedDepthMap, varTexCoord0).x;
float intensity = 0.0;
if (outlinedDepth < (FAR_DISTANCE-DEPTH_BIAS)) {
if (outlinedDepth < FAR_Z) {
// We're not on the far plane so we are on the outlined object, thus no outline to do!
// But maybe we need to fill the interior
// TODO: this should be done as another shader with switch done on CPU
if (params._fillOpacityUnoccluded>OPACITY_EPSILON && params._fillOpacityUnoccluded>OPACITY_EPSILON) {
// Are we occluded?
float sceneDepth = texture(sceneDepthMap, varTexCoord0).x;
if (sceneDepth < (outlinedDepth-DEPTH_BIAS)) {
// Transform to linear depth for better precision
outlinedDepth = -evalZeyeFromZdb(outlinedDepth);
sceneDepth = -evalZeyeFromZdb(sceneDepth);
// Are we occluded?
if (sceneDepth < (outlinedDepth-LINEAR_DEPTH_BIAS)) {
intensity = params._fillOpacityOccluded;
} else {
intensity = params._fillOpacityUnoccluded;
@ -63,7 +70,7 @@ void main(void) {
if (uv.x>=0.0 && uv.x<=1.0)
{
outlinedDepth = texture(outlinedDepthMap, uv).x;
intensity += (outlinedDepth < (FAR_DISTANCE-DEPTH_BIAS)) ? 1.0 : 0.0;
intensity += (outlinedDepth < FAR_Z) ? 1.0 : 0.0;
weight += 1.f;
}
uv.x += deltaUv.x;

View file

@ -70,12 +70,12 @@ gpu::TexturePointer OutlineFramebuffer::getDepthTexture() {
return _depthTexture;
}
void PrepareOutline::run(const render::RenderContextPointer& renderContext, const PrepareOutline::Inputs& input, PrepareOutline::Output& output) {
auto outlinedItems = input.get1();
void PrepareOutline::run(const render::RenderContextPointer& renderContext, const PrepareOutline::Inputs& inputs, PrepareOutline::Output& output) {
auto outlinedItems = inputs.get0();
if (!outlinedItems.empty()) {
auto args = renderContext->args;
auto deferredFrameBuffer = input.get0();
auto deferredFrameBuffer = inputs.get1();
auto frameSize = deferredFrameBuffer->getFrameSize();
if (!_outlineFramebuffer) {
@ -138,13 +138,20 @@ void DrawOutline::configure(const Config& config) {
}
void DrawOutline::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) {
auto mainFrameBuffer = inputs.get0();
auto mainFrameBuffer = inputs.get1();
if (mainFrameBuffer) {
auto sceneDepthBuffer = mainFrameBuffer->getPrimaryDepthTexture();
auto outlinedDepthBuffer = inputs.get1();
const auto frameTransform = inputs.get0();
auto outlinedDepthBuffer = inputs.get2();
auto destinationFrameBuffer = inputs.get3();
auto pipeline = getPipeline();
if (!_primaryWithoutDepthBuffer) {
_primaryWithoutDepthBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("primaryWithoutDepth"));
_primaryWithoutDepthBuffer->setRenderBuffer(0, destinationFrameBuffer->getRenderBuffer(0));
}
if (outlinedDepthBuffer) {
auto framebufferSize = glm::ivec2(sceneDepthBuffer->getDimensions());
auto args = renderContext->args;
@ -163,6 +170,7 @@ void DrawOutline::run(const render::RenderContextPointer& renderContext, const I
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
batch.enableStereo(false);
batch.setFramebuffer(_primaryWithoutDepthBuffer);
batch.setViewportTransform(args->_viewport);
batch.setProjectionTransform(glm::mat4());
@ -170,10 +178,14 @@ void DrawOutline::run(const render::RenderContextPointer& renderContext, const I
batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, args->_viewport));
batch.setPipeline(pipeline);
batch.setUniformBuffer(0, _configuration);
batch.setUniformBuffer(OUTLINE_PARAMS_SLOT, _configuration);
batch.setUniformBuffer(FRAME_TRANSFORM_SLOT, frameTransform->getFrameTransformBuffer());
batch.setResourceTexture(SCENE_DEPTH_SLOT, sceneDepthBuffer);
batch.setResourceTexture(OUTLINED_DEPTH_SLOT, outlinedDepthBuffer->getDepthTexture());
batch.draw(gpu::TRIANGLE_STRIP, 4);
// Restore previous frame buffer
batch.setFramebuffer(destinationFrameBuffer);
});
}
}
@ -186,13 +198,14 @@ const gpu::PipelinePointer& DrawOutline::getPipeline() {
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding("outlineParamsBuffer", 0));
slotBindings.insert(gpu::Shader::Binding("outlineParamsBuffer", OUTLINE_PARAMS_SLOT));
slotBindings.insert(gpu::Shader::Binding("deferredFrameTransformBuffer", FRAME_TRANSFORM_SLOT));
slotBindings.insert(gpu::Shader::Binding("sceneDepthMap", SCENE_DEPTH_SLOT));
slotBindings.insert(gpu::Shader::Binding("outlinedDepthMap", OUTLINED_DEPTH_SLOT));
gpu::Shader::makeProgram(*program, slotBindings);
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
state->setDepthTest(false);
state->setDepthTest(gpu::State::DepthTest(false, false));
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
_pipeline = gpu::Pipeline::create(program, state);
}

View file

@ -14,6 +14,7 @@
#include <render/Engine.h>
#include "DeferredFramebuffer.h"
#include "DeferredFrameTransform.h"
class OutlineFramebuffer {
public:
@ -43,9 +44,9 @@ class PrepareOutline {
public:
using Inputs = render::VaryingSet2<DeferredFramebufferPointer, render::ItemBounds>;
// Output will contain outlined objects only z-depth texture
using Output = OutlineFramebufferPointer;
using Inputs = render::VaryingSet2<render::ItemBounds, DeferredFramebufferPointer>;
// Output will contain outlined objects only z-depth texture and the input primary buffer but without the primary depth buffer
using Output = OutlineFramebufferPointer;
using JobModel = render::Job::ModelIO<PrepareOutline, Inputs, Output>;
PrepareOutline() {}
@ -93,7 +94,7 @@ signals:
class DrawOutline {
public:
using Inputs = render::VaryingSet2<DeferredFramebufferPointer, OutlineFramebufferPointer>;
using Inputs = render::VaryingSet4<DeferredFrameTransformPointer, DeferredFramebufferPointer, OutlineFramebufferPointer, gpu::FramebufferPointer>;
using Config = DrawOutlineConfig;
using JobModel = render::Job::ModelI<DrawOutline, Inputs, Config>;
@ -106,7 +107,10 @@ private:
enum {
SCENE_DEPTH_SLOT = 0,
OUTLINED_DEPTH_SLOT
OUTLINED_DEPTH_SLOT,
OUTLINE_PARAMS_SLOT = 0,
FRAME_TRANSFORM_SLOT
};
#include "Outline_shared.slh"
@ -115,6 +119,7 @@ private:
const gpu::PipelinePointer& getPipeline();
gpu::FramebufferPointer _primaryWithoutDepthBuffer;
gpu::PipelinePointer _pipeline;
OutlineConfigurationBuffer _configuration;
glm::vec3 _color;

View file

@ -109,7 +109,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
task.addJob<DrawStateSortDeferred>("DrawOpaqueOutlined", opaqueOutlineInputs, shapePlumber);
// Retrieve z value of the outlined objects
const auto outlinePrepareInputs = PrepareOutline::Inputs(deferredFramebuffer, outlinedOpaques).asVarying();
const auto outlinePrepareInputs = PrepareOutline::Inputs(outlinedOpaques, deferredFramebuffer).asVarying();
const auto outlinedFrameBuffer = task.addJob<PrepareOutline>("PrepareOutline", outlinePrepareInputs);
// Render opaque objects in DeferredBuffer
@ -182,7 +182,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
task.addJob<ToneMappingDeferred>("ToneMapping", toneMappingInputs);
// Draw outline
const auto outlineInputs = DrawOutline::Inputs(deferredFramebuffer, outlinedFrameBuffer).asVarying();
const auto outlineInputs = DrawOutline::Inputs(deferredFrameTransform, deferredFramebuffer, outlinedFrameBuffer, primaryFramebuffer).asVarying();
task.addJob<DrawOutline>("DrawOutline", outlineInputs);
{ // DEbug the bounds of the rendered items, still look at the zbuffer