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); sceneDepth = -evalZeyeFromZdb(sceneDepth);
// Are we occluded? // 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); return vec4(groupParams._color.rgb, intensity);
<@else@> <@else@>
return vec4(0,0,0,0); return vec4(0,0,0,0);

View file

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

View file

@ -60,41 +60,8 @@ private:
}; };
class DrawOutlineConfig : public render::Job::Config { class Outline {
Q_OBJECT protected:
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:
#include "Outline_shared.slh" #include "Outline_shared.slh"
@ -102,6 +69,68 @@ public:
enum { enum {
MAX_GROUP_COUNT = GROUP_COUNT 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 Inputs = render::VaryingSet4<DeferredFrameTransformPointer, OutlineRessourcesPointer, DeferredFramebufferPointer, gpu::FramebufferPointer>;
using Config = DrawOutlineConfig; using Config = DrawOutlineConfig;
@ -127,27 +156,27 @@ private:
OutlineParameters _groups[MAX_GROUP_COUNT]; OutlineParameters _groups[MAX_GROUP_COUNT];
}; };
enum Mode {
M_ALL_UNFILLED,
M_SOME_FILLED,
};
using OutlineConfigurationBuffer = gpu::StructBuffer<OutlineConfiguration>; using OutlineConfigurationBuffer = gpu::StructBuffer<OutlineConfiguration>;
static const gpu::PipelinePointer& getPipeline(bool isFilled); const gpu::PipelinePointer& getPipeline();
static gpu::PipelinePointer _pipeline; static gpu::PipelinePointer _pipeline;
static gpu::PipelinePointer _pipelineFilled; static gpu::PipelinePointer _pipelineFilled;
OutlineConfigurationBuffer _configuration; OutlineConfigurationBuffer _configuration;
glm::vec3 _color; glm::ivec2 _framebufferSize{ 0,0 };
float _size; Mode _mode{ M_ALL_UNFILLED };
int _blurKernelSize; float _sizes[MAX_GROUP_COUNT];
float _intensity;
float _fillOpacityUnoccluded;
float _fillOpacityOccluded;
float _threshold;
bool _hasConfigurationChanged{ true };
}; };
class DrawOutlineTask { class DrawOutlineTask {
public: 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 Inputs = render::VaryingSet4<Groups, DeferredFramebufferPointer, gpu::FramebufferPointer, DeferredFrameTransformPointer>;
using Config = render::Task::Config; using Config = render::Task::Config;
using JobModel = render::Task::ModelI<DrawOutlineTask, Inputs, Config>; using JobModel = render::Task::ModelI<DrawOutlineTask, Inputs, Config>;
@ -165,7 +194,7 @@ private:
class DrawOutlineMask { class DrawOutlineMask {
public: 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>; 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 // Output will contain outlined objects only z-depth texture and the input primary buffer but without the primary depth buffer
using Outputs = OutlineRessourcesPointer; using Outputs = OutlineRessourcesPointer;

View file

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

View file

@ -20,6 +20,24 @@ Item {
Column { Column {
spacing: 8 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 { CheckBox {
text: "View Mask" text: "View Mask"
checked: root.debugConfig["viewMask"] checked: root.debugConfig["viewMask"]
@ -27,11 +45,16 @@ Item {
root.debugConfig["viewMask"] = checked; root.debugConfig["viewMask"] = checked;
} }
} }
Component {
id: paramWidgets
Column {
spacing: 8
CheckBox { CheckBox {
text: "Glow" text: "Glow"
checked: root.drawConfig["glow"] checked: root.drawConfig["glow"]
onCheckedChanged: { onCheckedChanged: {
root.drawConfig["glow"] = checked; drawConfig["glow"] = checked;
} }
} }
ConfigSlider { ConfigSlider {
@ -117,3 +140,10 @@ Item {
} }
} }
} }
Loader {
id: paramWidgetLoader
sourceComponent: paramWidgets
}
}
}