mirror of
https://github.com/JulianGro/overte.git
synced 2025-08-08 09:47:47 +02:00
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:
parent
d61652f958
commit
d86c3c4f2a
4 changed files with 46 additions and 21 deletions
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue