Renamed to OutlineEffect and working on debugging tool. Problems with outline framebuffer not complete

This commit is contained in:
Olivier Prat 2017-08-08 18:41:57 +02:00
parent 27227d6bd2
commit 44ee7c4bf1
7 changed files with 382 additions and 131 deletions

View file

@ -0,0 +1,207 @@
//
// OutlineEffect.cpp
// render-utils/src/
//
// Created by Olivier Prat on 08/08/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "OutlineEffect.h"
#include "GeometryCache.h"
#include "gpu/Context.h"
#include "gpu/StandardShaderLib.h"
#include "surfaceGeometry_copyDepth_frag.h"
#include "debug_deferred_buffer_vert.h"
#include "debug_deferred_buffer_frag.h"
OutlineFramebuffer::OutlineFramebuffer() {
}
void OutlineFramebuffer::update(const gpu::TexturePointer& linearDepthBuffer) {
//If the depth buffer or size changed, we need to delete our FBOs
bool reset = false;
if (_depthTexture) {
auto newFrameSize = glm::ivec2(linearDepthBuffer->getDimensions());
if (_frameSize != newFrameSize) {
_frameSize = newFrameSize;
reset = true;
}
}
if (reset) {
clear();
}
}
void OutlineFramebuffer::clear() {
_depthFramebuffer.reset();
_depthTexture.reset();
}
void OutlineFramebuffer::allocate() {
auto width = _frameSize.x;
auto height = _frameSize.y;
auto colorFormat = gpu::Element::VEC4F_COLOR_RGBA; // TODO : find a more compact format
_depthFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("outlineDepth", colorFormat, width, height));
_depthTexture = _depthFramebuffer->getRenderBuffer(0);
}
gpu::FramebufferPointer OutlineFramebuffer::getDepthFramebuffer() {
if (!_depthFramebuffer) {
allocate();
}
return _depthFramebuffer;
}
gpu::TexturePointer OutlineFramebuffer::getDepthTexture() {
if (!_depthTexture) {
allocate();
}
return _depthTexture;
}
void PrepareOutline::run(const render::RenderContextPointer& renderContext, const PrepareOutline::Input& input, PrepareOutline::Output& output) {
auto outlinedItems = input.get1();
if (!outlinedItems.empty()) {
glm::uvec2 frameSize(renderContext->args->_viewport.z, renderContext->args->_viewport.w);
auto args = renderContext->args;
auto deferredFrameBuffer = input.get0();
if (!_outlineFramebuffer) {
_outlineFramebuffer = std::make_shared<OutlineFramebuffer>();
}
_outlineFramebuffer->update(deferredFrameBuffer->getPrimaryDepthTexture());
if (!_copyDepthPipeline) {
auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS();
auto ps = gpu::Shader::createPixel(std::string(surfaceGeometry_copyDepth_frag));
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("depthMap"), 0));
gpu::Shader::makeProgram(*program, slotBindings);
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
state->setColorWriteMask(true, false, false, false);
// Good to go add the brand new pipeline
_copyDepthPipeline = gpu::Pipeline::create(program, state);
}
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
auto depthBuffer = deferredFrameBuffer->getPrimaryDepthTexture();
// Copy depth to texture as we will overwrite
batch.enableStereo(false);
batch.setViewportTransform(args->_viewport);
batch.setProjectionTransform(glm::mat4());
batch.resetViewTransform();
batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(frameSize, args->_viewport));
batch.setFramebuffer(_outlineFramebuffer->getDepthFramebuffer());
batch.setPipeline(_copyDepthPipeline);
batch.setResourceTexture(0, depthBuffer);
batch.draw(gpu::TRIANGLE_STRIP, 4);
// Restore previous frame buffer
batch.setFramebuffer(deferredFrameBuffer->getDeferredFramebuffer());
});
output = _outlineFramebuffer;
} else {
output = nullptr;
}
}
DebugOutline::DebugOutline() {
_geometryId = DependencyManager::get<GeometryCache>()->allocateID();
}
DebugOutline::~DebugOutline() {
auto geometryCache = DependencyManager::get<GeometryCache>();
if (geometryCache) {
geometryCache->releaseID(_geometryId);
}
}
void DebugOutline::configure(const Config& config) {
_isDisplayDepthEnabled = config.viewOutlinedDepth;
}
void DebugOutline::run(const render::RenderContextPointer& renderContext, const Input& input) {
if (_isDisplayDepthEnabled && input) {
assert(renderContext->args);
assert(renderContext->args->hasViewFrustum());
RenderArgs* args = renderContext->args;
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
batch.enableStereo(false);
batch.setViewportTransform(args->_viewport);
const auto geometryBuffer = DependencyManager::get<GeometryCache>();
glm::mat4 projMat;
Transform viewMat;
args->getViewFrustum().evalProjectionMatrix(projMat);
args->getViewFrustum().evalViewTransform(viewMat);
batch.setProjectionTransform(projMat);
batch.setViewTransform(viewMat, true);
batch.setModelTransform(Transform());
batch.setPipeline(getDebugPipeline());
batch.setResourceTexture(0, input->getDepthTexture());
const glm::vec4 color(1.0f, 0.5f, 0.2f, 1.0f);
const glm::vec2 bottomLeft(-1.0f, -1.0f);
const glm::vec2 topRight(1.0f, 1.0f);
geometryBuffer->renderQuad(batch, bottomLeft, topRight, color, _geometryId);
batch.setResourceTexture(0, nullptr);
});
}
}
const gpu::PipelinePointer& DebugOutline::getDebugPipeline() {
if (!_debugPipeline) {
static const std::string VERTEX_SHADER{ debug_deferred_buffer_vert };
static const std::string FRAGMENT_SHADER{ debug_deferred_buffer_frag };
static const std::string SOURCE_PLACEHOLDER{ "//SOURCE_PLACEHOLDER" };
static const auto SOURCE_PLACEHOLDER_INDEX = FRAGMENT_SHADER.find(SOURCE_PLACEHOLDER);
Q_ASSERT_X(SOURCE_PLACEHOLDER_INDEX != std::string::npos, Q_FUNC_INFO,
"Could not find source placeholder");
static const std::string DEFAULT_DEPTH_SHADER{
"vec4 getFragmentColor() {"
" float depth = texture(depthMap, uv).x;"
" return vec4(vec3(depth), 1.0);"
" }"
};
auto bakedFragmentShader = FRAGMENT_SHADER;
bakedFragmentShader.replace(SOURCE_PLACEHOLDER_INDEX, SOURCE_PLACEHOLDER.size(), DEFAULT_DEPTH_SHADER);
static const auto vs = gpu::Shader::createVertex(VERTEX_SHADER);
const auto ps = gpu::Shader::createPixel(bakedFragmentShader);
const auto program = gpu::Shader::createProgram(vs, ps);
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding("depthMap", 0));
gpu::Shader::makeProgram(*program, slotBindings);
auto state = std::make_shared<gpu::State>();
state->setDepthTest(gpu::State::DepthTest(false));
state->setColorWriteMask(true, false, false, false);
_debugPipeline = gpu::Pipeline::create(program, state);
}
return _debugPipeline;
}

View file

@ -0,0 +1,112 @@
//
// OutlineEffect.h
// render-utils/src/
//
// Created by Olivier Prat on 08/08/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_render_utils_OutlineEffect_h
#define hifi_render_utils_OutlineEffect_h
#include <render/Engine.h>
#include "DeferredFramebuffer.h"
/*
class PickItemsConfig : public render::Job::Config {
Q_OBJECT
Q_PROPERTY(bool isEnabled MEMBER isEnabled NOTIFY dirty)
public:
bool isEnabled{ false };
signals:
void dirty();
};
*/
class OutlineFramebuffer {
public:
OutlineFramebuffer();
gpu::FramebufferPointer getDepthFramebuffer();
gpu::TexturePointer getDepthTexture();
// Update the source framebuffer size which will drive the allocation of all the other resources.
void update(const gpu::TexturePointer& linearDepthBuffer);
const glm::ivec2& getSourceFrameSize() const { return _frameSize; }
protected:
void clear();
void allocate();
gpu::FramebufferPointer _depthFramebuffer;
gpu::TexturePointer _depthTexture;
glm::ivec2 _frameSize;
};
using OutlineFramebufferPointer = std::shared_ptr<OutlineFramebuffer>;
class PrepareOutline {
public:
using Input = render::VaryingSet2<DeferredFramebufferPointer, render::ItemBounds>;
// Output will contain outlined objects only z-depth texture
using Output = OutlineFramebufferPointer;
using JobModel = render::Job::ModelIO<PrepareOutline, Input, Output>;
PrepareOutline() {}
void run(const render::RenderContextPointer& renderContext, const PrepareOutline::Input& input, PrepareOutline::Output& output);
private:
OutlineFramebufferPointer _outlineFramebuffer;
gpu::PipelinePointer _copyDepthPipeline;
};
class DebugOutlineConfig : public render::Job::Config {
Q_OBJECT
Q_PROPERTY(bool viewOutlinedDepth MEMBER viewOutlinedDepth NOTIFY dirty)
public:
bool viewOutlinedDepth{ false };
signals:
void dirty();
};
class DebugOutline {
public:
using Input = OutlineFramebufferPointer;
using Config = DebugOutlineConfig;
using JobModel = render::Job::ModelI<DebugOutline, Input, Config>;
DebugOutline();
~DebugOutline();
void configure(const Config& config);
void run(const render::RenderContextPointer& renderContext, const Input& inputs);
private:
const gpu::PipelinePointer& getDebugPipeline();
gpu::PipelinePointer _debugPipeline;
int _geometryId{ 0 };
bool _isDisplayDepthEnabled{ false };
};
#endif // hifi_render_utils_OutlineEffect_h

View file

@ -40,7 +40,7 @@
#include "ToneMappingEffect.h"
#include "SubsurfaceScattering.h"
#include "PickItemsJob.h"
#include "RenderOutline.h"
#include "OutlineEffect.h"
#include <gpu/StandardShaderLib.h>
@ -95,7 +95,8 @@ 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 outlinedZBuffer = task.addJob<PrepareOutline>("PrepareOutline", deferredFramebuffer);
const auto outlinePrepareInputs = PrepareOutline::Input(deferredFramebuffer, outlinedOpaques).hasVarying();
const auto outlinedFrameBuffer = task.addJob<PrepareOutline>("PrepareOutline", outlinePrepareInputs);
// Render opaque objects in DeferredBuffer
const auto opaqueInputs = DrawStateSortDeferred::Inputs(opaques, lightingModel).hasVarying();
@ -199,6 +200,9 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
const auto debugAmbientOcclusionInputs = DebugAmbientOcclusion::Inputs(deferredFrameTransform, deferredFramebuffer, linearDepthTarget, ambientOcclusionUniforms).hasVarying();
task.addJob<DebugAmbientOcclusion>("DebugAmbientOcclusion", debugAmbientOcclusionInputs);
// Debug outline
task.addJob<DebugOutline>("DebugOutline", outlinedFrameBuffer);
// Scene Octree Debugging job
{
task.addJob<DrawSceneOctree>("DrawSceneOctree", spatialSelection);

View file

@ -1,76 +0,0 @@
//
// RenderOutline.cpp
// render-utils/src/
//
// Created by Olivier Prat on 08/08/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "RenderOutline.h"
#include "gpu/Context.h"
#include "gpu/StandardShaderLib.h"
#include "surfaceGeometry_copyDepth_frag.h"
void PrepareOutline::run(const render::RenderContextPointer& renderContext, const PrepareOutline::Input& deferredFramebuffer, PrepareOutline::Output& output) {
glm::uvec2 frameSize(renderContext->args->_viewport.z, renderContext->args->_viewport.w);
auto args = renderContext->args;
// Resizing framebuffers instead of re-building them seems to cause issues with threaded
// rendering
if (_outlineFramebuffer && _outlineFramebuffer->getSize() != frameSize) {
_outlineFramebuffer.reset();
}
if (!_outlineFramebuffer) {
_outlineFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("deferredOutline"));
auto colorFormat = gpu::Element::COLOR_RED_HALF;
auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT);
auto primaryColorTexture = gpu::Texture::createRenderBuffer(colorFormat, frameSize.x, frameSize.y, gpu::Texture::SINGLE_MIP, defaultSampler);
_outlineFramebuffer->setRenderBuffer(0, primaryColorTexture);
}
if (!_copyDepthPipeline) {
auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS();
auto ps = gpu::Shader::createPixel(std::string(surfaceGeometry_copyDepth_frag));
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("depthMap"), 0));
gpu::Shader::makeProgram(*program, slotBindings);
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
state->setColorWriteMask(true, false, false, false);
// Good to go add the brand new pipeline
_copyDepthPipeline = gpu::Pipeline::create(program, state);
}
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
auto depthBuffer = deferredFramebuffer->getPrimaryDepthTexture();
// Copy depth to texture as we will overwrite
batch.enableStereo(false);
batch.setViewportTransform(args->_viewport);
batch.setProjectionTransform(glm::mat4());
batch.resetViewTransform();
batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(frameSize, args->_viewport));
batch.setFramebuffer(_outlineFramebuffer);
batch.setPipeline(_copyDepthPipeline);
batch.setResourceTexture(0, depthBuffer);
batch.draw(gpu::TRIANGLE_STRIP, 4);
// Restore previous frame buffer
batch.setFramebuffer(deferredFramebuffer->getDeferredFramebuffer());
});
output = _outlineFramebuffer->getRenderBuffer(0);
}

View file

@ -1,53 +0,0 @@
//
// RenderOutline.h
// render-utils/src/
//
// Created by Olivier Prat on 08/08/17.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_render_utils_RenderOutline_h
#define hifi_render_utils_RenderOutline_h
#include <render/Engine.h>
#include "DeferredFramebuffer.h"
/*
class PickItemsConfig : public render::Job::Config {
Q_OBJECT
Q_PROPERTY(bool isEnabled MEMBER isEnabled NOTIFY dirty)
public:
bool isEnabled{ false };
signals:
void dirty();
};
*/
class PrepareOutline {
public:
using Input = DeferredFramebufferPointer;
// Output will contain outlined objects only z-depth texture
using Output = gpu::TexturePointer;
using JobModel = render::Job::ModelIO<PrepareOutline, Input, Output>;
PrepareOutline() {}
void run(const render::RenderContextPointer& renderContext, const PrepareOutline::Input& input, PrepareOutline::Output& output);
private:
gpu::FramebufferPointer _outlineFramebuffer;
gpu::PipelinePointer _copyDepthPipeline;
};
#endif // hifi_render_utils_RenderOutline_h

View file

@ -0,0 +1,20 @@
//
// debugOutline.js
// developer/utilities/render
//
// Olivier Prat, created on 08/08/2017.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
// Set up the qml ui
var qml = Script.resolvePath('outline.qml');
var window = new OverlayWindow({
title: 'Outline',
source: qml,
width: 250,
height: 80,
});
window.closed.connect(function() { Script.stop(); });

View file

@ -0,0 +1,37 @@
//
// outline.qml
// developer/utilities/render
//
// Olivier Prat, created on 08/08/2017.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import QtQuick.Controls 1.4
Item {
id: root
property var pickConfig: Render.getConfig("RenderMainView.PickOutlined")
property var debugConfig: Render.getConfig("RenderMainView.DebugOutline")
Column {
spacing: 8
CheckBox {
text: "Edit Outline"
checked: root.pickConfig["enabled"]
onCheckedChanged: {
root.pickConfig["enabled"] = checked;
}
}
CheckBox {
text: "View Outlined Depth"
checked: root.debugConfig["viewOutlinedDepth"]
onCheckedChanged: {
root.debugConfig["viewOutlinedDepth"] = checked;
}
}
}
}