Multiple outline group config working

This commit is contained in:
Olivier Prat 2017-10-17 10:01:06 +02:00
parent 70f892e67d
commit 9ed5185a3e
5 changed files with 234 additions and 152 deletions

View file

@ -53,7 +53,7 @@ vec4 computeGroupOutline(int centerGroupId, float centerDepth, int groupId, vec2
sceneDepth = -evalZeyeFromZdb(sceneDepth);
// Are we occluded?
intensity = (sceneDepth < (centerDepth-LINEAR_DEPTH_BIAS)) ? groupParams._fillOpacityOccluded : groupParams._fillOpacityUnoccluded;
intensity = (sceneDepth < (centerDepth-LINEAR_DEPTH_BIAS)) ? groupParams._occludedFillOpacity : groupParams._unoccludedFillOpacity;
return vec4(groupParams._color.rgb, intensity);
<@else@>
return vec4(0,0,0,0);

View file

@ -215,6 +215,17 @@ void PrepareDrawOutline::run(const render::RenderContextPointer& renderContext,
outputs = _primaryWithoutDepthBuffer;
}
int DrawOutlineConfig::getGroupCount() const {
return Outline::MAX_GROUP_COUNT;
}
void DrawOutlineConfig::setGroup(int value) {
assert(value >= 0 && value < Outline::MAX_GROUP_COUNT);
group = std::min<int>(value, Outline::MAX_GROUP_COUNT);
group = std::max<int>(group, 0);
emit dirty();
}
gpu::PipelinePointer DrawOutline::_pipeline;
gpu::PipelinePointer DrawOutline::_pipelineFilled;
@ -222,15 +233,34 @@ DrawOutline::DrawOutline() {
}
void DrawOutline::configure(const Config& config) {
_color = config.color;
_blurKernelSize = std::min(10, std::max(2, (int)floorf(config.width*2 + 0.5f)));
// Size is in normalized screen height. We decide that for outline width = 1, this is equal to 1/400.
_size = config.width / 400.f;
_fillOpacityUnoccluded = config.fillOpacityUnoccluded;
_fillOpacityOccluded = config.fillOpacityOccluded;
_threshold = config.glow ? 1.f : 1e-3f;
_intensity = config.intensity * (config.glow ? 2.f : 1.f);
_hasConfigurationChanged = true;
auto& configuration = _configuration.edit();
const auto OPACITY_EPSILON = 5e-3f;
bool someFilled = false;
bool isFilled;
for (auto groupId = 0; groupId < MAX_GROUP_COUNT; groupId++) {
auto& dstGroupConfig = configuration._groups[groupId];
auto& srcGroupConfig = config.groupParameters[groupId];
dstGroupConfig._color = srcGroupConfig.color;
dstGroupConfig._intensity = srcGroupConfig.intensity * (srcGroupConfig.glow ? 2.f : 1.f);
dstGroupConfig._unoccludedFillOpacity = srcGroupConfig.unoccludedFillOpacity;
dstGroupConfig._occludedFillOpacity = srcGroupConfig.occludedFillOpacity;
dstGroupConfig._threshold = srcGroupConfig.glow ? 1.f : 1e-3f;
dstGroupConfig._blurKernelSize = std::min(10, std::max(2, (int)floorf(srcGroupConfig.width * 2 + 0.5f)));
// Size is in normalized screen height. We decide that for outline width = 1, this is equal to 1/400.
_sizes[groupId] = srcGroupConfig.width / 400.0f;
isFilled = (srcGroupConfig.unoccludedFillOpacity > OPACITY_EPSILON || srcGroupConfig.occludedFillOpacity > OPACITY_EPSILON);
someFilled = someFilled || isFilled;
}
if (someFilled) {
_mode = M_SOME_FILLED;
} else {
_mode = M_ALL_UNFILLED;
}
}
void DrawOutline::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) {
@ -245,27 +275,20 @@ void DrawOutline::run(const render::RenderContextPointer& renderContext, const I
auto framebufferSize = glm::ivec2(outlinedDepthTexture->getDimensions());
if (sceneDepthBuffer) {
const auto OPACITY_EPSILON = 5e-3f;
auto pipeline = getPipeline(_fillOpacityUnoccluded>OPACITY_EPSILON || _fillOpacityOccluded>OPACITY_EPSILON);
auto pipeline = getPipeline();
auto args = renderContext->args;
if (_hasConfigurationChanged)
if (_framebufferSize != framebufferSize)
{
auto& configuration = _configuration.edit();
for (auto groupId = 0; groupId < MAX_GROUP_COUNT; groupId++) {
auto& groupConfig = configuration._groups[groupId];
groupConfig._color = _color;
groupConfig._intensity = _intensity;
groupConfig._fillOpacityUnoccluded = _fillOpacityUnoccluded;
groupConfig._fillOpacityOccluded = _fillOpacityOccluded;
groupConfig._threshold = _threshold;
groupConfig._blurKernelSize = _blurKernelSize;
groupConfig._size.x = (_size * framebufferSize.y) / framebufferSize.x;
groupConfig._size.y = _size;
groupConfig._size.x = (_sizes[groupId] * framebufferSize.y) / framebufferSize.x;
groupConfig._size.y = _sizes[groupId];
}
_hasConfigurationChanged = false;
_framebufferSize = framebufferSize;
}
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
@ -292,7 +315,7 @@ void DrawOutline::run(const render::RenderContextPointer& renderContext, const I
}
}
const gpu::PipelinePointer& DrawOutline::getPipeline(bool isFilled) {
const gpu::PipelinePointer& DrawOutline::getPipeline() {
if (!_pipeline) {
auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS();
auto ps = gpu::Shader::createPixel(std::string(Outline_frag));
@ -316,7 +339,7 @@ const gpu::PipelinePointer& DrawOutline::getPipeline(bool isFilled) {
gpu::Shader::makeProgram(*program, slotBindings);
_pipelineFilled = gpu::Pipeline::create(program, state);
}
return isFilled ? _pipelineFilled : _pipeline;
return _mode == M_SOME_FILLED ? _pipelineFilled : _pipeline;
}
DebugOutline::DebugOutline() {
@ -480,7 +503,7 @@ void DrawOutlineTask::build(JobModel& task, const render::Varying& inputs, rende
}
DrawOutlineMask::Groups sortedBounds;
for (auto i = 0; i < DrawOutline::MAX_GROUP_COUNT; i++) {
for (auto i = 0; i < Outline::MAX_GROUP_COUNT; i++) {
const auto groupItems = groups[i];
const auto outlinedItemIDs = task.addJob<render::MetaToSubItems>("OutlineMetaToSubItemIDs", groupItems);
const auto outlinedItems = task.addJob<render::IDsToBounds>("OutlineMetaToSubItems", outlinedItemIDs, true);

View file

@ -60,41 +60,8 @@ private:
};
class DrawOutlineConfig : public render::Job::Config {
Q_OBJECT
Q_PROPERTY(bool glow MEMBER glow NOTIFY dirty)
Q_PROPERTY(float width MEMBER width NOTIFY dirty)
Q_PROPERTY(float intensity MEMBER intensity 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)
Q_PROPERTY(float fillOpacityUnoccluded MEMBER fillOpacityUnoccluded NOTIFY dirty)
Q_PROPERTY(float fillOpacityOccluded MEMBER fillOpacityOccluded NOTIFY dirty)
public:
void setColorR(float value) { color.r = value; emit dirty(); }
float getColorR() const { return color.r; }
void setColorG(float value) { color.g = value; emit dirty(); }
float getColorG() const { return color.g; }
void setColorB(float value) { color.b = value; emit dirty(); }
float getColorB() const { return color.b; }
glm::vec3 color{ 1.f, 0.7f, 0.2f };
float width{ 2.0f };
float intensity{ 0.9f };
float fillOpacityUnoccluded{ 0.0f };
float fillOpacityOccluded{ 0.0f };
bool glow{ false };
signals:
void dirty();
};
class DrawOutline {
private:
class Outline {
protected:
#include "Outline_shared.slh"
@ -102,6 +69,68 @@ public:
enum {
MAX_GROUP_COUNT = GROUP_COUNT
};
};
class DrawOutlineConfig : public render::Job::Config {
Q_OBJECT
Q_PROPERTY(int group MEMBER group WRITE setGroup NOTIFY dirty);
Q_PROPERTY(bool glow READ isGlow WRITE setGlow NOTIFY dirty)
Q_PROPERTY(float width READ getWidth WRITE setWidth NOTIFY dirty)
Q_PROPERTY(float intensity READ getIntensity WRITE setIntensity 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)
Q_PROPERTY(float unoccludedFillOpacity READ getUnoccludedFillOpacity WRITE setUnoccludedFillOpacity NOTIFY dirty)
Q_PROPERTY(float occludedFillOpacity READ getOccludedFillOpacity WRITE setOccludedFillOpacity NOTIFY dirty)
public:
struct GroupParameters {
glm::vec3 color{ 1.f, 0.7f, 0.2f };
float width{ 2.0f };
float intensity{ 0.9f };
float unoccludedFillOpacity{ 0.0f };
float occludedFillOpacity{ 0.0f };
bool glow{ false };
};
int getGroupCount() const;
void setColorR(float value) { groupParameters[group].color.r = value; emit dirty(); }
float getColorR() const { return groupParameters[group].color.r; }
void setColorG(float value) { groupParameters[group].color.g = value; emit dirty(); }
float getColorG() const { return groupParameters[group].color.g; }
void setColorB(float value) { groupParameters[group].color.b = value; emit dirty(); }
float getColorB() const { return groupParameters[group].color.b; }
void setGlow(bool value) { groupParameters[group].glow = value; emit dirty(); }
bool isGlow() const { return groupParameters[group].glow; }
void setWidth(float value) { groupParameters[group].width = value; emit dirty(); }
float getWidth() const { return groupParameters[group].width; }
void setIntensity(float value) { groupParameters[group].intensity = value; emit dirty(); }
float getIntensity() const { return groupParameters[group].intensity; }
void setUnoccludedFillOpacity(float value) { groupParameters[group].unoccludedFillOpacity = value; emit dirty(); }
float getUnoccludedFillOpacity() const { return groupParameters[group].unoccludedFillOpacity; }
void setOccludedFillOpacity(float value) { groupParameters[group].occludedFillOpacity = value; emit dirty(); }
float getOccludedFillOpacity() const { return groupParameters[group].occludedFillOpacity; }
void setGroup(int value);
int group{ 0 };
GroupParameters groupParameters[Outline::MAX_GROUP_COUNT];
signals:
void dirty();
};
class DrawOutline : public Outline {
public:
using Inputs = render::VaryingSet4<DeferredFrameTransformPointer, OutlineRessourcesPointer, DeferredFramebufferPointer, gpu::FramebufferPointer>;
using Config = DrawOutlineConfig;
@ -127,27 +156,27 @@ private:
OutlineParameters _groups[MAX_GROUP_COUNT];
};
enum Mode {
M_ALL_UNFILLED,
M_SOME_FILLED,
};
using OutlineConfigurationBuffer = gpu::StructBuffer<OutlineConfiguration>;
static const gpu::PipelinePointer& getPipeline(bool isFilled);
const gpu::PipelinePointer& getPipeline();
static gpu::PipelinePointer _pipeline;
static gpu::PipelinePointer _pipelineFilled;
OutlineConfigurationBuffer _configuration;
glm::vec3 _color;
float _size;
int _blurKernelSize;
float _intensity;
float _fillOpacityUnoccluded;
float _fillOpacityOccluded;
float _threshold;
bool _hasConfigurationChanged{ true };
glm::ivec2 _framebufferSize{ 0,0 };
Mode _mode{ M_ALL_UNFILLED };
float _sizes[MAX_GROUP_COUNT];
};
class DrawOutlineTask {
public:
using Groups = render::VaryingArray<render::ItemBounds, DrawOutline::MAX_GROUP_COUNT>;
using Groups = render::VaryingArray<render::ItemBounds, Outline::MAX_GROUP_COUNT>;
using Inputs = render::VaryingSet4<Groups, DeferredFramebufferPointer, gpu::FramebufferPointer, DeferredFrameTransformPointer>;
using Config = render::Task::Config;
using JobModel = render::Task::ModelI<DrawOutlineTask, Inputs, Config>;
@ -165,7 +194,7 @@ private:
class DrawOutlineMask {
public:
using Groups = render::VaryingArray<render::ShapeBounds, DrawOutline::MAX_GROUP_COUNT>;
using Groups = render::VaryingArray<render::ShapeBounds, Outline::MAX_GROUP_COUNT>;
using Inputs = render::VaryingSet2<Groups, DeferredFramebufferPointer>;
// Output will contain outlined objects only z-depth texture and the input primary buffer but without the primary depth buffer
using Outputs = OutlineRessourcesPointer;

View file

@ -19,8 +19,8 @@ struct OutlineParameters
float _intensity;
VEC2 _size;
float _fillOpacityUnoccluded;
float _fillOpacityOccluded;
float _unoccludedFillOpacity;
float _occludedFillOpacity;
float _threshold;
int _blurKernelSize;

View file

@ -20,6 +20,24 @@ Item {
Column {
spacing: 8
ComboBox {
id: groupBox
model: ["Group 0", "Group 1", "Group 2", "Group 3", "Group 4"]
Timer {
id: postpone
interval: 100; running: false; repeat: false
onTriggered: { paramWidgetLoader.sourceComponent = paramWidgets }
}
onCurrentIndexChanged: {
// This is a hack to be sure the widgets below properly reflect the change of category: delete the Component
// by setting the loader source to Null and then recreate it 100ms later
root.drawConfig["group"] = currentIndex
paramWidgetLoader.sourceComponent = undefined;
postpone.interval = 100
postpone.start()
}
}
CheckBox {
text: "View Mask"
checked: root.debugConfig["viewMask"]
@ -27,93 +45,105 @@ Item {
root.debugConfig["viewMask"] = checked;
}
}
CheckBox {
text: "Glow"
checked: root.drawConfig["glow"]
onCheckedChanged: {
root.drawConfig["glow"] = checked;
}
}
ConfigSlider {
label: "Width"
integral: false
config: root.drawConfig
property: "width"
max: 15.0
min: 0.0
width: 280
}
ConfigSlider {
label: "Intensity"
integral: false
config: root.drawConfig
property: "intensity"
max: 1.0
min: 0.0
width: 280
}
GroupBox {
title: "Color"
width: 280
Component {
id: paramWidgets
Column {
spacing: 8
CheckBox {
text: "Glow"
checked: root.drawConfig["glow"]
onCheckedChanged: {
drawConfig["glow"] = checked;
}
}
ConfigSlider {
label: "Width"
integral: false
config: root.drawConfig
property: "width"
max: 15.0
min: 0.0
width: 280
}
ConfigSlider {
label: "Intensity"
integral: false
config: root.drawConfig
property: "intensity"
max: 1.0
min: 0.0
width: 280
}
ConfigSlider {
label: "Red"
integral: false
config: root.drawConfig
property: "colorR"
max: 1.0
min: 0.0
width: 270
}
ConfigSlider {
label: "Green"
integral: false
config: root.drawConfig
property: "colorG"
max: 1.0
min: 0.0
width: 270
}
ConfigSlider {
label: "Blue"
integral: false
config: root.drawConfig
property: "colorB"
max: 1.0
min: 0.0
width: 270
GroupBox {
title: "Color"
width: 280
Column {
spacing: 8
ConfigSlider {
label: "Red"
integral: false
config: root.drawConfig
property: "colorR"
max: 1.0
min: 0.0
width: 270
}
ConfigSlider {
label: "Green"
integral: false
config: root.drawConfig
property: "colorG"
max: 1.0
min: 0.0
width: 270
}
ConfigSlider {
label: "Blue"
integral: false
config: root.drawConfig
property: "colorB"
max: 1.0
min: 0.0
width: 270
}
}
}
GroupBox {
title: "Fill Opacity"
width: 280
Column {
spacing: 8
ConfigSlider {
label: "Unoccluded"
integral: false
config: root.drawConfig
property: "fillOpacityUnoccluded"
max: 1.0
min: 0.0
width: 270
}
ConfigSlider {
label: "Occluded"
integral: false
config: root.drawConfig
property: "fillOpacityOccluded"
max: 1.0
min: 0.0
width: 270
}
}
}
}
}
GroupBox {
title: "Fill Opacity"
width: 280
Column {
spacing: 8
ConfigSlider {
label: "Unoccluded"
integral: false
config: root.drawConfig
property: "fillOpacityUnoccluded"
max: 1.0
min: 0.0
width: 270
}
ConfigSlider {
label: "Occluded"
integral: false
config: root.drawConfig
property: "fillOpacityOccluded"
max: 1.0
min: 0.0
width: 270
}
}
Loader {
id: paramWidgetLoader
sourceComponent: paramWidgets
}
}
}