mirror of
https://github.com/lubosz/overte.git
synced 2025-04-24 14:03:17 +02:00
First alpha working version of outline
This commit is contained in:
parent
f36500a74c
commit
01a028cbb6
9 changed files with 260 additions and 11 deletions
63
libraries/render-utils/src/Outline.slf
Normal file
63
libraries/render-utils/src/Outline.slf
Normal file
|
@ -0,0 +1,63 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
//
|
||||
// Add outline effect based on two zbuffers : one containing the total scene z and another
|
||||
// with the z of only the objects to be outlined
|
||||
//
|
||||
// Created by Olivier Prat on 08/09/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
|
||||
//
|
||||
|
||||
<@include Outline_shared.slh@>
|
||||
|
||||
uniform outlineParamsBuffer {
|
||||
OutlineParameters params;
|
||||
};
|
||||
|
||||
uniform sampler2D sceneDepthMap;
|
||||
uniform sampler2D outlinedDepthMap;
|
||||
|
||||
in vec2 varTexCoord0;
|
||||
out vec4 outFragColor;
|
||||
|
||||
const int BLUR_KERNEL_SIZE = 9;
|
||||
const float FAR_DISTANCE = 1.0;
|
||||
|
||||
void main(void) {
|
||||
float outlinedDepth = texture(outlinedDepthMap, varTexCoord0).x;
|
||||
if (outlinedDepth < FAR_DISTANCE) {
|
||||
// We're not on the far plane so we are on the outlined object, thus no outline to do!
|
||||
discard;
|
||||
}
|
||||
|
||||
//float sceneDepth = texture(sceneDepthMap, varTexCoord0).x;
|
||||
float outlineIntensity = 0.0;
|
||||
{
|
||||
const float deltaUv = params._size / BLUR_KERNEL_SIZE;
|
||||
vec2 uv;
|
||||
vec2 startUv = varTexCoord0 - vec2(params._size, params._size) / 2.0;
|
||||
int x;
|
||||
int y;
|
||||
|
||||
for (y=0 ; y<BLUR_KERNEL_SIZE ; y++) {
|
||||
uv = startUv;
|
||||
startUv.y += deltaUv;
|
||||
|
||||
for (x=0 ; x<BLUR_KERNEL_SIZE ; x++) {
|
||||
outlinedDepth = texture(outlinedDepthMap, uv).x;
|
||||
outlineIntensity += (outlinedDepth < FAR_DISTANCE) ? 1.0 : 0.0;
|
||||
uv.x += deltaUv;
|
||||
}
|
||||
}
|
||||
|
||||
outlineIntensity /= BLUR_KERNEL_SIZE*BLUR_KERNEL_SIZE;
|
||||
}
|
||||
|
||||
if (outlineIntensity < 1e-3) {
|
||||
discard;
|
||||
}
|
||||
outFragColor = vec4(params._color.rgb, outlineIntensity);
|
||||
}
|
|
@ -18,6 +18,7 @@
|
|||
#include "surfaceGeometry_copyDepth_frag.h"
|
||||
#include "debug_deferred_buffer_vert.h"
|
||||
#include "debug_deferred_buffer_frag.h"
|
||||
#include "Outline_frag.h"
|
||||
|
||||
OutlineFramebuffer::OutlineFramebuffer() {
|
||||
}
|
||||
|
@ -99,6 +100,8 @@ void PrepareOutline::run(const render::RenderContextPointer& renderContext, cons
|
|||
_copyDepthPipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
|
||||
// TODO : Instead of copying entire buffer, we should only copy the sub rect containing the outlined object
|
||||
// grown to take into account blur width
|
||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
|
||||
|
@ -122,6 +125,69 @@ void PrepareOutline::run(const render::RenderContextPointer& renderContext, cons
|
|||
}
|
||||
}
|
||||
|
||||
DrawOutline::DrawOutline() {
|
||||
}
|
||||
|
||||
void DrawOutline::configure(const Config& config) {
|
||||
_color = config.color;
|
||||
_size = config.width;
|
||||
}
|
||||
|
||||
void DrawOutline::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) {
|
||||
auto mainFrameBuffer = inputs.get0();
|
||||
|
||||
if (mainFrameBuffer) {
|
||||
auto sceneDepthBuffer = mainFrameBuffer->getPrimaryDepthTexture();
|
||||
auto outlinedDepthBuffer = inputs.get1();
|
||||
auto pipeline = getPipeline();
|
||||
|
||||
if (outlinedDepthBuffer) {
|
||||
auto framebufferSize = glm::ivec2(sceneDepthBuffer->getDimensions());
|
||||
auto args = renderContext->args;
|
||||
{
|
||||
auto& configuration = _configuration.edit();
|
||||
configuration._color = _color;
|
||||
configuration._size = _size / 1024.f;
|
||||
}
|
||||
|
||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
|
||||
batch.setViewportTransform(args->_viewport);
|
||||
batch.setProjectionTransform(glm::mat4());
|
||||
batch.resetViewTransform();
|
||||
batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, args->_viewport));
|
||||
batch.setPipeline(pipeline);
|
||||
|
||||
batch.setUniformBuffer(0, _configuration);
|
||||
batch.setResourceTexture(SCENE_DEPTH_SLOT, sceneDepthBuffer);
|
||||
batch.setResourceTexture(OUTLINED_DEPTH_SLOT, outlinedDepthBuffer->getDepthTexture());
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const gpu::PipelinePointer& DrawOutline::getPipeline() {
|
||||
if (!_pipeline) {
|
||||
auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS();
|
||||
auto ps = gpu::Shader::createPixel(std::string(Outline_frag));
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
slotBindings.insert(gpu::Shader::Binding("outlineParamsBuffer", 0));
|
||||
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->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
|
||||
_pipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
return _pipeline;
|
||||
}
|
||||
|
||||
DebugOutline::DebugOutline() {
|
||||
_geometryId = DependencyManager::get<GeometryCache>()->allocateID();
|
||||
}
|
||||
|
|
|
@ -73,6 +73,60 @@ private:
|
|||
gpu::PipelinePointer _copyDepthPipeline;
|
||||
};
|
||||
|
||||
class DrawOutlineConfig : public render::Job::Config {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(float width MEMBER width NOTIFY dirty)
|
||||
Q_PROPERTY(float colorR READ getColorR WRITE setColorR NOTIFY dirty)
|
||||
Q_PROPERTY(float colorG READ getColorG WRITE setColorG NOTIFY dirty)
|
||||
Q_PROPERTY(float colorB READ getColorB WRITE setColorB NOTIFY dirty)
|
||||
public:
|
||||
|
||||
void setColorR(float value) { color.r = value; }
|
||||
float getColorR() const { return color.r; }
|
||||
|
||||
void setColorG(float value) { color.g = value; }
|
||||
float getColorG() const { return color.g; }
|
||||
|
||||
void setColorB(float value) { color.b = value; }
|
||||
float getColorB() const { return color.b; }
|
||||
|
||||
float width{ 5.f };
|
||||
glm::vec3 color{ 1.f, 0.7f, 0.2f };
|
||||
|
||||
signals:
|
||||
void dirty();
|
||||
};
|
||||
|
||||
class DrawOutline {
|
||||
public:
|
||||
using Inputs = render::VaryingSet2<DeferredFramebufferPointer, OutlineFramebufferPointer>;
|
||||
using Config = DrawOutlineConfig;
|
||||
using JobModel = render::Job::ModelI<DrawOutline, Inputs, Config>;
|
||||
|
||||
DrawOutline();
|
||||
|
||||
void configure(const Config& config);
|
||||
void run(const render::RenderContextPointer& renderContext, const Inputs& inputs);
|
||||
|
||||
private:
|
||||
|
||||
enum {
|
||||
SCENE_DEPTH_SLOT = 0,
|
||||
OUTLINED_DEPTH_SLOT
|
||||
};
|
||||
|
||||
#include "Outline_shared.slh"
|
||||
|
||||
using OutlineConfigurationBuffer = gpu::StructBuffer<OutlineParameters>;
|
||||
|
||||
const gpu::PipelinePointer& getPipeline();
|
||||
|
||||
gpu::PipelinePointer _pipeline;
|
||||
OutlineConfigurationBuffer _configuration;
|
||||
glm::vec3 _color;
|
||||
float _size;
|
||||
};
|
||||
|
||||
class DebugOutlineConfig : public render::Job::Config {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool viewOutlinedDepth MEMBER viewOutlinedDepth NOTIFY dirty)
|
||||
|
@ -85,7 +139,6 @@ signals:
|
|||
void dirty();
|
||||
};
|
||||
|
||||
|
||||
class DebugOutline {
|
||||
public:
|
||||
using Inputs = OutlineFramebufferPointer;
|
||||
|
|
17
libraries/render-utils/src/Outline_shared.slh
Normal file
17
libraries/render-utils/src/Outline_shared.slh
Normal file
|
@ -0,0 +1,17 @@
|
|||
// glsl / C++ compatible source as interface for Outline
|
||||
#ifdef __cplusplus
|
||||
# define VEC3 glm::vec3
|
||||
#else
|
||||
# define VEC3 vec3
|
||||
#endif
|
||||
|
||||
struct OutlineParameters
|
||||
{
|
||||
VEC3 _color;
|
||||
float _size;
|
||||
};
|
||||
|
||||
// <@if 1@>
|
||||
// Trigger Scribe include
|
||||
// <@endif@> <!def that !>
|
||||
//
|
|
@ -14,17 +14,19 @@ PickItemsJob::PickItemsJob(render::ItemKey::Flags validKeys, render::ItemKey::Fl
|
|||
}
|
||||
|
||||
void PickItemsJob::configure(const Config& config) {
|
||||
_isEnabled = config.pick;
|
||||
}
|
||||
|
||||
void PickItemsJob::run(const render::RenderContextPointer& renderContext, const PickItemsJob::Input& input, PickItemsJob::Output& output) {
|
||||
output.clear();
|
||||
if (_isEnabled) {
|
||||
float minIsectDistance = std::numeric_limits<float>::max();
|
||||
auto& itemBounds = input;
|
||||
auto item = findNearestItem(renderContext, itemBounds, minIsectDistance);
|
||||
|
||||
float minIsectDistance = std::numeric_limits<float>::max();
|
||||
auto& itemBounds = input;
|
||||
auto item = findNearestItem(renderContext, itemBounds, minIsectDistance);
|
||||
|
||||
if (render::Item::isValidID(item.id)) {
|
||||
output.push_back(item);
|
||||
if (render::Item::isValidID(item.id)) {
|
||||
output.push_back(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,10 +16,15 @@
|
|||
#include <render/Item.h>
|
||||
|
||||
class PickItemsConfig : public render::Job::Config {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool pick MEMBER pick NOTIFY dirty)
|
||||
|
||||
public:
|
||||
|
||||
PickItemsConfig() : render::Job::Config(false) {}
|
||||
bool pick{ false };
|
||||
|
||||
signals:
|
||||
void dirty();
|
||||
};
|
||||
|
||||
class PickItemsJob {
|
||||
|
@ -40,6 +45,7 @@ private:
|
|||
|
||||
render::ItemKey::Flags _validKeys;
|
||||
render::ItemKey::Flags _excludeKeys;
|
||||
bool _isEnabled{ false };
|
||||
|
||||
render::ItemBound findNearestItem(const render::RenderContextPointer& renderContext, const render::ItemBounds& inputs, float& minIsectDistance) const;
|
||||
};
|
||||
|
|
|
@ -169,6 +169,10 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
|
|||
const auto toneMappingInputs = render::Varying(ToneMappingDeferred::Inputs(lightingFramebuffer, primaryFramebuffer));
|
||||
task.addJob<ToneMappingDeferred>("ToneMapping", toneMappingInputs);
|
||||
|
||||
// Draw outline
|
||||
const auto outlineInputs = DrawOutline::Inputs(deferredFramebuffer, outlinedFrameBuffer).hasVarying();
|
||||
task.addJob<DrawOutline>("DrawOutline", outlineInputs);
|
||||
|
||||
{ // DEbug the bounds of the rendered items, still look at the zbuffer
|
||||
task.addJob<DrawBounds>("DrawMetaBounds", metas);
|
||||
task.addJob<DrawBounds>("DrawOpaqueBounds", opaques);
|
||||
|
|
|
@ -15,6 +15,6 @@ var window = new OverlayWindow({
|
|||
title: 'Outline',
|
||||
source: qml,
|
||||
width: 250,
|
||||
height: 80,
|
||||
height: 250,
|
||||
});
|
||||
window.closed.connect(function() { Script.stop(); });
|
|
@ -10,20 +10,22 @@
|
|||
//
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import "configSlider"
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property var pickConfig: Render.getConfig("RenderMainView.PickOutlined")
|
||||
property var debugConfig: Render.getConfig("RenderMainView.DebugOutline")
|
||||
property var drawConfig: Render.getConfig("RenderMainView.DrawOutline")
|
||||
|
||||
Column {
|
||||
spacing: 8
|
||||
|
||||
CheckBox {
|
||||
text: "Edit Outline"
|
||||
checked: root.pickConfig["enabled"]
|
||||
checked: root.pickConfig["pick"]
|
||||
onCheckedChanged: {
|
||||
root.pickConfig["enabled"] = checked;
|
||||
root.pickConfig["pick"] = checked;
|
||||
}
|
||||
}
|
||||
CheckBox {
|
||||
|
@ -33,5 +35,41 @@ Item {
|
|||
root.debugConfig["viewOutlinedDepth"] = checked;
|
||||
}
|
||||
}
|
||||
ConfigSlider {
|
||||
label: "Width"
|
||||
integral: false
|
||||
config: root.drawConfig
|
||||
property: "width"
|
||||
max: 15.0
|
||||
min: 0.0
|
||||
width: 230
|
||||
}
|
||||
ConfigSlider {
|
||||
label: "Color R"
|
||||
integral: false
|
||||
config: root.drawConfig
|
||||
property: "colorR"
|
||||
max: 1.0
|
||||
min: 0.0
|
||||
width: 230
|
||||
}
|
||||
ConfigSlider {
|
||||
label: "Color G"
|
||||
integral: false
|
||||
config: root.drawConfig
|
||||
property: "colorG"
|
||||
max: 1.0
|
||||
min: 0.0
|
||||
width: 230
|
||||
}
|
||||
ConfigSlider {
|
||||
label: "Color B"
|
||||
integral: false
|
||||
config: root.drawConfig
|
||||
property: "colorB"
|
||||
max: 1.0
|
||||
min: 0.0
|
||||
width: 230
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue