mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
Added OutlineStyleStage
This commit is contained in:
parent
09ee69db30
commit
9e6472b577
13 changed files with 427 additions and 119 deletions
|
@ -68,11 +68,15 @@ ContextOverlayInterface::ContextOverlayInterface() {
|
|||
connect(&qApp->getOverlays(), &Overlays::hoverEnterOverlay, this, &ContextOverlayInterface::contextOverlays_hoverEnterOverlay);
|
||||
connect(&qApp->getOverlays(), &Overlays::hoverLeaveOverlay, this, &ContextOverlayInterface::contextOverlays_hoverLeaveOverlay);
|
||||
|
||||
_selectionToSceneHandlers[0].initialize("contextOverlayHighlightList");
|
||||
connect(_selectionScriptingInterface.data(), &SelectionScriptingInterface::selectedItemsListChanged, &_selectionToSceneHandlers[0], &SelectionToSceneHandler::selectedItemsListChanged);
|
||||
for (auto i = 1; i < render::Scene::MAX_OUTLINE_COUNT; i++) {
|
||||
_selectionToSceneHandlers[i].initialize(QString("contextOverlayHighlightList") + QString::number(i));
|
||||
connect(_selectionScriptingInterface.data(), &SelectionScriptingInterface::selectedItemsListChanged, &_selectionToSceneHandlers[i], &SelectionToSceneHandler::selectedItemsListChanged);
|
||||
{
|
||||
render::Transaction transaction;
|
||||
initializeSelectionToSceneHandler(_selectionToSceneHandlers[0], "contextOverlayHighlightList", transaction);
|
||||
for (auto i = 1; i < MAX_SELECTION_COUNT; i++) {
|
||||
auto selectionName = QString("contextOverlayHighlightList") + QString::number(i);
|
||||
initializeSelectionToSceneHandler(_selectionToSceneHandlers[i], selectionName, transaction);
|
||||
}
|
||||
const render::ScenePointer& scene = qApp->getMain3DScene();
|
||||
scene->enqueueTransaction(transaction);
|
||||
}
|
||||
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
@ -81,6 +85,12 @@ ContextOverlayInterface::ContextOverlayInterface() {
|
|||
_challengeOwnershipTimeoutTimer.setSingleShot(true);
|
||||
}
|
||||
|
||||
void ContextOverlayInterface::initializeSelectionToSceneHandler(SelectionToSceneHandler& handler, const QString& selectionName, render::Transaction& transaction) {
|
||||
handler.initialize(selectionName);
|
||||
connect(_selectionScriptingInterface.data(), &SelectionScriptingInterface::selectedItemsListChanged, &handler, &SelectionToSceneHandler::selectedItemsListChanged);
|
||||
transaction.resetSelectionOutline(selectionName.toStdString());
|
||||
}
|
||||
|
||||
static const uint32_t MOUSE_HW_ID = 0;
|
||||
static const uint32_t LEFT_HAND_HW_ID = 1;
|
||||
static const xColor CONTEXT_OVERLAY_COLOR = { 255, 255, 255 };
|
||||
|
|
|
@ -76,6 +76,11 @@ private slots:
|
|||
void handleChallengeOwnershipReplyPacket(QSharedPointer<ReceivedMessage> packet, SharedNodePointer sendingNode);
|
||||
|
||||
private:
|
||||
|
||||
enum {
|
||||
MAX_SELECTION_COUNT = 16
|
||||
};
|
||||
|
||||
bool _verboseLogging { true };
|
||||
bool _enabled { true };
|
||||
EntityItemID _currentEntityWithContextOverlay{};
|
||||
|
@ -91,8 +96,9 @@ private:
|
|||
void disableEntityHighlight(const EntityItemID& entityItemID);
|
||||
|
||||
void deletingEntity(const EntityItemID& entityItemID);
|
||||
void initializeSelectionToSceneHandler(SelectionToSceneHandler& handler, const QString& selectionName, render::Transaction& transaction);
|
||||
|
||||
SelectionToSceneHandler _selectionToSceneHandlers[render::Scene::MAX_OUTLINE_COUNT];
|
||||
SelectionToSceneHandler _selectionToSceneHandlers[MAX_SELECTION_COUNT];
|
||||
|
||||
Q_INVOKABLE void startChallengeOwnershipTimer();
|
||||
QTimer _challengeOwnershipTimeoutTimer;
|
||||
|
|
|
@ -83,7 +83,11 @@ gpu::FramebufferPointer OutlineRessources::getColorFramebuffer() {
|
|||
}
|
||||
|
||||
OutlineSharedParameters::OutlineSharedParameters() {
|
||||
std::fill(_blurPixelWidths.begin(), _blurPixelWidths.end(), 0);
|
||||
_outlineIds.fill(render::OutlineStyleStage::INVALID_INDEX);
|
||||
}
|
||||
|
||||
float OutlineSharedParameters::getBlurPixelWidth(const render::OutlineStyle& style, int frameBufferHeight) {
|
||||
return ceilf(style.width * frameBufferHeight / 400.0f);
|
||||
}
|
||||
|
||||
PrepareDrawOutline::PrepareDrawOutline() {
|
||||
|
@ -141,8 +145,12 @@ void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, con
|
|||
_boundsBuffer = std::make_shared<gpu::Buffer>(sizeof(render::ItemBound));
|
||||
}
|
||||
|
||||
if (!inShapes.empty()) {
|
||||
auto outlineStage = renderContext->_scene->getStage<render::OutlineStyleStage>(render::OutlineStyleStage::getName());
|
||||
auto outlineId = _sharedParameters->_outlineIds[_outlineIndex];
|
||||
|
||||
if (!inShapes.empty() && !render::OutlineStyleStage::isIndexInvalid(outlineId)) {
|
||||
auto ressources = inputs.get1();
|
||||
auto& outline = outlineStage->getOutline(outlineId);
|
||||
|
||||
RenderArgs* args = renderContext->args;
|
||||
ShapeKey::Builder defaultKeyBuilder;
|
||||
|
@ -213,10 +221,10 @@ void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, con
|
|||
// Draw stencil mask with object bounding boxes
|
||||
const auto outlineWidthLoc = _stencilMaskPipeline->getProgram()->getUniforms().findLocation("outlineWidth");
|
||||
const auto sqrt3 = 1.74f;
|
||||
const float blurPixelWidth = 2.0f * sqrt3 *_sharedParameters->_blurPixelWidths[_outlineIndex];
|
||||
const float blurPixelWidth = 2.0f * sqrt3 * OutlineSharedParameters::getBlurPixelWidth(outline._style, args->_viewport.w);
|
||||
const auto framebufferSize = ressources->getSourceFrameSize();
|
||||
|
||||
auto stencilPipeline = _sharedParameters->_isFilled.test(_outlineIndex) ? _stencilMaskFillPipeline : _stencilMaskPipeline;
|
||||
auto stencilPipeline = outline._style.isFilled() ? _stencilMaskFillPipeline : _stencilMaskPipeline;
|
||||
batch.setPipeline(stencilPipeline);
|
||||
batch.setResourceBuffer(0, _boundsBuffer);
|
||||
batch._glUniform2f(outlineWidthLoc, blurPixelWidth / framebufferSize.x, blurPixelWidth / framebufferSize.y);
|
||||
|
@ -237,24 +245,6 @@ DrawOutline::DrawOutline(unsigned int outlineIndex, OutlineSharedParametersPoint
|
|||
_sharedParameters{ parameters } {
|
||||
}
|
||||
|
||||
void DrawOutline::configure(const Config& config) {
|
||||
const auto OPACITY_EPSILON = 5e-3f;
|
||||
|
||||
_parameters._color = config.color;
|
||||
_parameters._intensity = config.intensity * (config.glow ? 2.0f : 1.0f);
|
||||
_parameters._unoccludedFillOpacity = config.unoccludedFillOpacity;
|
||||
_parameters._occludedFillOpacity = config.occludedFillOpacity;
|
||||
_parameters._threshold = config.glow ? 1.0f : 1e-3f;
|
||||
_parameters._blurKernelSize = std::min(7, std::max(2, (int)floorf(config.width * 3 + 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.0f;
|
||||
_parameters._size.x = (_size * _framebufferSize.y) / _framebufferSize.x;
|
||||
_parameters._size.y = _size;
|
||||
_sharedParameters->_blurPixelWidths[_outlineIndex] = (int)ceilf(_size * _framebufferSize.y);
|
||||
_sharedParameters->_isFilled.set(_outlineIndex, (config.unoccludedFillOpacity > OPACITY_EPSILON || config.occludedFillOpacity > OPACITY_EPSILON));
|
||||
_configuration.edit() = _parameters;
|
||||
}
|
||||
|
||||
void DrawOutline::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) {
|
||||
auto outlineFrameBuffer = inputs.get1();
|
||||
auto outlineRect = inputs.get3();
|
||||
|
@ -267,39 +257,50 @@ void DrawOutline::run(const render::RenderContextPointer& renderContext, const I
|
|||
auto framebufferSize = glm::ivec2(outlinedDepthTexture->getDimensions());
|
||||
|
||||
if (sceneDepthBuffer) {
|
||||
auto pipeline = getPipeline();
|
||||
auto args = renderContext->args;
|
||||
|
||||
if (_framebufferSize != framebufferSize)
|
||||
{
|
||||
_parameters._size.x = (_size * framebufferSize.y) / framebufferSize.x;
|
||||
_parameters._size.y = _size;
|
||||
_framebufferSize = framebufferSize;
|
||||
_sharedParameters->_blurPixelWidths[_outlineIndex] = (int)ceilf(_size * _framebufferSize.y);
|
||||
_configuration.edit() = _parameters;
|
||||
auto outlineStage = renderContext->_scene->getStage<render::OutlineStyleStage>(render::OutlineStyleStage::getName());
|
||||
auto outlineId = _sharedParameters->_outlineIds[_outlineIndex];
|
||||
if (!render::OutlineStyleStage::isIndexInvalid(outlineId)) {
|
||||
auto& outline = outlineStage->getOutline(_sharedParameters->_outlineIds[_outlineIndex]);
|
||||
auto pipeline = getPipeline(outline._style);
|
||||
{
|
||||
auto& shaderParameters = _configuration.edit();
|
||||
|
||||
shaderParameters._color = outline._style.color;
|
||||
shaderParameters._intensity = outline._style.intensity * (outline._style.glow ? 2.0f : 1.0f);
|
||||
shaderParameters._unoccludedFillOpacity = outline._style.unoccludedFillOpacity;
|
||||
shaderParameters._occludedFillOpacity = outline._style.occludedFillOpacity;
|
||||
shaderParameters._threshold = outline._style.glow ? 1.0f : 1e-3f;
|
||||
shaderParameters._blurKernelSize = std::min(7, std::max(2, (int)floorf(outline._style.width * 3 + 0.5f)));
|
||||
// Size is in normalized screen height. We decide that for outline width = 1, this is equal to 1/400.
|
||||
auto size = outline._style.width / 400.0f;
|
||||
shaderParameters._size.x = (size * framebufferSize.y) / framebufferSize.x;
|
||||
shaderParameters._size.y = size;
|
||||
}
|
||||
|
||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
batch.setFramebuffer(destinationFrameBuffer);
|
||||
|
||||
batch.setViewportTransform(args->_viewport);
|
||||
batch.setProjectionTransform(glm::mat4());
|
||||
batch.resetViewTransform();
|
||||
batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, args->_viewport));
|
||||
batch.setPipeline(pipeline);
|
||||
|
||||
batch.setUniformBuffer(OUTLINE_PARAMS_SLOT, _configuration);
|
||||
batch.setUniformBuffer(FRAME_TRANSFORM_SLOT, frameTransform->getFrameTransformBuffer());
|
||||
batch.setResourceTexture(SCENE_DEPTH_SLOT, sceneDepthBuffer->getPrimaryDepthTexture());
|
||||
batch.setResourceTexture(OUTLINED_DEPTH_SLOT, outlinedDepthTexture);
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
});
|
||||
}
|
||||
|
||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
batch.setFramebuffer(destinationFrameBuffer);
|
||||
|
||||
batch.setViewportTransform(args->_viewport);
|
||||
batch.setProjectionTransform(glm::mat4());
|
||||
batch.resetViewTransform();
|
||||
batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, args->_viewport));
|
||||
batch.setPipeline(pipeline);
|
||||
|
||||
batch.setUniformBuffer(OUTLINE_PARAMS_SLOT, _configuration);
|
||||
batch.setUniformBuffer(FRAME_TRANSFORM_SLOT, frameTransform->getFrameTransformBuffer());
|
||||
batch.setResourceTexture(SCENE_DEPTH_SLOT, sceneDepthBuffer->getPrimaryDepthTexture());
|
||||
batch.setResourceTexture(OUTLINED_DEPTH_SLOT, outlinedDepthTexture);
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const gpu::PipelinePointer& DrawOutline::getPipeline() {
|
||||
const gpu::PipelinePointer& DrawOutline::getPipeline(const render::OutlineStyle& style) {
|
||||
if (!_pipeline) {
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
state->setDepthTest(gpu::State::DepthTest(false, false));
|
||||
|
@ -324,7 +325,7 @@ const gpu::PipelinePointer& DrawOutline::getPipeline() {
|
|||
gpu::Shader::makeProgram(*program, slotBindings);
|
||||
_pipelineFilled = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
return _sharedParameters->_isFilled.test(_outlineIndex) ? _pipelineFilled : _pipeline;
|
||||
return style.isFilled() ? _pipelineFilled : _pipeline;
|
||||
}
|
||||
|
||||
DebugOutline::DebugOutline() {
|
||||
|
@ -424,6 +425,35 @@ const gpu::PipelinePointer& DebugOutline::getDepthPipeline() {
|
|||
return _depthPipeline;
|
||||
}
|
||||
|
||||
void SelectionToOutline::run(const render::RenderContextPointer& renderContext, Outputs& outputs) {
|
||||
auto outlineStage = renderContext->_scene->getStage<render::OutlineStyleStage>(render::OutlineStyleStage::getName());
|
||||
|
||||
outputs.clear();
|
||||
_sharedParameters->_outlineIds.fill(render::OutlineStyleStage::INVALID_INDEX);
|
||||
|
||||
for (auto i = 0; i < OutlineSharedParameters::MAX_OUTLINE_COUNT; i++) {
|
||||
std::ostringstream stream;
|
||||
stream << "contextOverlayHighlightList";
|
||||
if (i > 0) {
|
||||
stream << i;
|
||||
}
|
||||
auto selectionName = stream.str();
|
||||
auto outlineId = outlineStage->getOutlineIdBySelection(selectionName);
|
||||
if (!render::OutlineStyleStage::isIndexInvalid(outlineId)) {
|
||||
_sharedParameters->_outlineIds[outputs.size()] = outlineId;
|
||||
outputs.emplace_back(selectionName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExtractSelectionName::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) {
|
||||
if (_outlineIndex < inputs.size()) {
|
||||
outputs = inputs[_outlineIndex];
|
||||
} else {
|
||||
outputs.clear();
|
||||
}
|
||||
}
|
||||
|
||||
DrawOutlineTask::DrawOutlineTask() {
|
||||
|
||||
}
|
||||
|
@ -433,7 +463,7 @@ void DrawOutlineTask::configure(const Config& config) {
|
|||
}
|
||||
|
||||
void DrawOutlineTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs) {
|
||||
const auto groups = inputs.getN<Inputs>(0).get<Groups>();
|
||||
const auto items = inputs.getN<Inputs>(0).get<RenderFetchCullSortTask::BucketList>();
|
||||
const auto sceneFrameBuffer = inputs.getN<Inputs>(1);
|
||||
const auto primaryFramebuffer = inputs.getN<Inputs>(2);
|
||||
const auto deferredFrameTransform = inputs.getN<Inputs>(3);
|
||||
|
@ -449,12 +479,15 @@ void DrawOutlineTask::build(JobModel& task, const render::Varying& inputs, rende
|
|||
}
|
||||
auto sharedParameters = std::make_shared<OutlineSharedParameters>();
|
||||
|
||||
const auto outlineSelectionNames = task.addJob<SelectionToOutline>("SelectionToOutline", sharedParameters);
|
||||
|
||||
// Prepare for outline group rendering.
|
||||
const auto outlineRessources = task.addJob<PrepareDrawOutline>("PrepareOutline", primaryFramebuffer);
|
||||
render::Varying outline0Rect;
|
||||
|
||||
for (auto i = 0; i < render::Scene::MAX_OUTLINE_COUNT; i++) {
|
||||
const auto groupItems = groups[i];
|
||||
for (auto i = 0; i < OutlineSharedParameters::MAX_OUTLINE_COUNT; i++) {
|
||||
const auto selectionName = task.addJob<ExtractSelectionName>("ExtractSelectionName", outlineSelectionNames, i);
|
||||
const auto groupItems = addSelectItemJobs(task, selectionName, items);
|
||||
const auto outlinedItemIDs = task.addJob<render::MetaToSubItems>("OutlineMetaToSubItemIDs", groupItems);
|
||||
const auto outlinedItems = task.addJob<render::IDsToBounds>("OutlineMetaToSubItems", outlinedItemIDs);
|
||||
|
||||
|
@ -490,6 +523,20 @@ void DrawOutlineTask::build(JobModel& task, const render::Varying& inputs, rende
|
|||
task.addJob<DebugOutline>("OutlineDebug", debugInputs);
|
||||
}
|
||||
|
||||
const render::Varying DrawOutlineTask::addSelectItemJobs(JobModel& task, const render::Varying& selectionName,
|
||||
const RenderFetchCullSortTask::BucketList& items) {
|
||||
const auto& opaques = items[RenderFetchCullSortTask::OPAQUE_SHAPE];
|
||||
const auto& transparents = items[RenderFetchCullSortTask::TRANSPARENT_SHAPE];
|
||||
const auto& metas = items[RenderFetchCullSortTask::META];
|
||||
|
||||
const auto selectMetaInput = SelectItems::Inputs(metas, Varying(), selectionName).asVarying();
|
||||
const auto selectedMetas = task.addJob<SelectItems>("MetaSelection", selectMetaInput);
|
||||
const auto selectMetaAndOpaqueInput = SelectItems::Inputs(opaques, selectedMetas, selectionName).asVarying();
|
||||
const auto selectedMetasAndOpaques = task.addJob<SelectItems>("OpaqueSelection", selectMetaAndOpaqueInput);
|
||||
const auto selectItemInput = SelectItems::Inputs(transparents, selectedMetasAndOpaques, selectionName).asVarying();
|
||||
return task.addJob<SelectItems>("TransparentSelection", selectItemInput);
|
||||
}
|
||||
|
||||
#include "model_shadow_vert.h"
|
||||
#include "skin_model_shadow_vert.h"
|
||||
|
||||
|
|
|
@ -13,6 +13,9 @@
|
|||
#define hifi_render_utils_OutlineEffect_h
|
||||
|
||||
#include <render/Engine.h>
|
||||
#include <render/OutlineStyleStage.h>
|
||||
#include <render/RenderFetchCullSortTask.h>
|
||||
|
||||
#include "DeferredFramebuffer.h"
|
||||
#include "DeferredFrameTransform.h"
|
||||
|
||||
|
@ -46,10 +49,15 @@ using OutlineRessourcesPointer = std::shared_ptr<OutlineRessources>;
|
|||
class OutlineSharedParameters {
|
||||
public:
|
||||
|
||||
enum {
|
||||
MAX_OUTLINE_COUNT = 8
|
||||
};
|
||||
|
||||
OutlineSharedParameters();
|
||||
|
||||
std::array<int, render::Scene::MAX_OUTLINE_COUNT> _blurPixelWidths;
|
||||
std::bitset<render::Scene::MAX_OUTLINE_COUNT> _isFilled;
|
||||
std::array<render::OutlineStyleStage::Index, MAX_OUTLINE_COUNT> _outlineIds;
|
||||
|
||||
static float getBlurPixelWidth(const render::OutlineStyle& style, int frameBufferHeight);
|
||||
};
|
||||
|
||||
using OutlineSharedParametersPointer = std::shared_ptr<OutlineSharedParameters>;
|
||||
|
@ -70,6 +78,38 @@ private:
|
|||
|
||||
};
|
||||
|
||||
class SelectionToOutline {
|
||||
public:
|
||||
|
||||
using Outputs = std::vector<std::string>;
|
||||
using JobModel = render::Job::ModelO<SelectionToOutline, Outputs>;
|
||||
|
||||
SelectionToOutline(OutlineSharedParametersPointer parameters) : _sharedParameters{ parameters } {}
|
||||
|
||||
void run(const render::RenderContextPointer& renderContext, Outputs& outputs);
|
||||
|
||||
private:
|
||||
|
||||
OutlineSharedParametersPointer _sharedParameters;
|
||||
};
|
||||
|
||||
class ExtractSelectionName {
|
||||
public:
|
||||
|
||||
using Inputs = SelectionToOutline::Outputs;
|
||||
using Outputs = std::string;
|
||||
using JobModel = render::Job::ModelIO<ExtractSelectionName, Inputs, Outputs>;
|
||||
|
||||
ExtractSelectionName(unsigned int outlineIndex) : _outlineIndex{ outlineIndex } {}
|
||||
|
||||
void run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs);
|
||||
|
||||
private:
|
||||
|
||||
unsigned int _outlineIndex;
|
||||
|
||||
};
|
||||
|
||||
class DrawOutlineMask {
|
||||
public:
|
||||
|
||||
|
@ -92,49 +132,15 @@ protected:
|
|||
static gpu::PipelinePointer _stencilMaskFillPipeline;
|
||||
};
|
||||
|
||||
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 unoccludedFillOpacity MEMBER unoccludedFillOpacity NOTIFY dirty)
|
||||
Q_PROPERTY(float occludedFillOpacity MEMBER occludedFillOpacity 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 unoccludedFillOpacity{ 0.0f };
|
||||
float occludedFillOpacity{ 0.0f };
|
||||
bool glow{ false };
|
||||
|
||||
signals:
|
||||
void dirty();
|
||||
};
|
||||
|
||||
class DrawOutline {
|
||||
public:
|
||||
|
||||
using Inputs = render::VaryingSet4<DeferredFrameTransformPointer, OutlineRessourcesPointer, DeferredFramebufferPointer, glm::ivec4>;
|
||||
using Config = DrawOutlineConfig;
|
||||
using Config = render::Job::Config;
|
||||
using JobModel = render::Job::ModelI<DrawOutline, Inputs, Config>;
|
||||
|
||||
DrawOutline(unsigned int outlineIndex, OutlineSharedParametersPointer parameters);
|
||||
|
||||
void configure(const Config& config);
|
||||
void run(const render::RenderContextPointer& renderContext, const Inputs& inputs);
|
||||
|
||||
private:
|
||||
|
@ -151,7 +157,7 @@ private:
|
|||
|
||||
using OutlineConfigurationBuffer = gpu::StructBuffer<OutlineParameters>;
|
||||
|
||||
const gpu::PipelinePointer& getPipeline();
|
||||
static const gpu::PipelinePointer& getPipeline(const render::OutlineStyle& style);
|
||||
|
||||
static gpu::PipelinePointer _pipeline;
|
||||
static gpu::PipelinePointer _pipelineFilled;
|
||||
|
@ -160,8 +166,6 @@ private:
|
|||
OutlineParameters _parameters;
|
||||
OutlineSharedParametersPointer _sharedParameters;
|
||||
OutlineConfigurationBuffer _configuration;
|
||||
glm::ivec2 _framebufferSize{ 0,0 };
|
||||
float _size;
|
||||
};
|
||||
|
||||
class DebugOutlineConfig : public render::Job::Config {
|
||||
|
@ -201,8 +205,7 @@ private:
|
|||
class DrawOutlineTask {
|
||||
public:
|
||||
|
||||
using Groups = render::VaryingArray<render::ItemBounds, render::Scene::MAX_OUTLINE_COUNT>;
|
||||
using Inputs = render::VaryingSet4<Groups, DeferredFramebufferPointer, gpu::FramebufferPointer, DeferredFrameTransformPointer>;
|
||||
using Inputs = render::VaryingSet4<RenderFetchCullSortTask::BucketList, DeferredFramebufferPointer, gpu::FramebufferPointer, DeferredFrameTransformPointer>;
|
||||
using Config = render::Task::Config;
|
||||
using JobModel = render::Task::ModelI<DrawOutlineTask, Inputs, Config>;
|
||||
|
||||
|
@ -214,6 +217,8 @@ public:
|
|||
private:
|
||||
|
||||
static void initMaskPipelines(render::ShapePlumber& plumber, gpu::StatePointer state);
|
||||
static const render::Varying addSelectItemJobs(JobModel& task, const render::Varying& selectionName, const RenderFetchCullSortTask::BucketList& items);
|
||||
|
||||
};
|
||||
|
||||
#endif // hifi_render_utils_OutlineEffect_h
|
||||
|
|
|
@ -64,11 +64,11 @@ const render::Varying RenderDeferredTask::addSelectItemJobs(JobModel& task, cons
|
|||
const render::Varying& metas,
|
||||
const render::Varying& opaques,
|
||||
const render::Varying& transparents) {
|
||||
const auto selectMetaInput = SelectItems::Inputs(metas, Varying()).asVarying();
|
||||
const auto selectMetaInput = SelectItems::Inputs(metas, Varying(), std::string()).asVarying();
|
||||
const auto selectedMetas = task.addJob<SelectItems>("MetaSelection", selectMetaInput, selectionName);
|
||||
const auto selectMetaAndOpaqueInput = SelectItems::Inputs(opaques, selectedMetas).asVarying();
|
||||
const auto selectMetaAndOpaqueInput = SelectItems::Inputs(opaques, selectedMetas, std::string()).asVarying();
|
||||
const auto selectedMetasAndOpaques = task.addJob<SelectItems>("OpaqueSelection", selectMetaAndOpaqueInput, selectionName);
|
||||
const auto selectItemInput = SelectItems::Inputs(transparents, selectedMetasAndOpaques).asVarying();
|
||||
const auto selectItemInput = SelectItems::Inputs(transparents, selectedMetasAndOpaques, std::string()).asVarying();
|
||||
return task.addJob<SelectItems>("TransparentSelection", selectItemInput, selectionName);
|
||||
}
|
||||
|
||||
|
@ -187,16 +187,8 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
|
|||
// Select items that need to be outlined
|
||||
const auto selectionBaseName = "contextOverlayHighlightList";
|
||||
const auto selectedItems = addSelectItemJobs(task, selectionBaseName, metas, opaques, transparents);
|
||||
DrawOutlineTask::Groups outlineGroups;
|
||||
outlineGroups[0] = selectedItems;
|
||||
for (auto i = 1; i < render::Scene::MAX_OUTLINE_COUNT; i++) {
|
||||
std::ostringstream selectionName;
|
||||
selectionName << selectionBaseName;
|
||||
selectionName << i;
|
||||
outlineGroups[i] = addSelectItemJobs(task, selectionName.str().c_str(), metas, opaques, transparents);
|
||||
}
|
||||
|
||||
const auto outlineInputs = DrawOutlineTask::Inputs(outlineGroups, deferredFramebuffer, primaryFramebuffer, deferredFrameTransform).asVarying();
|
||||
const auto outlineInputs = DrawOutlineTask::Inputs(items.get0(), deferredFramebuffer, primaryFramebuffer, deferredFrameTransform).asVarying();
|
||||
task.addJob<DrawOutlineTask>("DrawOutline", outlineInputs);
|
||||
|
||||
task.addJob<EndGPURangeTimer>("OutlineRangeTimer", outlineRangeTimer);
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "BackgroundStage.h"
|
||||
#include "HazeStage.h"
|
||||
#include <render/TransitionStage.h>
|
||||
#include <render/OutlineStyleStage.h>
|
||||
#include "DeferredLightingEffect.h"
|
||||
|
||||
void UpdateSceneTask::build(JobModel& task, const render::Varying& input, render::Varying& output) {
|
||||
|
@ -22,6 +23,7 @@ void UpdateSceneTask::build(JobModel& task, const render::Varying& input, render
|
|||
task.addJob<BackgroundStageSetup>("BackgroundStageSetup");
|
||||
task.addJob<HazeStageSetup>("HazeStageSetup");
|
||||
task.addJob<render::TransitionStageSetup>("TransitionStageSetup");
|
||||
task.addJob<render::OutlineStyleStageSetup>("OutlineStyleStageSetup");
|
||||
|
||||
task.addJob<DefaultLightingSetup>("DefaultLightingSetup");
|
||||
|
||||
|
|
|
@ -57,7 +57,12 @@ void SliceItems::run(const RenderContextPointer& renderContext, const ItemBounds
|
|||
}
|
||||
|
||||
void SelectItems::run(const RenderContextPointer& renderContext, const Inputs& inputs, ItemBounds& outItems) {
|
||||
auto selection = renderContext->_scene->getSelection(_name);
|
||||
auto selectionName{ _name };
|
||||
if (!inputs.get2().empty()) {
|
||||
selectionName = inputs.get2();
|
||||
}
|
||||
|
||||
auto selection = renderContext->_scene->getSelection(selectionName);
|
||||
const auto& selectedItems = selection.getItems();
|
||||
const auto& inItems = inputs.get0();
|
||||
const auto itemsToAppend = inputs[1];
|
||||
|
|
|
@ -113,12 +113,13 @@ namespace render {
|
|||
// Keep items belonging to the job selection
|
||||
class SelectItems {
|
||||
public:
|
||||
using Inputs = VaryingSet2<ItemBounds, ItemBounds>;
|
||||
using Inputs = VaryingSet3<ItemBounds, ItemBounds, std::string>;
|
||||
using JobModel = Job::ModelIO<SelectItems, Inputs, ItemBounds>;
|
||||
|
||||
std::string _name;
|
||||
SelectItems() {}
|
||||
SelectItems(const Selection::Name& name) : _name(name) {}
|
||||
|
||||
|
||||
void run(const RenderContextPointer& renderContext, const Inputs& inputs, ItemBounds& outItems);
|
||||
};
|
||||
|
||||
|
|
39
libraries/render/src/render/OutlineStyle.h
Normal file
39
libraries/render/src/render/OutlineStyle.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
//
|
||||
// OutlineStyle.h
|
||||
|
||||
// Created by Olivier Prat on 11/06/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
|
||||
//
|
||||
|
||||
#ifndef hifi_render_utils_OutlineStyle_h
|
||||
#define hifi_render_utils_OutlineStyle_h
|
||||
|
||||
#include <glm/vec3.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace render {
|
||||
|
||||
// This holds the configuration for a particular outline style
|
||||
class OutlineStyle {
|
||||
public:
|
||||
|
||||
bool isFilled() const {
|
||||
return unoccludedFillOpacity > 5e-3f || occludedFillOpacity > 5e-3f;
|
||||
}
|
||||
|
||||
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 };
|
||||
std::string selectionName;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // hifi_render_utils_OutlineStyle_h
|
46
libraries/render/src/render/OutlineStyleStage.cpp
Normal file
46
libraries/render/src/render/OutlineStyleStage.cpp
Normal file
|
@ -0,0 +1,46 @@
|
|||
#include "OutlineStyleStage.h"
|
||||
|
||||
using namespace render;
|
||||
|
||||
std::string OutlineStyleStage::_name("OutlineStyle");
|
||||
|
||||
OutlineStyleStage::Index OutlineStyleStage::addOutline(const std::string& selectionName, const OutlineStyle& style) {
|
||||
Outline outline{ selectionName, style };
|
||||
Index id;
|
||||
|
||||
id = _outlines.newElement(outline);
|
||||
_activeOutlineIds.push_back(id);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void OutlineStyleStage::removeOutline(Index index) {
|
||||
OutlineIdList::iterator idIterator = std::find(_activeOutlineIds.begin(), _activeOutlineIds.end(), index);
|
||||
if (idIterator != _activeOutlineIds.end()) {
|
||||
_activeOutlineIds.erase(idIterator);
|
||||
}
|
||||
if (!_outlines.isElementFreed(index)) {
|
||||
_outlines.freeElement(index);
|
||||
}
|
||||
}
|
||||
|
||||
Index OutlineStyleStage::getOutlineIdBySelection(const std::string& selectionName) const {
|
||||
for (auto outlineId : _activeOutlineIds) {
|
||||
const auto& outline = _outlines.get(outlineId);
|
||||
if (outline._selectionName == selectionName) {
|
||||
return outlineId;
|
||||
}
|
||||
}
|
||||
return INVALID_INDEX;
|
||||
}
|
||||
|
||||
OutlineStyleStageSetup::OutlineStyleStageSetup() {
|
||||
}
|
||||
|
||||
void OutlineStyleStageSetup::run(const render::RenderContextPointer& renderContext) {
|
||||
if (!renderContext->_scene->getStage(OutlineStyleStage::getName())) {
|
||||
auto stage = std::make_shared<OutlineStyleStage>();
|
||||
renderContext->_scene->resetStage(OutlineStyleStage::getName(), stage);
|
||||
}
|
||||
}
|
||||
|
77
libraries/render/src/render/OutlineStyleStage.h
Normal file
77
libraries/render/src/render/OutlineStyleStage.h
Normal file
|
@ -0,0 +1,77 @@
|
|||
//
|
||||
// OutlineStyleStage.h
|
||||
|
||||
// Created by Olivier Prat on 07/07/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
|
||||
//
|
||||
|
||||
#ifndef hifi_render_utils_outlinestage_h
|
||||
#define hifi_render_utils_outlinestage_h
|
||||
|
||||
#include "Stage.h"
|
||||
#include "Engine.h"
|
||||
#include "IndexedContainer.h"
|
||||
#include "OutlineStyle.h"
|
||||
|
||||
namespace render {
|
||||
|
||||
// OutlineStyle stage to set up OutlineStyle-related effects
|
||||
class OutlineStyleStage : public Stage {
|
||||
public:
|
||||
|
||||
class Outline {
|
||||
public:
|
||||
|
||||
Outline(const std::string& selectionName, const OutlineStyle& style) : _selectionName{ selectionName }, _style{ style } { }
|
||||
|
||||
std::string _selectionName;
|
||||
OutlineStyle _style;
|
||||
|
||||
};
|
||||
|
||||
static const std::string& getName() { return _name; }
|
||||
|
||||
using Index = render::indexed_container::Index;
|
||||
static const Index INVALID_INDEX{ render::indexed_container::INVALID_INDEX };
|
||||
using OutlineIdList = render::indexed_container::Indices;
|
||||
|
||||
static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; }
|
||||
|
||||
bool checkOutlineId(Index index) const { return _outlines.checkIndex(index); }
|
||||
|
||||
const Outline& getOutline(Index OutlineStyleId) const { return _outlines.get(OutlineStyleId); }
|
||||
Outline& editOutline(Index OutlineStyleId) { return _outlines.edit(OutlineStyleId); }
|
||||
|
||||
Index addOutline(const std::string& selectionName, const OutlineStyle& style = OutlineStyle());
|
||||
Index getOutlineIdBySelection(const std::string& selectionName) const;
|
||||
void removeOutline(Index index);
|
||||
|
||||
OutlineIdList::iterator begin() { return _activeOutlineIds.begin(); }
|
||||
OutlineIdList::iterator end() { return _activeOutlineIds.end(); }
|
||||
|
||||
private:
|
||||
|
||||
using Outlines = render::indexed_container::IndexedVector<Outline>;
|
||||
|
||||
static std::string _name;
|
||||
|
||||
Outlines _outlines;
|
||||
OutlineIdList _activeOutlineIds;
|
||||
};
|
||||
using OutlineStyleStagePointer = std::shared_ptr<OutlineStyleStage>;
|
||||
|
||||
class OutlineStyleStageSetup {
|
||||
public:
|
||||
using JobModel = render::Job::Model<OutlineStyleStageSetup>;
|
||||
|
||||
OutlineStyleStageSetup();
|
||||
void run(const RenderContextPointer& renderContext);
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
}
|
||||
#endif // hifi_render_utils_outlinestage_h
|
|
@ -14,6 +14,7 @@
|
|||
#include <gpu/Batch.h>
|
||||
#include "Logging.h"
|
||||
#include "TransitionStage.h"
|
||||
#include "OutlineStyleStage.h"
|
||||
|
||||
using namespace render;
|
||||
|
||||
|
@ -54,6 +55,18 @@ void Transaction::resetSelection(const Selection& selection) {
|
|||
_resetSelections.emplace_back(selection);
|
||||
}
|
||||
|
||||
void Transaction::resetSelectionOutline(const std::string& selectionName, const OutlineStyle& style) {
|
||||
_outlineResets.emplace_back(OutlineReset{ selectionName, style });
|
||||
}
|
||||
|
||||
void Transaction::removeOutlineFromSelection(const std::string& selectionName) {
|
||||
_outlineRemoves.emplace_back(selectionName);
|
||||
}
|
||||
|
||||
void Transaction::querySelectionOutline(const std::string& selectionName, SelectionOutlineQueryFunc func) {
|
||||
_outlineQueries.emplace_back(OutlineQuery{ selectionName, func });
|
||||
}
|
||||
|
||||
void Transaction::merge(const Transaction& transaction) {
|
||||
_resetItems.insert(_resetItems.end(), transaction._resetItems.begin(), transaction._resetItems.end());
|
||||
_removedItems.insert(_removedItems.end(), transaction._removedItems.begin(), transaction._removedItems.end());
|
||||
|
@ -62,6 +75,9 @@ void Transaction::merge(const Transaction& transaction) {
|
|||
_addedTransitions.insert(_addedTransitions.end(), transaction._addedTransitions.begin(), transaction._addedTransitions.end());
|
||||
_queriedTransitions.insert(_queriedTransitions.end(), transaction._queriedTransitions.begin(), transaction._queriedTransitions.end());
|
||||
_reAppliedTransitions.insert(_reAppliedTransitions.end(), transaction._reAppliedTransitions.begin(), transaction._reAppliedTransitions.end());
|
||||
_outlineResets.insert(_outlineResets.end(), transaction._outlineResets.begin(), transaction._outlineResets.end());
|
||||
_outlineRemoves.insert(_outlineRemoves.end(), transaction._outlineRemoves.begin(), transaction._outlineRemoves.end());
|
||||
_outlineQueries.insert(_outlineQueries.end(), transaction._outlineQueries.begin(), transaction._outlineQueries.end());
|
||||
}
|
||||
|
||||
|
||||
|
@ -176,6 +192,10 @@ void Scene::processTransactionFrame(const Transaction& transaction) {
|
|||
// resets and potential NEW items
|
||||
resetSelections(transaction._resetSelections);
|
||||
}
|
||||
|
||||
resetOutlines(transaction._outlineResets);
|
||||
removeOutlines(transaction._outlineRemoves);
|
||||
queryOutlines(transaction._outlineQueries);
|
||||
}
|
||||
|
||||
void Scene::resetItems(const Transaction::Resets& transactions) {
|
||||
|
@ -316,6 +336,50 @@ void Scene::queryTransitionItems(const Transaction::TransitionQueries& transacti
|
|||
}
|
||||
}
|
||||
|
||||
void Scene::resetOutlines(const Transaction::OutlineResets& transactions) {
|
||||
auto outlineStage = getStage<OutlineStyleStage>(OutlineStyleStage::getName());
|
||||
|
||||
for (auto& transaction : transactions) {
|
||||
const auto& selectionName = std::get<0>(transaction);
|
||||
const auto& newStyle = std::get<1>(transaction);
|
||||
auto outlineId = outlineStage->getOutlineIdBySelection(selectionName);
|
||||
|
||||
if (OutlineStyleStage::isIndexInvalid(outlineId)) {
|
||||
outlineStage->addOutline(selectionName, newStyle);
|
||||
} else {
|
||||
outlineStage->editOutline(outlineId)._style = newStyle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Scene::removeOutlines(const Transaction::OutlineRemoves& transactions) {
|
||||
auto outlineStage = getStage<OutlineStyleStage>(OutlineStyleStage::getName());
|
||||
|
||||
for (auto& selectionName : transactions) {
|
||||
auto outlineId = outlineStage->getOutlineIdBySelection(selectionName);
|
||||
|
||||
if (!OutlineStyleStage::isIndexInvalid(outlineId)) {
|
||||
outlineStage->removeOutline(outlineId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Scene::queryOutlines(const Transaction::OutlineQueries& transactions) {
|
||||
auto outlineStage = getStage<OutlineStyleStage>(OutlineStyleStage::getName());
|
||||
|
||||
for (auto& transaction : transactions) {
|
||||
const auto& selectionName = std::get<0>(transaction);
|
||||
const auto& func = std::get<1>(transaction);
|
||||
auto outlineId = outlineStage->getOutlineIdBySelection(selectionName);
|
||||
|
||||
if (!OutlineStyleStage::isIndexInvalid(outlineId)) {
|
||||
func(&outlineStage->editOutline(outlineId)._style);
|
||||
} else {
|
||||
func(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Scene::collectSubItems(ItemID parentId, ItemIDs& subItems) const {
|
||||
// Access the true item
|
||||
auto& item = _items[parentId];
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "Stage.h"
|
||||
#include "Selection.h"
|
||||
#include "Transition.h"
|
||||
#include "OutlineStyle.h"
|
||||
|
||||
namespace render {
|
||||
|
||||
|
@ -37,6 +38,7 @@ class Transaction {
|
|||
public:
|
||||
|
||||
typedef std::function<void(ItemID, const Transition*)> TransitionQueryFunc;
|
||||
typedef std::function<void(OutlineStyle const*)> SelectionOutlineQueryFunc;
|
||||
|
||||
Transaction() {}
|
||||
~Transaction() {}
|
||||
|
@ -61,6 +63,10 @@ public:
|
|||
// Selection transactions
|
||||
void resetSelection(const Selection& selection);
|
||||
|
||||
void resetSelectionOutline(const std::string& selectionName, const OutlineStyle& style = OutlineStyle());
|
||||
void removeOutlineFromSelection(const std::string& selectionName);
|
||||
void querySelectionOutline(const std::string& selectionName, SelectionOutlineQueryFunc func);
|
||||
|
||||
void merge(const Transaction& transaction);
|
||||
|
||||
// Checkers if there is work to do when processing the transaction
|
||||
|
@ -75,6 +81,9 @@ protected:
|
|||
using TransitionQuery = std::tuple<ItemID, TransitionQueryFunc>;
|
||||
using TransitionReApply = ItemID;
|
||||
using SelectionReset = Selection;
|
||||
using OutlineReset = std::tuple<std::string, OutlineStyle>;
|
||||
using OutlineRemove = std::string;
|
||||
using OutlineQuery = std::tuple<std::string, SelectionOutlineQueryFunc>;
|
||||
|
||||
using Resets = std::vector<Reset>;
|
||||
using Removes = std::vector<Remove>;
|
||||
|
@ -83,6 +92,9 @@ protected:
|
|||
using TransitionQueries = std::vector<TransitionQuery>;
|
||||
using TransitionReApplies = std::vector<TransitionReApply>;
|
||||
using SelectionResets = std::vector<SelectionReset>;
|
||||
using OutlineResets = std::vector<OutlineReset>;
|
||||
using OutlineRemoves = std::vector<OutlineRemove>;
|
||||
using OutlineQueries = std::vector<OutlineQuery>;
|
||||
|
||||
Resets _resetItems;
|
||||
Removes _removedItems;
|
||||
|
@ -91,6 +103,9 @@ protected:
|
|||
TransitionQueries _queriedTransitions;
|
||||
TransitionReApplies _reAppliedTransitions;
|
||||
SelectionResets _resetSelections;
|
||||
OutlineResets _outlineResets;
|
||||
OutlineRemoves _outlineRemoves;
|
||||
OutlineQueries _outlineQueries;
|
||||
};
|
||||
typedef std::queue<Transaction> TransactionQueue;
|
||||
|
||||
|
@ -103,10 +118,6 @@ typedef std::queue<Transaction> TransactionQueue;
|
|||
class Scene {
|
||||
public:
|
||||
|
||||
enum {
|
||||
MAX_OUTLINE_COUNT = 8
|
||||
};
|
||||
|
||||
Scene(glm::vec3 origin, float size);
|
||||
~Scene();
|
||||
|
||||
|
@ -192,6 +203,9 @@ protected:
|
|||
void transitionItems(const Transaction::TransitionAdds& transactions);
|
||||
void reApplyTransitions(const Transaction::TransitionReApplies& transactions);
|
||||
void queryTransitionItems(const Transaction::TransitionQueries& transactions);
|
||||
void resetOutlines(const Transaction::OutlineResets& transactions);
|
||||
void removeOutlines(const Transaction::OutlineRemoves& transactions);
|
||||
void queryOutlines(const Transaction::OutlineQueries& transactions);
|
||||
|
||||
void collectSubItems(ItemID parentId, ItemIDs& subItems) const;
|
||||
|
||||
|
|
Loading…
Reference in a new issue