mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 17:24:24 +02:00
Working multiple outlines except debugging scripts which applies config to all outlines and graphics bug when filled
This commit is contained in:
parent
76589316df
commit
25b3549e04
12 changed files with 251 additions and 526 deletions
|
@ -36,7 +36,7 @@ ContextOverlayInterface::ContextOverlayInterface() {
|
||||||
|
|
||||||
_selectionToSceneHandlers[0].initialize("contextOverlayHighlightList");
|
_selectionToSceneHandlers[0].initialize("contextOverlayHighlightList");
|
||||||
connect(_selectionScriptingInterface.data(), &SelectionScriptingInterface::selectedItemsListChanged, &_selectionToSceneHandlers[0], &SelectionToSceneHandler::selectedItemsListChanged);
|
connect(_selectionScriptingInterface.data(), &SelectionScriptingInterface::selectedItemsListChanged, &_selectionToSceneHandlers[0], &SelectionToSceneHandler::selectedItemsListChanged);
|
||||||
for (auto i = 1; i < MAX_HIGHLIGHT_COUNT; i++) {
|
for (auto i = 1; i < render::Scene::MAX_OUTLINE_COUNT ; i++) {
|
||||||
_selectionToSceneHandlers[i].initialize(QString("contextOverlayHighlightList")+QString::number(i));
|
_selectionToSceneHandlers[i].initialize(QString("contextOverlayHighlightList")+QString::number(i));
|
||||||
connect(_selectionScriptingInterface.data(), &SelectionScriptingInterface::selectedItemsListChanged, &_selectionToSceneHandlers[i], &SelectionToSceneHandler::selectedItemsListChanged);
|
connect(_selectionScriptingInterface.data(), &SelectionScriptingInterface::selectedItemsListChanged, &_selectionToSceneHandlers[i], &SelectionToSceneHandler::selectedItemsListChanged);
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,10 +48,6 @@ class ContextOverlayInterface : public QObject, public Dependency {
|
||||||
std::shared_ptr<Image3DOverlay> _contextOverlay { nullptr };
|
std::shared_ptr<Image3DOverlay> _contextOverlay { nullptr };
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum {
|
|
||||||
MAX_HIGHLIGHT_COUNT = 5
|
|
||||||
};
|
|
||||||
|
|
||||||
ContextOverlayInterface();
|
ContextOverlayInterface();
|
||||||
|
|
||||||
Q_INVOKABLE QUuid getCurrentEntityWithContextOverlay() { return _currentEntityWithContextOverlay; }
|
Q_INVOKABLE QUuid getCurrentEntityWithContextOverlay() { return _currentEntityWithContextOverlay; }
|
||||||
|
@ -91,7 +87,7 @@ private:
|
||||||
|
|
||||||
void deletingEntity(const EntityItemID& entityItemID);
|
void deletingEntity(const EntityItemID& entityItemID);
|
||||||
|
|
||||||
SelectionToSceneHandler _selectionToSceneHandlers[MAX_HIGHLIGHT_COUNT];
|
SelectionToSceneHandler _selectionToSceneHandlers[render::Scene::MAX_OUTLINE_COUNT];
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_ContextOverlayInterface_h
|
#endif // hifi_ContextOverlayInterface_h
|
||||||
|
|
|
@ -16,13 +16,11 @@
|
||||||
<@include Outline_shared.slh@>
|
<@include Outline_shared.slh@>
|
||||||
|
|
||||||
uniform outlineParamsBuffer {
|
uniform outlineParamsBuffer {
|
||||||
OutlineParameters groups[GROUP_COUNT];
|
OutlineParameters params;
|
||||||
};
|
};
|
||||||
|
|
||||||
uniform sampler2D sceneDepthMap;
|
uniform sampler2D sceneDepthMap;
|
||||||
uniform sampler2D outlinedDepthMap;
|
uniform sampler2D outlinedDepthMap;
|
||||||
uniform sampler2D outlinedIdMap;
|
|
||||||
uniform int enabledGroupsMask;
|
|
||||||
|
|
||||||
in vec2 varTexCoord0;
|
in vec2 varTexCoord0;
|
||||||
out vec4 outFragColor;
|
out vec4 outFragColor;
|
||||||
|
@ -33,52 +31,47 @@ const float OPACITY_EPSILON = 5e-3;
|
||||||
|
|
||||||
<@func main(IS_FILLED)@>
|
<@func main(IS_FILLED)@>
|
||||||
|
|
||||||
int getGroupIndexFromColor(vec4 color) {
|
void main(void) {
|
||||||
ivec4 id = ivec4(color * GROUP_ID_COLOR_COMPONENT_MAX) << ivec4(0, GROUP_ID_COLOR_COMPONENT_BITS, GROUP_ID_COLOR_COMPONENT_BITS*2, GROUP_ID_COLOR_COMPONENT_BITS*3);
|
// We offset by half a texel to be centered on the depth sample. If we don't do this
|
||||||
return (id.r | id.g | id.b | id.a) - 1;
|
// the blur will have a different width between the left / right sides and top / bottom
|
||||||
}
|
// sides of the silhouette
|
||||||
|
vec2 halfTexel = getInvWidthHeight() / 2;
|
||||||
vec4 computeGroupOutline(int centerGroupId, float centerDepth, int groupId, vec2 texCoord) {
|
vec2 texCoord0 = varTexCoord0+halfTexel;
|
||||||
|
float outlinedDepth = texture(outlinedDepthMap, texCoord0).x;
|
||||||
float intensity = 0.0;
|
float intensity = 0.0;
|
||||||
|
|
||||||
if (centerGroupId==groupId && centerDepth < FAR_Z) {
|
if (outlinedDepth < FAR_Z) {
|
||||||
// We're on the outlined object, thus no outline to do!
|
// We're not on the far plane so we are on the outlined object, thus no outline to do!
|
||||||
<@if IS_FILLED@>
|
<@if IS_FILLED@>
|
||||||
OutlineParameters groupParams = groups[groupId];
|
|
||||||
|
|
||||||
// But we need to fill the interior
|
// But we need to fill the interior
|
||||||
float sceneDepth = texture(sceneDepthMap, texCoord).x;
|
float sceneDepth = texture(sceneDepthMap, texCoord0).x;
|
||||||
// Transform to linear depth for better precision
|
// Transform to linear depth for better precision
|
||||||
centerDepth = -evalZeyeFromZdb(centerDepth);
|
outlinedDepth = -evalZeyeFromZdb(outlinedDepth);
|
||||||
sceneDepth = -evalZeyeFromZdb(sceneDepth);
|
sceneDepth = -evalZeyeFromZdb(sceneDepth);
|
||||||
|
|
||||||
// Are we occluded?
|
// Are we occluded?
|
||||||
intensity = (sceneDepth < (centerDepth-LINEAR_DEPTH_BIAS)) ? groupParams._occludedFillOpacity : groupParams._unoccludedFillOpacity;
|
intensity = sceneDepth < (outlinedDepth-LINEAR_DEPTH_BIAS) ? params._occludedFillOpacity : params._unoccludedFillOpacity;
|
||||||
return vec4(groupParams._color.rgb, intensity);
|
|
||||||
<@else@>
|
<@else@>
|
||||||
return vec4(0,0,0,0);
|
discard;
|
||||||
<@endif@>
|
<@endif@>
|
||||||
} else {
|
} else {
|
||||||
OutlineParameters groupParams = groups[groupId];
|
|
||||||
float weight = 0.0;
|
float weight = 0.0;
|
||||||
vec2 deltaUv = groupParams._size / groupParams._blurKernelSize;
|
vec2 deltaUv = params._size / params._blurKernelSize;
|
||||||
vec2 lineStartUv = texCoord - groupParams._size / 2.0;
|
vec2 lineStartUv = texCoord0 - params._size / 2.0;
|
||||||
vec2 uv;
|
vec2 uv;
|
||||||
int x;
|
int x;
|
||||||
int y;
|
int y;
|
||||||
|
|
||||||
for (y=0 ; y<groupParams._blurKernelSize ; y++) {
|
for (y=0 ; y<params._blurKernelSize ; y++) {
|
||||||
uv = lineStartUv;
|
uv = lineStartUv;
|
||||||
lineStartUv.y += deltaUv.y;
|
lineStartUv.y += deltaUv.y;
|
||||||
|
|
||||||
if (uv.y>=0.0 && uv.y<=1.0) {
|
if (uv.y>=0.0 && uv.y<=1.0) {
|
||||||
for (x=0 ; x<groupParams._blurKernelSize ; x++) {
|
for (x=0 ; x<params._blurKernelSize ; x++) {
|
||||||
if (uv.x>=0.0 && uv.x<=1.0)
|
if (uv.x>=0.0 && uv.x<=1.0)
|
||||||
{
|
{
|
||||||
vec4 outlinedIdColor = texture(outlinedIdMap, uv);
|
outlinedDepth = texture(outlinedDepthMap, uv).x;
|
||||||
float outlinedDepth = texture(outlinedDepthMap, uv).x;
|
intensity += (outlinedDepth < FAR_Z) ? 1.0 : 0.0;
|
||||||
int outlinedId = getGroupIndexFromColor(outlinedIdColor);
|
|
||||||
intensity += (outlinedDepth<FAR_Z /*&& outlinedId!=groupId*/) ? 1.0 : 0.0;
|
|
||||||
weight += 1.f;
|
weight += 1.f;
|
||||||
}
|
}
|
||||||
uv.x += deltaUv.x;
|
uv.x += deltaUv.x;
|
||||||
|
@ -88,41 +81,13 @@ vec4 computeGroupOutline(int centerGroupId, float centerDepth, int groupId, vec2
|
||||||
|
|
||||||
intensity /= weight;
|
intensity /= weight;
|
||||||
if (intensity < OPACITY_EPSILON) {
|
if (intensity < OPACITY_EPSILON) {
|
||||||
return vec4(0,0,0,0);
|
discard;
|
||||||
}
|
}
|
||||||
intensity = min(1.0, intensity / groupParams._threshold) * groupParams._intensity;
|
|
||||||
return vec4(groupParams._color.rgb, intensity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void main(void) {
|
intensity = min(1.0, intensity / params._threshold) * params._intensity;
|
||||||
// We offset by half a texel to be centered on the depth sample. If we don't do this
|
|
||||||
// the blur will have a different width between the left / right sides and top / bottom
|
|
||||||
// sides of the silhouette
|
|
||||||
vec2 halfTexel = getInvWidthHeight() / 2;
|
|
||||||
vec2 texCoord0 = varTexCoord0+halfTexel;
|
|
||||||
vec4 outlinedIdColor = texture(outlinedIdMap, texCoord0);
|
|
||||||
float outlinedDepth = texture(outlinedDepthMap, texCoord0).x;
|
|
||||||
float intensity = 0.0;
|
|
||||||
int groupId = getGroupIndexFromColor(outlinedIdColor);
|
|
||||||
|
|
||||||
vec4 finalColor = vec4(0,0,0,0);
|
|
||||||
int groupMask = 1;
|
|
||||||
for (int i=0 ; i<GROUP_COUNT ; i++) {
|
|
||||||
if ((enabledGroupsMask & groupMask)!=0) {
|
|
||||||
vec4 groupColor = computeGroupOutline(groupId, outlinedDepth, i, texCoord0);
|
|
||||||
finalColor.rgb = mix(finalColor.rgb, groupColor.rgb, groupColor.a);
|
|
||||||
// If first group we encounter then don't mix the color
|
|
||||||
finalColor.rgb = finalColor.a==0 ? groupColor.rgb : finalColor.rgb;
|
|
||||||
finalColor.a = min(1, finalColor.a+groupColor.a*(1-finalColor.a));
|
|
||||||
}
|
|
||||||
groupMask <<= 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (finalColor.a < OPACITY_EPSILON) {
|
outFragColor = vec4(params._color.rgb, intensity);
|
||||||
discard;
|
|
||||||
}
|
|
||||||
outFragColor = finalColor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
<@endfunc@>
|
<@endfunc@>
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "gpu/Context.h"
|
#include "gpu/Context.h"
|
||||||
#include "gpu/StandardShaderLib.h"
|
#include "gpu/StandardShaderLib.h"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
#include "surfaceGeometry_copyDepth_frag.h"
|
#include "surfaceGeometry_copyDepth_frag.h"
|
||||||
#include "debug_deferred_buffer_vert.h"
|
#include "debug_deferred_buffer_vert.h"
|
||||||
|
@ -30,22 +31,29 @@ using namespace render;
|
||||||
OutlineRessources::OutlineRessources() {
|
OutlineRessources::OutlineRessources() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void OutlineRessources::update(const gpu::TexturePointer& colorBuffer) {
|
void OutlineRessources::update(const gpu::FramebufferPointer& primaryFrameBuffer) {
|
||||||
|
auto newFrameSize = glm::ivec2(primaryFrameBuffer->getSize());
|
||||||
|
|
||||||
// If the depth buffer or size changed, we need to delete our FBOs and recreate them at the
|
// If the depth buffer or size changed, we need to delete our FBOs and recreate them at the
|
||||||
// new correct dimensions.
|
// new correct dimensions.
|
||||||
if (_depthTexture) {
|
if (_depthFrameBuffer) {
|
||||||
auto newFrameSize = glm::ivec2(colorBuffer->getDimensions());
|
|
||||||
if (_frameSize != newFrameSize) {
|
if (_frameSize != newFrameSize) {
|
||||||
_frameSize = newFrameSize;
|
_frameSize = newFrameSize;
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!_colorFrameBuffer) {
|
||||||
|
if (_frameSize != newFrameSize) {
|
||||||
|
_frameSize = newFrameSize;
|
||||||
|
// Failing to recreate this frame buffer when the screen has been resized creates a bug on Mac
|
||||||
|
_colorFrameBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("primaryWithoutDepth"));
|
||||||
|
_colorFrameBuffer->setRenderBuffer(0, primaryFrameBuffer->getRenderBuffer(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OutlineRessources::clear() {
|
void OutlineRessources::clear() {
|
||||||
_frameBuffer.reset();
|
_depthFrameBuffer.reset();
|
||||||
_depthTexture.reset();
|
|
||||||
_idTexture.reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OutlineRessources::allocate() {
|
void OutlineRessources::allocate() {
|
||||||
|
@ -53,177 +61,95 @@ void OutlineRessources::allocate() {
|
||||||
auto width = _frameSize.x;
|
auto width = _frameSize.x;
|
||||||
auto height = _frameSize.y;
|
auto height = _frameSize.y;
|
||||||
auto depthFormat = gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH);
|
auto depthFormat = gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH);
|
||||||
|
auto depthTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(depthFormat, width, height));
|
||||||
_idTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_2, width, height));
|
|
||||||
_depthTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(depthFormat, width, height));
|
|
||||||
|
|
||||||
_frameBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("outlineDepth"));
|
_depthFrameBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("outlineDepth"));
|
||||||
_frameBuffer->setDepthStencilBuffer(_depthTexture, depthFormat);
|
_depthFrameBuffer->setDepthStencilBuffer(depthTexture, depthFormat);
|
||||||
_frameBuffer->setRenderBuffer(0, _idTexture);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gpu::FramebufferPointer OutlineRessources::getFramebuffer() {
|
gpu::FramebufferPointer OutlineRessources::getDepthFramebuffer() {
|
||||||
if (!_frameBuffer) {
|
if (!_depthFrameBuffer) {
|
||||||
allocate();
|
allocate();
|
||||||
}
|
}
|
||||||
return _frameBuffer;
|
return _depthFrameBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
gpu::TexturePointer OutlineRessources::getDepthTexture() {
|
gpu::TexturePointer OutlineRessources::getDepthTexture() {
|
||||||
if (!_depthTexture) {
|
return getDepthFramebuffer()->getDepthStencilBuffer();
|
||||||
allocate();
|
|
||||||
}
|
|
||||||
return _depthTexture;
|
|
||||||
}
|
|
||||||
|
|
||||||
gpu::TexturePointer OutlineRessources::getIdTexture() {
|
|
||||||
if (!_idTexture) {
|
|
||||||
allocate();
|
|
||||||
}
|
|
||||||
return _idTexture;
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::vec4 encodeIdToColor(unsigned int id) {
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
unsigned int r : 2;
|
|
||||||
unsigned int g : 2;
|
|
||||||
unsigned int b : 2;
|
|
||||||
unsigned int a : 2;
|
|
||||||
};
|
|
||||||
unsigned char id;
|
|
||||||
} groupId;
|
|
||||||
|
|
||||||
static_assert(GROUP_ID_COLOR_COMPONENT_BITS == 2, "Assuming two bits per component contrary to GLSL shader code. See Outline_shared.slh");
|
|
||||||
|
|
||||||
assert(id < 254);
|
|
||||||
groupId.id = id+1;
|
|
||||||
|
|
||||||
glm::vec4 idColor{ groupId.r, groupId.g, groupId.b, groupId.a };
|
|
||||||
|
|
||||||
// Normalize. Since we put 2 bits into each color component, each component has a maximum
|
|
||||||
// value of 3.
|
|
||||||
idColor /= GROUP_ID_COLOR_COMPONENT_MAX;
|
|
||||||
return idColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& output) {
|
|
||||||
assert(renderContext->args);
|
|
||||||
assert(renderContext->args->hasViewFrustum());
|
|
||||||
auto& groups = inputs.get0();
|
|
||||||
auto& deferredFrameBuffer = inputs.get1();
|
|
||||||
|
|
||||||
RenderArgs* args = renderContext->args;
|
|
||||||
ShapeKey::Builder defaultKeyBuilder;
|
|
||||||
auto hasOutline = false;
|
|
||||||
|
|
||||||
if (!_outlineRessources) {
|
|
||||||
_outlineRessources = std::make_shared<OutlineRessources>();
|
|
||||||
}
|
|
||||||
_outlineRessources->update(deferredFrameBuffer->getDeferredColorTexture());
|
|
||||||
|
|
||||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
|
||||||
args->_batch = &batch;
|
|
||||||
|
|
||||||
auto maskPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder);
|
|
||||||
auto maskSkinnedPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder.withSkinned());
|
|
||||||
auto colorLoc = maskPipeline.get()->pipeline->getProgram()->getUniforms().findLocation("color");
|
|
||||||
auto skinnedColorLoc = maskSkinnedPipeline.get()->pipeline->getProgram()->getUniforms().findLocation("color");
|
|
||||||
unsigned int groupId = 0;
|
|
||||||
|
|
||||||
for (auto& inShapeBounds : groups) {
|
|
||||||
if (!inShapeBounds.isNull()) {
|
|
||||||
auto& inShapes = inShapeBounds.get<render::ShapeBounds>();
|
|
||||||
|
|
||||||
if (!inShapes.empty()) {
|
|
||||||
if (!hasOutline) {
|
|
||||||
batch.setFramebuffer(_outlineRessources->getFramebuffer());
|
|
||||||
// Clear it only if it hasn't been done before
|
|
||||||
batch.clearFramebuffer(
|
|
||||||
gpu::Framebuffer::BUFFER_COLOR0 | gpu::Framebuffer::BUFFER_DEPTH,
|
|
||||||
vec4(0.0f, 0.0f, 0.0f, 0.0f), 1.0f, 0, false);
|
|
||||||
|
|
||||||
// Setup camera, projection and viewport for all items
|
|
||||||
batch.setViewportTransform(args->_viewport);
|
|
||||||
batch.setStateScissorRect(args->_viewport);
|
|
||||||
|
|
||||||
glm::mat4 projMat;
|
|
||||||
Transform viewMat;
|
|
||||||
args->getViewFrustum().evalProjectionMatrix(projMat);
|
|
||||||
args->getViewFrustum().evalViewTransform(viewMat);
|
|
||||||
|
|
||||||
batch.setProjectionTransform(projMat);
|
|
||||||
batch.setViewTransform(viewMat);
|
|
||||||
hasOutline = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<ShapeKey> skinnedShapeKeys{};
|
|
||||||
// Encode group id in quantized color
|
|
||||||
glm::vec4 idColor = encodeIdToColor(groupId);
|
|
||||||
|
|
||||||
// Iterate through all inShapes and render the unskinned
|
|
||||||
args->_shapePipeline = maskPipeline;
|
|
||||||
batch.setPipeline(maskPipeline->pipeline);
|
|
||||||
batch._glUniform4f(colorLoc, idColor.r, idColor.g, idColor.b, idColor.a);
|
|
||||||
for (auto items : inShapes) {
|
|
||||||
if (items.first.isSkinned()) {
|
|
||||||
skinnedShapeKeys.push_back(items.first);
|
|
||||||
} else {
|
|
||||||
renderItems(renderContext, items.second);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reiterate to render the skinned
|
|
||||||
args->_shapePipeline = maskSkinnedPipeline;
|
|
||||||
batch.setPipeline(maskSkinnedPipeline->pipeline);
|
|
||||||
batch._glUniform4f(skinnedColorLoc, idColor.r, idColor.g, idColor.b, idColor.a);
|
|
||||||
for (const auto& key : skinnedShapeKeys) {
|
|
||||||
renderItems(renderContext, inShapes.at(key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
++groupId;
|
|
||||||
}
|
|
||||||
|
|
||||||
args->_shapePipeline = nullptr;
|
|
||||||
args->_batch = nullptr;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (hasOutline) {
|
|
||||||
output = _outlineRessources;
|
|
||||||
} else {
|
|
||||||
output = nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PrepareDrawOutline::PrepareDrawOutline() {
|
PrepareDrawOutline::PrepareDrawOutline() {
|
||||||
|
_ressources = std::make_shared<OutlineRessources>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrepareDrawOutline::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) {
|
void PrepareDrawOutline::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) {
|
||||||
auto destinationFrameBuffer = inputs;
|
auto destinationFrameBuffer = inputs;
|
||||||
auto framebufferSize = destinationFrameBuffer->getSize();
|
|
||||||
|
|
||||||
if (!_primaryWithoutDepthBuffer || framebufferSize != _frameBufferSize) {
|
_ressources->update(destinationFrameBuffer);
|
||||||
// Failing to recreate this frame buffer when the screen has been resized creates a bug on Mac
|
outputs = _ressources;
|
||||||
_primaryWithoutDepthBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("primaryWithoutDepth"));
|
}
|
||||||
_primaryWithoutDepthBuffer->setRenderBuffer(0, destinationFrameBuffer->getRenderBuffer(0));
|
|
||||||
_frameBufferSize = framebufferSize;
|
void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) {
|
||||||
|
assert(renderContext->args);
|
||||||
|
assert(renderContext->args->hasViewFrustum());
|
||||||
|
auto& inShapes = inputs.get0();
|
||||||
|
|
||||||
|
if (!inShapes.empty()) {
|
||||||
|
auto ressources = inputs.get1();
|
||||||
|
|
||||||
|
RenderArgs* args = renderContext->args;
|
||||||
|
ShapeKey::Builder defaultKeyBuilder;
|
||||||
|
|
||||||
|
outputs = args->_viewport;
|
||||||
|
|
||||||
|
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||||
|
args->_batch = &batch;
|
||||||
|
|
||||||
|
auto maskPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder);
|
||||||
|
auto maskSkinnedPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder.withSkinned());
|
||||||
|
|
||||||
|
batch.setFramebuffer(ressources->getDepthFramebuffer());
|
||||||
|
batch.clearDepthFramebuffer(1.0f);
|
||||||
|
|
||||||
|
// Setup camera, projection and viewport for all items
|
||||||
|
batch.setViewportTransform(args->_viewport);
|
||||||
|
batch.setStateScissorRect(args->_viewport);
|
||||||
|
|
||||||
|
glm::mat4 projMat;
|
||||||
|
Transform viewMat;
|
||||||
|
args->getViewFrustum().evalProjectionMatrix(projMat);
|
||||||
|
args->getViewFrustum().evalViewTransform(viewMat);
|
||||||
|
|
||||||
|
batch.setProjectionTransform(projMat);
|
||||||
|
batch.setViewTransform(viewMat);
|
||||||
|
|
||||||
|
std::vector<ShapeKey> skinnedShapeKeys{};
|
||||||
|
|
||||||
|
// Iterate through all inShapes and render the unskinned
|
||||||
|
args->_shapePipeline = maskPipeline;
|
||||||
|
batch.setPipeline(maskPipeline->pipeline);
|
||||||
|
for (auto items : inShapes) {
|
||||||
|
if (items.first.isSkinned()) {
|
||||||
|
skinnedShapeKeys.push_back(items.first);
|
||||||
|
} else {
|
||||||
|
renderItems(renderContext, items.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reiterate to render the skinned
|
||||||
|
args->_shapePipeline = maskSkinnedPipeline;
|
||||||
|
batch.setPipeline(maskSkinnedPipeline->pipeline);
|
||||||
|
for (const auto& key : skinnedShapeKeys) {
|
||||||
|
renderItems(renderContext, inShapes.at(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
args->_shapePipeline = nullptr;
|
||||||
|
args->_batch = nullptr;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Outline rect should be null as there are no outlined shapes
|
||||||
|
outputs = glm::ivec4(0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
@ -236,41 +162,28 @@ void DrawOutline::configure(const Config& config) {
|
||||||
auto& configuration = _configuration.edit();
|
auto& configuration = _configuration.edit();
|
||||||
const auto OPACITY_EPSILON = 5e-3f;
|
const auto OPACITY_EPSILON = 5e-3f;
|
||||||
|
|
||||||
bool someFilled = false;
|
configuration._color = config.color;
|
||||||
bool isFilled;
|
configuration._intensity = config.intensity * (config.glow ? 2.f : 1.f);
|
||||||
|
configuration._unoccludedFillOpacity = config.unoccludedFillOpacity;
|
||||||
|
configuration._occludedFillOpacity = config.occludedFillOpacity;
|
||||||
|
configuration._threshold = config.glow ? 1.f : 1e-3f;
|
||||||
|
configuration._blurKernelSize = std::min(10, 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;
|
||||||
|
configuration._size.x = (_size * _framebufferSize.y) / _framebufferSize.x;
|
||||||
|
configuration._size.y = _size;
|
||||||
|
|
||||||
for (auto groupId = 0; groupId < MAX_GROUP_COUNT; groupId++) {
|
_isFilled = (config.unoccludedFillOpacity > OPACITY_EPSILON || config.occludedFillOpacity > OPACITY_EPSILON);
|
||||||
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) {
|
void DrawOutline::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) {
|
||||||
auto outlineFrameBuffer = inputs.get1();
|
auto outlineFrameBuffer = inputs.get1();
|
||||||
|
auto outlineRect = inputs.get4();
|
||||||
|
|
||||||
if (outlineFrameBuffer) {
|
if (outlineFrameBuffer && outlineRect.z>0 && outlineRect.w>0) {
|
||||||
auto sceneDepthBuffer = inputs.get2();
|
auto sceneDepthBuffer = inputs.get2();
|
||||||
const auto frameTransform = inputs.get0();
|
const auto frameTransform = inputs.get0();
|
||||||
auto outlinedDepthTexture = outlineFrameBuffer->getDepthTexture();
|
auto outlinedDepthTexture = outlineFrameBuffer->getDepthTexture();
|
||||||
auto outlinedIdTexture = outlineFrameBuffer->getIdTexture();
|
|
||||||
auto destinationFrameBuffer = inputs.get3();
|
auto destinationFrameBuffer = inputs.get3();
|
||||||
auto framebufferSize = glm::ivec2(outlinedDepthTexture->getDimensions());
|
auto framebufferSize = glm::ivec2(outlinedDepthTexture->getDimensions());
|
||||||
|
|
||||||
|
@ -281,13 +194,8 @@ void DrawOutline::run(const render::RenderContextPointer& renderContext, const I
|
||||||
if (_framebufferSize != framebufferSize)
|
if (_framebufferSize != framebufferSize)
|
||||||
{
|
{
|
||||||
auto& configuration = _configuration.edit();
|
auto& configuration = _configuration.edit();
|
||||||
|
configuration._size.x = (_size * framebufferSize.y) / framebufferSize.x;
|
||||||
for (auto groupId = 0; groupId < MAX_GROUP_COUNT; groupId++) {
|
configuration._size.y = _size;
|
||||||
auto& groupConfig = configuration._groups[groupId];
|
|
||||||
|
|
||||||
groupConfig._size.x = (_sizes[groupId] * framebufferSize.y) / framebufferSize.x;
|
|
||||||
groupConfig._size.y = _sizes[groupId];
|
|
||||||
}
|
|
||||||
_framebufferSize = framebufferSize;
|
_framebufferSize = framebufferSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,14 +209,10 @@ void DrawOutline::run(const render::RenderContextPointer& renderContext, const I
|
||||||
batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, args->_viewport));
|
batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, args->_viewport));
|
||||||
batch.setPipeline(pipeline);
|
batch.setPipeline(pipeline);
|
||||||
|
|
||||||
auto enabledGroupsLoc = pipeline->getProgram()->getUniforms().findLocation("enabledGroupsMask");
|
|
||||||
|
|
||||||
batch.setUniformBuffer(OUTLINE_PARAMS_SLOT, _configuration);
|
batch.setUniformBuffer(OUTLINE_PARAMS_SLOT, _configuration);
|
||||||
batch.setUniformBuffer(FRAME_TRANSFORM_SLOT, frameTransform->getFrameTransformBuffer());
|
batch.setUniformBuffer(FRAME_TRANSFORM_SLOT, frameTransform->getFrameTransformBuffer());
|
||||||
batch.setResourceTexture(SCENE_DEPTH_SLOT, sceneDepthBuffer->getPrimaryDepthTexture());
|
batch.setResourceTexture(SCENE_DEPTH_SLOT, sceneDepthBuffer->getPrimaryDepthTexture());
|
||||||
batch.setResourceTexture(OUTLINED_DEPTH_SLOT, outlinedDepthTexture);
|
batch.setResourceTexture(OUTLINED_DEPTH_SLOT, outlinedDepthTexture);
|
||||||
batch.setResourceTexture(OUTLINED_ID_SLOT, outlinedIdTexture);
|
|
||||||
batch._glUniform1i(enabledGroupsLoc, 1);
|
|
||||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -326,7 +230,6 @@ const gpu::PipelinePointer& DrawOutline::getPipeline() {
|
||||||
slotBindings.insert(gpu::Shader::Binding("deferredFrameTransformBuffer", FRAME_TRANSFORM_SLOT));
|
slotBindings.insert(gpu::Shader::Binding("deferredFrameTransformBuffer", FRAME_TRANSFORM_SLOT));
|
||||||
slotBindings.insert(gpu::Shader::Binding("sceneDepthMap", SCENE_DEPTH_SLOT));
|
slotBindings.insert(gpu::Shader::Binding("sceneDepthMap", SCENE_DEPTH_SLOT));
|
||||||
slotBindings.insert(gpu::Shader::Binding("outlinedDepthMap", OUTLINED_DEPTH_SLOT));
|
slotBindings.insert(gpu::Shader::Binding("outlinedDepthMap", OUTLINED_DEPTH_SLOT));
|
||||||
slotBindings.insert(gpu::Shader::Binding("outlinedIdMap", OUTLINED_ID_SLOT));
|
|
||||||
gpu::Shader::makeProgram(*program, slotBindings);
|
gpu::Shader::makeProgram(*program, slotBindings);
|
||||||
|
|
||||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||||
|
@ -339,19 +242,17 @@ const gpu::PipelinePointer& DrawOutline::getPipeline() {
|
||||||
gpu::Shader::makeProgram(*program, slotBindings);
|
gpu::Shader::makeProgram(*program, slotBindings);
|
||||||
_pipelineFilled = gpu::Pipeline::create(program, state);
|
_pipelineFilled = gpu::Pipeline::create(program, state);
|
||||||
}
|
}
|
||||||
return _mode == M_SOME_FILLED ? _pipelineFilled : _pipeline;
|
return _isFilled ? _pipelineFilled : _pipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
DebugOutline::DebugOutline() {
|
DebugOutline::DebugOutline() {
|
||||||
_geometryDepthId = DependencyManager::get<GeometryCache>()->allocateID();
|
_geometryDepthId = DependencyManager::get<GeometryCache>()->allocateID();
|
||||||
_geometryColorId = DependencyManager::get<GeometryCache>()->allocateID();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DebugOutline::~DebugOutline() {
|
DebugOutline::~DebugOutline() {
|
||||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||||
if (geometryCache) {
|
if (geometryCache) {
|
||||||
geometryCache->releaseID(_geometryDepthId);
|
geometryCache->releaseID(_geometryDepthId);
|
||||||
geometryCache->releaseID(_geometryColorId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -360,9 +261,9 @@ void DebugOutline::configure(const Config& config) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebugOutline::run(const render::RenderContextPointer& renderContext, const Inputs& input) {
|
void DebugOutline::run(const render::RenderContextPointer& renderContext, const Inputs& input) {
|
||||||
const auto outlineFramebuffer = input;
|
const auto outlineRessources = input;
|
||||||
|
|
||||||
if (_isDisplayEnabled && outlineFramebuffer) {
|
if (_isDisplayEnabled && outlineRessources) {
|
||||||
assert(renderContext->args);
|
assert(renderContext->args);
|
||||||
assert(renderContext->args->hasViewFrustum());
|
assert(renderContext->args->hasViewFrustum());
|
||||||
RenderArgs* args = renderContext->args;
|
RenderArgs* args = renderContext->args;
|
||||||
|
@ -384,20 +285,10 @@ void DebugOutline::run(const render::RenderContextPointer& renderContext, const
|
||||||
const glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f);
|
const glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
|
||||||
batch.setPipeline(getDepthPipeline());
|
batch.setPipeline(getDepthPipeline());
|
||||||
batch.setResourceTexture(0, outlineFramebuffer->getDepthTexture());
|
batch.setResourceTexture(0, outlineRessources->getDepthTexture());
|
||||||
{
|
const glm::vec2 bottomLeft(-1.0f, -1.0f);
|
||||||
const glm::vec2 bottomLeft(-1.0f, -1.0f);
|
const glm::vec2 topRight(1.0f, 1.0f);
|
||||||
const glm::vec2 topRight(0.0f, 1.0f);
|
geometryBuffer->renderQuad(batch, bottomLeft, topRight, color, _geometryDepthId);
|
||||||
geometryBuffer->renderQuad(batch, bottomLeft, topRight, color, _geometryDepthId);
|
|
||||||
}
|
|
||||||
|
|
||||||
batch.setPipeline(getIdPipeline());
|
|
||||||
batch.setResourceTexture(0, outlineFramebuffer->getIdTexture());
|
|
||||||
{
|
|
||||||
const glm::vec2 bottomLeft(0.0f, -1.0f);
|
|
||||||
const glm::vec2 topRight(1.0f, 1.0f);
|
|
||||||
geometryBuffer->renderQuad(batch, bottomLeft, topRight, color, _geometryColorId);
|
|
||||||
}
|
|
||||||
|
|
||||||
batch.setResourceTexture(0, nullptr);
|
batch.setResourceTexture(0, nullptr);
|
||||||
});
|
});
|
||||||
|
@ -439,27 +330,6 @@ void DebugOutline::initializePipelines() {
|
||||||
|
|
||||||
_depthPipeline = gpu::Pipeline::create(program, state);
|
_depthPipeline = gpu::Pipeline::create(program, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ID shader
|
|
||||||
{
|
|
||||||
static const std::string ID_SHADER{
|
|
||||||
"vec4 getFragmentColor() {"
|
|
||||||
" return texelFetch(albedoMap, ivec2(gl_FragCoord.xy), 0); "
|
|
||||||
"}"
|
|
||||||
};
|
|
||||||
|
|
||||||
auto fragmentShader = FRAGMENT_SHADER;
|
|
||||||
fragmentShader.replace(SOURCE_PLACEHOLDER_INDEX, SOURCE_PLACEHOLDER.size(), ID_SHADER);
|
|
||||||
|
|
||||||
const auto ps = gpu::Shader::createPixel(fragmentShader);
|
|
||||||
const auto program = gpu::Shader::createProgram(vs, ps);
|
|
||||||
|
|
||||||
gpu::Shader::BindingSet slotBindings;
|
|
||||||
slotBindings.insert(gpu::Shader::Binding("albedoMap", 0));
|
|
||||||
gpu::Shader::makeProgram(*program, slotBindings);
|
|
||||||
|
|
||||||
_idPipeline = gpu::Pipeline::create(program, state);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const gpu::PipelinePointer& DebugOutline::getDepthPipeline() {
|
const gpu::PipelinePointer& DebugOutline::getDepthPipeline() {
|
||||||
|
@ -470,14 +340,6 @@ const gpu::PipelinePointer& DebugOutline::getDepthPipeline() {
|
||||||
return _depthPipeline;
|
return _depthPipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
const gpu::PipelinePointer& DebugOutline::getIdPipeline() {
|
|
||||||
if (!_idPipeline) {
|
|
||||||
initializePipelines();
|
|
||||||
}
|
|
||||||
|
|
||||||
return _idPipeline;
|
|
||||||
}
|
|
||||||
|
|
||||||
DrawOutlineTask::DrawOutlineTask() {
|
DrawOutlineTask::DrawOutlineTask() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -496,70 +358,63 @@ void DrawOutlineTask::build(JobModel& task, const render::Varying& inputs, rende
|
||||||
ShapePlumberPointer shapePlumber = std::make_shared<ShapePlumber>();
|
ShapePlumberPointer shapePlumber = std::make_shared<ShapePlumber>();
|
||||||
{
|
{
|
||||||
auto state = std::make_shared<gpu::State>();
|
auto state = std::make_shared<gpu::State>();
|
||||||
state->setDepthTest(true, true, gpu::LESS_EQUAL);
|
state->setDepthTest(true, true, gpu::LESS);
|
||||||
state->setColorWriteMask(true, true, true, true);
|
state->setColorWriteMask(false, false, false, false);
|
||||||
|
|
||||||
initMaskPipelines(*shapePlumber, state);
|
initMaskPipelines(*shapePlumber, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawOutlineMask::Groups sortedBounds;
|
// Prepare for outline group rendering.
|
||||||
for (auto i = 0; i < Outline::MAX_GROUP_COUNT; i++) {
|
const auto outlineRessources = task.addJob<PrepareDrawOutline>("PrepareOutline", primaryFramebuffer);
|
||||||
|
|
||||||
|
for (auto i = 0; i < render::Scene::MAX_OUTLINE_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);
|
||||||
|
|
||||||
// Sort
|
// Sort
|
||||||
const auto sortedPipelines = task.addJob<render::PipelineSortShapes>("OutlinePipelineSort", outlinedItems);
|
const auto sortedPipelines = task.addJob<render::PipelineSortShapes>("OutlinePipelineSort", outlinedItems);
|
||||||
sortedBounds[i] = task.addJob<render::DepthSortShapes>("OutlineDepthSort", sortedPipelines);
|
const auto sortedBounds = task.addJob<render::DepthSortShapes>("OutlineDepthSort", sortedPipelines);
|
||||||
|
|
||||||
|
// Draw depth of outlined objects in separate buffer
|
||||||
|
std::string name;
|
||||||
|
{
|
||||||
|
std::ostringstream stream;
|
||||||
|
stream << "OutlineMask" << i;
|
||||||
|
name = stream.str();
|
||||||
|
}
|
||||||
|
const auto drawMaskInputs = DrawOutlineMask::Inputs(sortedBounds, outlineRessources).asVarying();
|
||||||
|
const auto outlinedRect = task.addJob<DrawOutlineMask>(name, drawMaskInputs, shapePlumber);
|
||||||
|
|
||||||
|
// Draw outline
|
||||||
|
{
|
||||||
|
std::ostringstream stream;
|
||||||
|
stream << "OutlineEffect" << i;
|
||||||
|
name = stream.str();
|
||||||
|
}
|
||||||
|
const auto drawOutlineInputs = DrawOutline::Inputs(deferredFrameTransform, outlineRessources, sceneFrameBuffer, primaryFramebuffer, outlinedRect).asVarying();
|
||||||
|
task.addJob<DrawOutline>(name, drawOutlineInputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw depth of outlined objects in separate buffer
|
|
||||||
const auto drawMaskInputs = DrawOutlineMask::Inputs(sortedBounds, sceneFrameBuffer).asVarying();
|
|
||||||
const auto outlinedFrameBuffer = task.addJob<DrawOutlineMask>("OutlineMask", drawMaskInputs, shapePlumber);
|
|
||||||
|
|
||||||
// Prepare for outline group rendering.
|
|
||||||
const auto destFrameBuffer = task.addJob<PrepareDrawOutline>("PrepareOutline", primaryFramebuffer);
|
|
||||||
|
|
||||||
// Draw outline
|
|
||||||
const auto drawOutlineInputs = DrawOutline::Inputs(deferredFrameTransform, outlinedFrameBuffer, sceneFrameBuffer, destFrameBuffer).asVarying();
|
|
||||||
task.addJob<DrawOutline>("OutlineEffect", drawOutlineInputs);
|
|
||||||
|
|
||||||
// Debug outline
|
// Debug outline
|
||||||
task.addJob<DebugOutline>("OutlineDebug", outlinedFrameBuffer);
|
task.addJob<DebugOutline>("OutlineDebug", outlineRessources);
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "model_shadow_vert.h"
|
#include "model_shadow_vert.h"
|
||||||
#include "model_shadow_fade_vert.h"
|
|
||||||
#include "skin_model_shadow_vert.h"
|
#include "skin_model_shadow_vert.h"
|
||||||
#include "skin_model_shadow_fade_vert.h"
|
|
||||||
|
|
||||||
#include "model_outline_frag.h"
|
#include "model_shadow_frag.h"
|
||||||
#include "model_outline_fade_frag.h"
|
|
||||||
|
|
||||||
void DrawOutlineTask::initMaskPipelines(render::ShapePlumber& shapePlumber, gpu::StatePointer state) {
|
void DrawOutlineTask::initMaskPipelines(render::ShapePlumber& shapePlumber, gpu::StatePointer state) {
|
||||||
auto modelVertex = gpu::Shader::createVertex(std::string(model_shadow_vert));
|
auto modelVertex = gpu::Shader::createVertex(std::string(model_shadow_vert));
|
||||||
auto modelPixel = gpu::Shader::createPixel(std::string(model_outline_frag));
|
auto modelPixel = gpu::Shader::createPixel(std::string(model_shadow_frag));
|
||||||
gpu::ShaderPointer modelProgram = gpu::Shader::createProgram(modelVertex, modelPixel);
|
gpu::ShaderPointer modelProgram = gpu::Shader::createProgram(modelVertex, modelPixel);
|
||||||
shapePlumber.addPipeline(
|
shapePlumber.addPipeline(
|
||||||
ShapeKey::Filter::Builder().withoutSkinned().withoutFade(),
|
ShapeKey::Filter::Builder().withoutSkinned(),
|
||||||
modelProgram, state);
|
modelProgram, state);
|
||||||
|
|
||||||
auto skinVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_vert));
|
auto skinVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_vert));
|
||||||
gpu::ShaderPointer skinProgram = gpu::Shader::createProgram(skinVertex, modelPixel);
|
gpu::ShaderPointer skinProgram = gpu::Shader::createProgram(skinVertex, modelPixel);
|
||||||
shapePlumber.addPipeline(
|
shapePlumber.addPipeline(
|
||||||
ShapeKey::Filter::Builder().withSkinned().withoutFade(),
|
ShapeKey::Filter::Builder().withSkinned(),
|
||||||
skinProgram, state);
|
skinProgram, state);
|
||||||
|
|
||||||
auto modelFadeVertex = gpu::Shader::createVertex(std::string(model_shadow_fade_vert));
|
|
||||||
auto modelFadePixel = gpu::Shader::createPixel(std::string(model_outline_fade_frag));
|
|
||||||
gpu::ShaderPointer modelFadeProgram = gpu::Shader::createProgram(modelFadeVertex, modelFadePixel);
|
|
||||||
shapePlumber.addPipeline(
|
|
||||||
ShapeKey::Filter::Builder().withoutSkinned().withFade(),
|
|
||||||
modelFadeProgram, state);
|
|
||||||
|
|
||||||
auto skinFadeVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_fade_vert));
|
|
||||||
gpu::ShaderPointer skinFadeProgram = gpu::Shader::createProgram(skinFadeVertex, modelFadePixel);
|
|
||||||
shapePlumber.addPipeline(
|
|
||||||
ShapeKey::Filter::Builder().withSkinned().withFade(),
|
|
||||||
skinFadeProgram, state);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,12 +20,13 @@ class OutlineRessources {
|
||||||
public:
|
public:
|
||||||
OutlineRessources();
|
OutlineRessources();
|
||||||
|
|
||||||
gpu::FramebufferPointer getFramebuffer();
|
gpu::FramebufferPointer getDepthFramebuffer();
|
||||||
gpu::TexturePointer getIdTexture();
|
|
||||||
gpu::TexturePointer getDepthTexture();
|
gpu::TexturePointer getDepthTexture();
|
||||||
|
|
||||||
|
gpu::FramebufferPointer getColorFramebuffer() { return _colorFrameBuffer; }
|
||||||
|
|
||||||
// Update the source framebuffer size which will drive the allocation of all the other resources.
|
// Update the source framebuffer size which will drive the allocation of all the other resources.
|
||||||
void update(const gpu::TexturePointer& colorBuffer);
|
void update(const gpu::FramebufferPointer& primaryFrameBuffer);
|
||||||
const glm::ivec2& getSourceFrameSize() const { return _frameSize; }
|
const glm::ivec2& getSourceFrameSize() const { return _frameSize; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -33,9 +34,8 @@ protected:
|
||||||
void clear();
|
void clear();
|
||||||
void allocate();
|
void allocate();
|
||||||
|
|
||||||
gpu::FramebufferPointer _frameBuffer;
|
gpu::FramebufferPointer _depthFrameBuffer;
|
||||||
gpu::TexturePointer _depthTexture;
|
gpu::FramebufferPointer _colorFrameBuffer;
|
||||||
gpu::TexturePointer _idTexture;
|
|
||||||
|
|
||||||
glm::ivec2 _frameSize;
|
glm::ivec2 _frameSize;
|
||||||
};
|
};
|
||||||
|
@ -45,9 +45,8 @@ using OutlineRessourcesPointer = std::shared_ptr<OutlineRessources>;
|
||||||
class PrepareDrawOutline {
|
class PrepareDrawOutline {
|
||||||
public:
|
public:
|
||||||
using Inputs = gpu::FramebufferPointer;
|
using Inputs = gpu::FramebufferPointer;
|
||||||
using Outputs = gpu::FramebufferPointer;
|
using Outputs = OutlineRessourcesPointer;
|
||||||
using Config = render::Job::Config;
|
using JobModel = render::Job::ModelIO<PrepareDrawOutline, Inputs, Outputs>;
|
||||||
using JobModel = render::Job::ModelIO<PrepareDrawOutline, Inputs, Outputs, Config>;
|
|
||||||
|
|
||||||
PrepareDrawOutline();
|
PrepareDrawOutline();
|
||||||
|
|
||||||
|
@ -55,84 +54,63 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
gpu::FramebufferPointer _primaryWithoutDepthBuffer;
|
OutlineRessourcesPointer _ressources;
|
||||||
gpu::Vec2u _frameBufferSize{ 0, 0 };
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Outline {
|
class DrawOutlineMask {
|
||||||
|
public:
|
||||||
|
|
||||||
|
using Inputs = render::VaryingSet2<render::ShapeBounds, OutlineRessourcesPointer>;
|
||||||
|
using Outputs = glm::ivec4;
|
||||||
|
using JobModel = render::Job::ModelIO<DrawOutlineMask, Inputs, Outputs>;
|
||||||
|
|
||||||
|
DrawOutlineMask(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {}
|
||||||
|
|
||||||
|
void run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
#include "Outline_shared.slh"
|
render::ShapePlumberPointer _shapePlumber;
|
||||||
|
|
||||||
public:
|
|
||||||
enum {
|
|
||||||
MAX_GROUP_COUNT = GROUP_COUNT
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DrawOutlineConfig : public render::Job::Config {
|
class DrawOutlineConfig : public render::Job::Config {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(int group MEMBER group WRITE setGroup NOTIFY dirty);
|
Q_PROPERTY(bool glow MEMBER glow NOTIFY dirty)
|
||||||
Q_PROPERTY(bool glow READ isGlow WRITE setGlow NOTIFY dirty)
|
Q_PROPERTY(float width MEMBER width NOTIFY dirty)
|
||||||
Q_PROPERTY(float width READ getWidth WRITE setWidth NOTIFY dirty)
|
Q_PROPERTY(float intensity MEMBER intensity 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 colorR READ getColorR WRITE setColorR NOTIFY dirty)
|
||||||
Q_PROPERTY(float colorG READ getColorG WRITE setColorG 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 colorB READ getColorB WRITE setColorB NOTIFY dirty)
|
||||||
Q_PROPERTY(float unoccludedFillOpacity READ getUnoccludedFillOpacity WRITE setUnoccludedFillOpacity NOTIFY dirty)
|
Q_PROPERTY(float unoccludedFillOpacity MEMBER unoccludedFillOpacity NOTIFY dirty)
|
||||||
Q_PROPERTY(float occludedFillOpacity READ getOccludedFillOpacity WRITE setOccludedFillOpacity NOTIFY dirty)
|
Q_PROPERTY(float occludedFillOpacity MEMBER occludedFillOpacity NOTIFY dirty)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
struct GroupParameters {
|
void setColorR(float value) { color.r = value; emit dirty(); }
|
||||||
glm::vec3 color{ 1.f, 0.7f, 0.2f };
|
float getColorR() const { return color.r; }
|
||||||
float width{ 2.0f };
|
|
||||||
float intensity{ 0.9f };
|
|
||||||
float unoccludedFillOpacity{ 0.0f };
|
|
||||||
float occludedFillOpacity{ 0.0f };
|
|
||||||
bool glow{ false };
|
|
||||||
};
|
|
||||||
|
|
||||||
int getGroupCount() const;
|
void setColorG(float value) { color.g = value; emit dirty(); }
|
||||||
|
float getColorG() const { return color.g; }
|
||||||
|
|
||||||
void setColorR(float value) { groupParameters[group].color.r = value; emit dirty(); }
|
void setColorB(float value) { color.b = value; emit dirty(); }
|
||||||
float getColorR() const { return groupParameters[group].color.r; }
|
float getColorB() const { return color.b; }
|
||||||
|
|
||||||
void setColorG(float value) { groupParameters[group].color.g = value; emit dirty(); }
|
glm::vec3 color{ 1.f, 0.7f, 0.2f };
|
||||||
float getColorG() const { return groupParameters[group].color.g; }
|
float width{ 2.0f };
|
||||||
|
float intensity{ 0.9f };
|
||||||
void setColorB(float value) { groupParameters[group].color.b = value; emit dirty(); }
|
float unoccludedFillOpacity{ 0.0f };
|
||||||
float getColorB() const { return groupParameters[group].color.b; }
|
float occludedFillOpacity{ 0.0f };
|
||||||
|
bool glow{ false };
|
||||||
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:
|
signals:
|
||||||
void dirty();
|
void dirty();
|
||||||
};
|
};
|
||||||
|
|
||||||
class DrawOutline : public Outline {
|
class DrawOutline {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
using Inputs = render::VaryingSet4<DeferredFrameTransformPointer, OutlineRessourcesPointer, DeferredFramebufferPointer, gpu::FramebufferPointer>;
|
using Inputs = render::VaryingSet5<DeferredFrameTransformPointer, OutlineRessourcesPointer, DeferredFramebufferPointer, gpu::FramebufferPointer, glm::ivec4>;
|
||||||
using Config = DrawOutlineConfig;
|
using Config = DrawOutlineConfig;
|
||||||
using JobModel = render::Job::ModelI<DrawOutline, Inputs, Config>;
|
using JobModel = render::Job::ModelI<DrawOutline, Inputs, Config>;
|
||||||
|
|
||||||
|
@ -143,71 +121,27 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
#include "Outline_shared.slh"
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
SCENE_DEPTH_SLOT = 0,
|
SCENE_DEPTH_SLOT = 0,
|
||||||
OUTLINED_DEPTH_SLOT,
|
OUTLINED_DEPTH_SLOT,
|
||||||
OUTLINED_ID_SLOT,
|
|
||||||
|
|
||||||
OUTLINE_PARAMS_SLOT = 0,
|
OUTLINE_PARAMS_SLOT = 0,
|
||||||
FRAME_TRANSFORM_SLOT,
|
FRAME_TRANSFORM_SLOT,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct OutlineConfiguration {
|
using OutlineConfigurationBuffer = gpu::StructBuffer<OutlineParameters>;
|
||||||
OutlineParameters _groups[MAX_GROUP_COUNT];
|
|
||||||
};
|
|
||||||
|
|
||||||
enum Mode {
|
|
||||||
M_ALL_UNFILLED,
|
|
||||||
M_SOME_FILLED,
|
|
||||||
};
|
|
||||||
|
|
||||||
using OutlineConfigurationBuffer = gpu::StructBuffer<OutlineConfiguration>;
|
|
||||||
|
|
||||||
const gpu::PipelinePointer& getPipeline();
|
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::ivec2 _framebufferSize{ 0,0 };
|
glm::ivec2 _framebufferSize{ 0,0 };
|
||||||
Mode _mode{ M_ALL_UNFILLED };
|
bool _isFilled{ false };
|
||||||
float _sizes[MAX_GROUP_COUNT];
|
float _size;
|
||||||
};
|
|
||||||
|
|
||||||
class DrawOutlineTask {
|
|
||||||
public:
|
|
||||||
|
|
||||||
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>;
|
|
||||||
|
|
||||||
DrawOutlineTask();
|
|
||||||
|
|
||||||
void configure(const Config& config);
|
|
||||||
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs);
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
static void initMaskPipelines(render::ShapePlumber& plumber, gpu::StatePointer state);
|
|
||||||
};
|
|
||||||
|
|
||||||
class DrawOutlineMask {
|
|
||||||
public:
|
|
||||||
|
|
||||||
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;
|
|
||||||
using JobModel = render::Job::ModelIO<DrawOutlineMask, Inputs, Outputs>;
|
|
||||||
|
|
||||||
DrawOutlineMask(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {}
|
|
||||||
|
|
||||||
void run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& output);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
render::ShapePlumberPointer _shapePlumber;
|
|
||||||
OutlineRessourcesPointer _outlineRessources;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DebugOutlineConfig : public render::Job::Config {
|
class DebugOutlineConfig : public render::Job::Config {
|
||||||
|
@ -237,16 +171,30 @@ public:
|
||||||
private:
|
private:
|
||||||
|
|
||||||
gpu::PipelinePointer _depthPipeline;
|
gpu::PipelinePointer _depthPipeline;
|
||||||
gpu::PipelinePointer _idPipeline;
|
|
||||||
int _geometryDepthId{ 0 };
|
int _geometryDepthId{ 0 };
|
||||||
int _geometryColorId{ 0 };
|
|
||||||
bool _isDisplayEnabled{ false };
|
bool _isDisplayEnabled{ false };
|
||||||
|
|
||||||
const gpu::PipelinePointer& getDepthPipeline();
|
const gpu::PipelinePointer& getDepthPipeline();
|
||||||
const gpu::PipelinePointer& getIdPipeline();
|
|
||||||
void initializePipelines();
|
void initializePipelines();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class DrawOutlineTask {
|
||||||
|
public:
|
||||||
|
|
||||||
|
using Groups = render::VaryingArray<render::ItemBounds, render::Scene::MAX_OUTLINE_COUNT>;
|
||||||
|
using Inputs = render::VaryingSet4<Groups, DeferredFramebufferPointer, gpu::FramebufferPointer, DeferredFrameTransformPointer>;
|
||||||
|
using Config = render::Task::Config;
|
||||||
|
using JobModel = render::Task::ModelI<DrawOutlineTask, Inputs, Config>;
|
||||||
|
|
||||||
|
DrawOutlineTask();
|
||||||
|
|
||||||
|
void configure(const Config& config);
|
||||||
|
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
static void initMaskPipelines(render::ShapePlumber& plumber, gpu::StatePointer state);
|
||||||
|
};
|
||||||
|
|
||||||
#endif // hifi_render_utils_OutlineEffect_h
|
#endif // hifi_render_utils_OutlineEffect_h
|
||||||
|
|
||||||
|
|
|
@ -9,10 +9,6 @@
|
||||||
# define VEC4 vec4
|
# define VEC4 vec4
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define GROUP_COUNT 7
|
|
||||||
#define GROUP_ID_COLOR_COMPONENT_BITS 2
|
|
||||||
#define GROUP_ID_COLOR_COMPONENT_MAX 3
|
|
||||||
|
|
||||||
struct OutlineParameters
|
struct OutlineParameters
|
||||||
{
|
{
|
||||||
VEC3 _color;
|
VEC3 _color;
|
||||||
|
|
|
@ -181,7 +181,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
|
||||||
const auto selectedItems = addSelectItemJobs(task, selectionBaseName, metas, opaques, transparents);
|
const auto selectedItems = addSelectItemJobs(task, selectionBaseName, metas, opaques, transparents);
|
||||||
DrawOutlineTask::Groups outlineGroups;
|
DrawOutlineTask::Groups outlineGroups;
|
||||||
outlineGroups[0] = selectedItems;
|
outlineGroups[0] = selectedItems;
|
||||||
for (auto i = 1; i < DrawOutline::MAX_GROUP_COUNT; i++) {
|
for (auto i = 1; i < render::Scene::MAX_OUTLINE_COUNT; i++) {
|
||||||
std::ostringstream selectionName;
|
std::ostringstream selectionName;
|
||||||
selectionName << selectionBaseName;
|
selectionName << selectionBaseName;
|
||||||
selectionName << i;
|
selectionName << i;
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
<@include gpu/Config.slh@>
|
|
||||||
<$VERSION_HEADER$>
|
|
||||||
// Generated on <$_SCRIBE_DATE$>
|
|
||||||
//
|
|
||||||
// model_outline.frag
|
|
||||||
// fragment shader
|
|
||||||
//
|
|
||||||
// Created by Olivier Prat on 10/13/17.
|
|
||||||
// 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
|
|
||||||
//
|
|
||||||
|
|
||||||
layout(location = 0) out vec4 _fragColor;
|
|
||||||
|
|
||||||
uniform vec4 color;
|
|
||||||
|
|
||||||
void main(void) {
|
|
||||||
_fragColor = color;
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
<@include gpu/Config.slh@>
|
|
||||||
<$VERSION_HEADER$>
|
|
||||||
// Generated on <$_SCRIBE_DATE$>
|
|
||||||
//
|
|
||||||
// model_outline_fade.frag
|
|
||||||
// fragment shader
|
|
||||||
//
|
|
||||||
// Created by Olivier Prat on 10/13/17.
|
|
||||||
// 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
|
|
||||||
//
|
|
||||||
|
|
||||||
<@include Fade.slh@>
|
|
||||||
<$declareFadeFragment()$>
|
|
||||||
|
|
||||||
layout(location = 0) out vec4 _fragColor;
|
|
||||||
|
|
||||||
uniform vec4 color;
|
|
||||||
|
|
||||||
in vec4 _worldPosition;
|
|
||||||
|
|
||||||
void main(void) {
|
|
||||||
FadeObjectParams fadeParams;
|
|
||||||
|
|
||||||
<$fetchFadeObjectParams(fadeParams)$>
|
|
||||||
applyFadeClip(fadeParams, _worldPosition.xyz);
|
|
||||||
|
|
||||||
_fragColor = color;
|
|
||||||
}
|
|
|
@ -102,6 +102,11 @@ typedef std::queue<Transaction> TransactionQueue;
|
||||||
// Items are notified accordingly on any update message happening
|
// Items are notified accordingly on any update message happening
|
||||||
class Scene {
|
class Scene {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MAX_OUTLINE_COUNT = 16
|
||||||
|
};
|
||||||
|
|
||||||
Scene(glm::vec3 origin, float size);
|
Scene(glm::vec3 origin, float size);
|
||||||
~Scene();
|
~Scene();
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,15 @@ var end2 = {
|
||||||
visible: true
|
visible: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var outlineGroupIndex = 0
|
||||||
|
|
||||||
|
function setOutlineGroupIndex(index) {
|
||||||
|
print("Switching to outline group "+index)
|
||||||
|
outlineGroupIndex = index
|
||||||
|
}
|
||||||
|
|
||||||
|
window.fromQml.connect(setOutlineGroupIndex);
|
||||||
|
|
||||||
var renderStates = [{name: "test", end: end}];
|
var renderStates = [{name: "test", end: end}];
|
||||||
var defaultRenderStates = [{name: "test", distance: 20.0, end: end2}];
|
var defaultRenderStates = [{name: "test", distance: 20.0, end: end2}];
|
||||||
|
|
||||||
|
@ -78,7 +87,6 @@ function update() {
|
||||||
|
|
||||||
var result = LaserPointers.getPrevRayPickResult(ray);
|
var result = LaserPointers.getPrevRayPickResult(ray);
|
||||||
var selectionName = "contextOverlayHighlightList"
|
var selectionName = "contextOverlayHighlightList"
|
||||||
var outlineGroupIndex = Render.getConfig("RenderMainView.OutlineEffect").group
|
|
||||||
|
|
||||||
if (outlineGroupIndex>0) {
|
if (outlineGroupIndex>0) {
|
||||||
selectionName += outlineGroupIndex
|
selectionName += outlineGroupIndex
|
||||||
|
@ -100,7 +108,7 @@ function update() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Selection.addToSelectedItemsList(selectionName, typeName, result.objectID)
|
Selection.addToSelectedItemsList(selectionName, typeName, result.objectID)
|
||||||
//print("type: " + result.type + ", id: " + result.objectID);
|
print("OUTLINE " + outlineGroupIndex + " picked type: " + result.type + ", id: " + result.objectID);
|
||||||
|
|
||||||
prevID = result.objectID;
|
prevID = result.objectID;
|
||||||
prevType = typeName;
|
prevType = typeName;
|
||||||
|
|
|
@ -15,7 +15,8 @@ import "configSlider"
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
property var debugConfig: Render.getConfig("RenderMainView.OutlineDebug")
|
property var debugConfig: Render.getConfig("RenderMainView.OutlineDebug")
|
||||||
property var drawConfig: Render.getConfig("RenderMainView.OutlineEffect")
|
property var drawConfig: Render.getConfig("RenderMainView.OutlineEffect0")
|
||||||
|
signal sendToScript(var message);
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
spacing: 8
|
spacing: 8
|
||||||
|
@ -26,12 +27,15 @@ Item {
|
||||||
Timer {
|
Timer {
|
||||||
id: postpone
|
id: postpone
|
||||||
interval: 100; running: false; repeat: false
|
interval: 100; running: false; repeat: false
|
||||||
onTriggered: { paramWidgetLoader.sourceComponent = paramWidgets }
|
onTriggered: {
|
||||||
|
paramWidgetLoader.sourceComponent = paramWidgets;
|
||||||
|
sendToScript(currentIndex)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
onCurrentIndexChanged: {
|
onCurrentIndexChanged: {
|
||||||
// This is a hack to be sure the widgets below properly reflect the change of category: delete the Component
|
// This is a hack to be sure the widgets below properly reflect the change of index: delete the Component
|
||||||
// by setting the loader source to Null and then recreate it 100ms later
|
// by setting the loader source to Null and then recreate it 100ms later
|
||||||
root.drawConfig["group"] = currentIndex
|
root.drawConfig = Render.getConfig("RenderMainView.OutlineEffect"+currentIndex)
|
||||||
paramWidgetLoader.sourceComponent = undefined;
|
paramWidgetLoader.sourceComponent = undefined;
|
||||||
postpone.interval = 100
|
postpone.interval = 100
|
||||||
postpone.start()
|
postpone.start()
|
||||||
|
|
Loading…
Reference in a new issue