mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 01:24:03 +02:00
Multiple outline group config working
This commit is contained in:
parent
70f892e67d
commit
9ed5185a3e
5 changed files with 234 additions and 152 deletions
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -19,8 +19,8 @@ struct OutlineParameters
|
|||
float _intensity;
|
||||
|
||||
VEC2 _size;
|
||||
float _fillOpacityUnoccluded;
|
||||
float _fillOpacityOccluded;
|
||||
float _unoccludedFillOpacity;
|
||||
float _occludedFillOpacity;
|
||||
|
||||
float _threshold;
|
||||
int _blurKernelSize;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue