mirror of
https://github.com/overte-org/overte.git
synced 2025-07-23 14:04:23 +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);
|
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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue