mirror of
https://github.com/JulianGro/overte.git
synced 2025-08-09 20:08:31 +02:00
Working stencil mask with object bounding boxes
This commit is contained in:
parent
e9743d4c95
commit
4b598a6e24
8 changed files with 305 additions and 223 deletions
|
@ -11,7 +11,6 @@
|
||||||
#include "OutlineEffect.h"
|
#include "OutlineEffect.h"
|
||||||
|
|
||||||
#include "GeometryCache.h"
|
#include "GeometryCache.h"
|
||||||
#include "RenderUtilsLogging.h"
|
|
||||||
|
|
||||||
#include "CubeProjectedPolygon.h"
|
#include "CubeProjectedPolygon.h"
|
||||||
|
|
||||||
|
@ -28,10 +27,11 @@
|
||||||
#include "debug_deferred_buffer_frag.h"
|
#include "debug_deferred_buffer_frag.h"
|
||||||
#include "Outline_frag.h"
|
#include "Outline_frag.h"
|
||||||
#include "Outline_filled_frag.h"
|
#include "Outline_filled_frag.h"
|
||||||
|
#include "Outline_aabox_vert.h"
|
||||||
|
|
||||||
using namespace render;
|
using namespace render;
|
||||||
|
|
||||||
#define OUTLINE_USE_SCISSOR false
|
#define OUTLINE_STENCIL_MASK 1
|
||||||
|
|
||||||
OutlineRessources::OutlineRessources() {
|
OutlineRessources::OutlineRessources() {
|
||||||
}
|
}
|
||||||
|
@ -56,15 +56,16 @@ void OutlineRessources::update(const gpu::FramebufferPointer& primaryFrameBuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
void OutlineRessources::allocateColorBuffer(const gpu::FramebufferPointer& primaryFrameBuffer) {
|
void OutlineRessources::allocateColorBuffer(const gpu::FramebufferPointer& primaryFrameBuffer) {
|
||||||
_colorFrameBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("primaryWithoutDepth"));
|
_colorFrameBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("primaryWithStencil"));
|
||||||
_colorFrameBuffer->setRenderBuffer(0, primaryFrameBuffer->getRenderBuffer(0));
|
_colorFrameBuffer->setRenderBuffer(0, primaryFrameBuffer->getRenderBuffer(0));
|
||||||
|
_colorFrameBuffer->setDepthStencilBuffer(_depthStencilTexture, _depthStencilTexture->getTexelFormat());
|
||||||
}
|
}
|
||||||
|
|
||||||
void OutlineRessources::allocateDepthBuffer(const gpu::FramebufferPointer& primaryFrameBuffer) {
|
void OutlineRessources::allocateDepthBuffer(const gpu::FramebufferPointer& primaryFrameBuffer) {
|
||||||
auto depthFormat = gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH);
|
auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL);
|
||||||
auto depthTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(depthFormat, _frameSize.x, _frameSize.y));
|
_depthStencilTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(depthFormat, _frameSize.x, _frameSize.y));
|
||||||
_depthFrameBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("outlineDepth"));
|
_depthFrameBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("outlineDepth"));
|
||||||
_depthFrameBuffer->setDepthStencilBuffer(depthTexture, depthFormat);
|
_depthFrameBuffer->setDepthStencilBuffer(_depthStencilTexture, depthFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
gpu::FramebufferPointer OutlineRessources::getDepthFramebuffer() {
|
gpu::FramebufferPointer OutlineRessources::getDepthFramebuffer() {
|
||||||
|
@ -73,10 +74,10 @@ gpu::FramebufferPointer OutlineRessources::getDepthFramebuffer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
gpu::TexturePointer OutlineRessources::getDepthTexture() {
|
gpu::TexturePointer OutlineRessources::getDepthTexture() {
|
||||||
return getDepthFramebuffer()->getDepthStencilBuffer();
|
return _depthStencilTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
gpu::FramebufferPointer OutlineRessources::getColorFramebuffer() {
|
gpu::FramebufferPointer OutlineRessources::getColorFramebuffer() {
|
||||||
assert(_colorFrameBuffer);
|
assert(_colorFrameBuffer);
|
||||||
return _colorFrameBuffer;
|
return _colorFrameBuffer;
|
||||||
}
|
}
|
||||||
|
@ -96,6 +97,10 @@ void PrepareDrawOutline::run(const render::RenderContextPointer& renderContext,
|
||||||
outputs = _ressources;
|
outputs = _ressources;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gpu::PipelinePointer DrawOutlineMask::_stencilMaskPipeline;
|
||||||
|
gpu::PipelinePointer DrawOutlineMask::_stencilMaskFillPipeline;
|
||||||
|
gpu::BufferPointer DrawOutlineMask::_boundsBuffer;
|
||||||
|
|
||||||
DrawOutlineMask::DrawOutlineMask(unsigned int outlineIndex,
|
DrawOutlineMask::DrawOutlineMask(unsigned int outlineIndex,
|
||||||
render::ShapePlumberPointer shapePlumber, OutlineSharedParametersPointer parameters) :
|
render::ShapePlumberPointer shapePlumber, OutlineSharedParametersPointer parameters) :
|
||||||
_outlineIndex{ outlineIndex },
|
_outlineIndex{ outlineIndex },
|
||||||
|
@ -108,26 +113,42 @@ void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, con
|
||||||
assert(renderContext->args->hasViewFrustum());
|
assert(renderContext->args->hasViewFrustum());
|
||||||
auto& inShapes = inputs.get0();
|
auto& inShapes = inputs.get0();
|
||||||
|
|
||||||
|
if (!_stencilMaskPipeline || !_stencilMaskFillPipeline) {
|
||||||
|
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||||
|
state->setDepthTest(true, false, gpu::LESS_EQUAL);
|
||||||
|
state->setStencilTest(true, 0xFF, gpu::State::StencilTest(OUTLINE_STENCIL_MASK, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_ZERO, gpu::State::STENCIL_OP_REPLACE));
|
||||||
|
state->setColorWriteMask(false, false, false, false);
|
||||||
|
state->setCullMode(gpu::State::CULL_FRONT);
|
||||||
|
|
||||||
|
gpu::StatePointer fillState = gpu::StatePointer(new gpu::State());
|
||||||
|
fillState->setDepthTest(false, false, gpu::LESS_EQUAL);
|
||||||
|
fillState->setStencilTest(true, 0xFF, gpu::State::StencilTest(OUTLINE_STENCIL_MASK, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_REPLACE));
|
||||||
|
fillState->setColorWriteMask(false, false, false, false);
|
||||||
|
fillState->setCullMode(gpu::State::CULL_FRONT);
|
||||||
|
|
||||||
|
auto vs = gpu::Shader::createVertex(std::string(Outline_aabox_vert));
|
||||||
|
auto ps = gpu::StandardShaderLib::getDrawWhitePS();
|
||||||
|
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||||
|
|
||||||
|
gpu::Shader::BindingSet slotBindings;
|
||||||
|
gpu::Shader::makeProgram(*program, slotBindings);
|
||||||
|
|
||||||
|
_stencilMaskPipeline = gpu::Pipeline::create(program, state);
|
||||||
|
_stencilMaskFillPipeline = gpu::Pipeline::create(program, fillState);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_boundsBuffer) {
|
||||||
|
_boundsBuffer = std::make_shared<gpu::Buffer>(sizeof(render::ItemBound));
|
||||||
|
}
|
||||||
|
|
||||||
if (!inShapes.empty()) {
|
if (!inShapes.empty()) {
|
||||||
auto ressources = inputs.get1();
|
auto ressources = inputs.get1();
|
||||||
|
|
||||||
RenderArgs* args = renderContext->args;
|
RenderArgs* args = renderContext->args;
|
||||||
ShapeKey::Builder defaultKeyBuilder;
|
ShapeKey::Builder defaultKeyBuilder;
|
||||||
|
|
||||||
#if OUTLINE_USE_SCISSOR
|
|
||||||
auto framebufferSize = ressources->getSourceFrameSize();
|
|
||||||
// First thing we do is determine the projected bounding rect of all the outlined items
|
|
||||||
auto outlinedRect = computeOutlineRect(inShapes, args->getViewFrustum(), framebufferSize);
|
|
||||||
auto blurPixelWidth = _sharedParameters->_blurPixelWidths[_outlineIndex];
|
|
||||||
//qCDebug(renderutils) << "Outline rect is " << outlinedRect.x << ' ' << outlinedRect.y << ' ' << outlinedRect.z << ' ' << outlinedRect.w;
|
|
||||||
|
|
||||||
// Add 1 pixel of extra margin to be on the safe side
|
|
||||||
outputs = expandRect(outlinedRect, blurPixelWidth+1, framebufferSize);
|
|
||||||
outlinedRect = expandRect(outputs, blurPixelWidth+1, framebufferSize);
|
|
||||||
#else
|
|
||||||
// Render full screen
|
// Render full screen
|
||||||
outputs = args->_viewport;
|
outputs = args->_viewport;
|
||||||
#endif
|
|
||||||
|
|
||||||
// Clear the framebuffer without stereo
|
// Clear the framebuffer without stereo
|
||||||
// Needs to be distinct from the other batch because using the clear call
|
// Needs to be distinct from the other batch because using the clear call
|
||||||
|
@ -135,25 +156,22 @@ void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, con
|
||||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||||
batch.enableStereo(false);
|
batch.enableStereo(false);
|
||||||
batch.setFramebuffer(ressources->getDepthFramebuffer());
|
batch.setFramebuffer(ressources->getDepthFramebuffer());
|
||||||
batch.clearDepthFramebuffer(1.0f);
|
batch.clearDepthStencilFramebuffer(1.0f, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
glm::mat4 projMat;
|
||||||
|
Transform viewMat;
|
||||||
|
args->getViewFrustum().evalProjectionMatrix(projMat);
|
||||||
|
args->getViewFrustum().evalViewTransform(viewMat);
|
||||||
|
|
||||||
|
render::ItemBounds itemBounds;
|
||||||
|
|
||||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||||
args->_batch = &batch;
|
args->_batch = &batch;
|
||||||
|
|
||||||
auto maskPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder);
|
auto maskPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder);
|
||||||
auto maskSkinnedPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder.withSkinned());
|
auto maskSkinnedPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder.withSkinned());
|
||||||
|
|
||||||
glm::mat4 projMat;
|
|
||||||
Transform viewMat;
|
|
||||||
args->getViewFrustum().evalProjectionMatrix(projMat);
|
|
||||||
args->getViewFrustum().evalViewTransform(viewMat);
|
|
||||||
|
|
||||||
#if OUTLINE_USE_SCISSOR
|
|
||||||
batch.setStateScissorRect(outlinedRect);
|
|
||||||
#endif
|
|
||||||
batch.setFramebuffer(ressources->getDepthFramebuffer());
|
|
||||||
|
|
||||||
// Setup camera, projection and viewport for all items
|
// Setup camera, projection and viewport for all items
|
||||||
batch.setViewportTransform(args->_viewport);
|
batch.setViewportTransform(args->_viewport);
|
||||||
batch.setProjectionTransform(projMat);
|
batch.setProjectionTransform(projMat);
|
||||||
|
@ -164,7 +182,8 @@ void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, con
|
||||||
// Iterate through all inShapes and render the unskinned
|
// Iterate through all inShapes and render the unskinned
|
||||||
args->_shapePipeline = maskPipeline;
|
args->_shapePipeline = maskPipeline;
|
||||||
batch.setPipeline(maskPipeline->pipeline);
|
batch.setPipeline(maskPipeline->pipeline);
|
||||||
for (auto items : inShapes) {
|
for (const auto& items : inShapes) {
|
||||||
|
itemBounds.insert(itemBounds.end(), items.second.begin(), items.second.end());
|
||||||
if (items.first.isSkinned()) {
|
if (items.first.isSkinned()) {
|
||||||
skinnedShapeKeys.push_back(items.first);
|
skinnedShapeKeys.push_back(items.first);
|
||||||
} else {
|
} else {
|
||||||
|
@ -182,72 +201,34 @@ void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, con
|
||||||
args->_shapePipeline = nullptr;
|
args->_shapePipeline = nullptr;
|
||||||
args->_batch = nullptr;
|
args->_batch = nullptr;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
_boundsBuffer->setData(itemBounds.size() * sizeof(render::ItemBound), (const gpu::Byte*) itemBounds.data());
|
||||||
|
|
||||||
|
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||||
|
// Setup camera, projection and viewport for all items
|
||||||
|
batch.setViewportTransform(args->_viewport);
|
||||||
|
batch.setProjectionTransform(projMat);
|
||||||
|
batch.setViewTransform(viewMat);
|
||||||
|
|
||||||
|
// 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 auto framebufferSize = ressources->getSourceFrameSize();
|
||||||
|
|
||||||
|
auto stencilPipeline = _sharedParameters->_isFilled.test(_outlineIndex) ? _stencilMaskFillPipeline : _stencilMaskPipeline;
|
||||||
|
batch.setPipeline(stencilPipeline);
|
||||||
|
batch.setResourceBuffer(0, _boundsBuffer);
|
||||||
|
batch._glUniform2f(outlineWidthLoc, blurPixelWidth / framebufferSize.x, blurPixelWidth / framebufferSize.y);
|
||||||
|
static const int NUM_VERTICES_PER_CUBE = 36;
|
||||||
|
batch.draw(gpu::TRIANGLES, NUM_VERTICES_PER_CUBE * (gpu::uint32) itemBounds.size(), 0);
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
// Outline rect should be null as there are no outlined shapes
|
// Outline rect should be null as there are no outlined shapes
|
||||||
outputs = glm::ivec4(0, 0, 0, 0);
|
outputs = glm::ivec4(0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::ivec4 DrawOutlineMask::computeOutlineRect(const render::ShapeBounds& shapes,
|
|
||||||
const ViewFrustum& viewFrustum, glm::ivec2 frameSize) {
|
|
||||||
glm::vec4 minMaxBounds{
|
|
||||||
std::numeric_limits<float>::max(),
|
|
||||||
std::numeric_limits<float>::max(),
|
|
||||||
-std::numeric_limits<float>::max(),
|
|
||||||
-std::numeric_limits<float>::max(),
|
|
||||||
};
|
|
||||||
|
|
||||||
for (const auto& keyShapes : shapes) {
|
|
||||||
const auto& items = keyShapes.second;
|
|
||||||
|
|
||||||
for (const auto& item : items) {
|
|
||||||
const auto& aabb = item.bound;
|
|
||||||
glm::vec2 bottomLeft;
|
|
||||||
glm::vec2 topRight;
|
|
||||||
|
|
||||||
if (viewFrustum.getProjectedRect(aabb, bottomLeft, topRight)) {
|
|
||||||
minMaxBounds.x = std::min(minMaxBounds.x, bottomLeft.x);
|
|
||||||
minMaxBounds.y = std::min(minMaxBounds.y, bottomLeft.y);
|
|
||||||
minMaxBounds.z = std::max(minMaxBounds.z, topRight.x);
|
|
||||||
minMaxBounds.w = std::max(minMaxBounds.w, topRight.y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (minMaxBounds.x != std::numeric_limits<float>::max()) {
|
|
||||||
const glm::vec2 halfFrameSize{ frameSize.x*0.5f, frameSize.y*0.5f };
|
|
||||||
glm::ivec4 rect;
|
|
||||||
|
|
||||||
minMaxBounds += 1.0f;
|
|
||||||
rect.x = glm::clamp((int)floorf(minMaxBounds.x * halfFrameSize.x), 0, frameSize.x);
|
|
||||||
rect.y = glm::clamp((int)floorf(minMaxBounds.y * halfFrameSize.y), 0, frameSize.y);
|
|
||||||
rect.z = glm::clamp((int)ceilf(minMaxBounds.z * halfFrameSize.x), 0, frameSize.x);
|
|
||||||
rect.w = glm::clamp((int)ceilf(minMaxBounds.w * halfFrameSize.y), 0, frameSize.y);
|
|
||||||
|
|
||||||
rect.z -= rect.x;
|
|
||||||
rect.w -= rect.y;
|
|
||||||
return rect;
|
|
||||||
} else {
|
|
||||||
return glm::ivec4(0, 0, 0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::ivec4 DrawOutlineMask::expandRect(glm::ivec4 rect, int amount, glm::ivec2 frameSize) {
|
|
||||||
// Go bo back to min max values
|
|
||||||
rect.z += rect.x;
|
|
||||||
rect.w += rect.y;
|
|
||||||
|
|
||||||
rect.x = std::max(0, rect.x - amount);
|
|
||||||
rect.y = std::max(0, rect.y - amount);
|
|
||||||
rect.z = std::min(frameSize.x, rect.z + amount);
|
|
||||||
rect.w = std::min(frameSize.y, rect.w + amount);
|
|
||||||
|
|
||||||
// Back to width height
|
|
||||||
rect.z -= rect.x;
|
|
||||||
rect.w -= rect.y;
|
|
||||||
return rect;
|
|
||||||
}
|
|
||||||
|
|
||||||
gpu::PipelinePointer DrawOutline::_pipeline;
|
gpu::PipelinePointer DrawOutline::_pipeline;
|
||||||
gpu::PipelinePointer DrawOutline::_pipelineFilled;
|
gpu::PipelinePointer DrawOutline::_pipelineFilled;
|
||||||
|
|
||||||
|
@ -270,7 +251,7 @@ void DrawOutline::configure(const Config& config) {
|
||||||
_parameters._size.x = (_size * _framebufferSize.y) / _framebufferSize.x;
|
_parameters._size.x = (_size * _framebufferSize.y) / _framebufferSize.x;
|
||||||
_parameters._size.y = _size;
|
_parameters._size.y = _size;
|
||||||
_sharedParameters->_blurPixelWidths[_outlineIndex] = (int)ceilf(_size * _framebufferSize.y);
|
_sharedParameters->_blurPixelWidths[_outlineIndex] = (int)ceilf(_size * _framebufferSize.y);
|
||||||
_isFilled = (config.unoccludedFillOpacity > OPACITY_EPSILON || config.occludedFillOpacity > OPACITY_EPSILON);
|
_sharedParameters->_isFilled.set(_outlineIndex, (config.unoccludedFillOpacity > OPACITY_EPSILON || config.occludedFillOpacity > OPACITY_EPSILON));
|
||||||
_configuration.edit() = _parameters;
|
_configuration.edit() = _parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,9 +259,6 @@ void DrawOutline::run(const render::RenderContextPointer& renderContext, const I
|
||||||
auto outlineFrameBuffer = inputs.get1();
|
auto outlineFrameBuffer = inputs.get1();
|
||||||
auto outlineRect = inputs.get3();
|
auto outlineRect = inputs.get3();
|
||||||
|
|
||||||
// TODO : If scissor isn't possible in stereo, send the AABox in the shader
|
|
||||||
// and do a raycasting per pixel to determine if we need to do the outline
|
|
||||||
// This should improve performance.
|
|
||||||
if (outlineFrameBuffer && outlineRect.z>0 && outlineRect.w>0) {
|
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();
|
||||||
|
@ -302,9 +280,7 @@ void DrawOutline::run(const render::RenderContextPointer& renderContext, const I
|
||||||
}
|
}
|
||||||
|
|
||||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||||
#if !OUTLINE_USE_SCISSOR
|
|
||||||
batch.enableStereo(false);
|
batch.enableStereo(false);
|
||||||
#endif
|
|
||||||
batch.setFramebuffer(destinationFrameBuffer);
|
batch.setFramebuffer(destinationFrameBuffer);
|
||||||
|
|
||||||
batch.setViewportTransform(args->_viewport);
|
batch.setViewportTransform(args->_viewport);
|
||||||
|
@ -312,9 +288,6 @@ void DrawOutline::run(const render::RenderContextPointer& renderContext, const I
|
||||||
batch.resetViewTransform();
|
batch.resetViewTransform();
|
||||||
batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, args->_viewport));
|
batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, args->_viewport));
|
||||||
batch.setPipeline(pipeline);
|
batch.setPipeline(pipeline);
|
||||||
#if OUTLINE_USE_SCISSOR
|
|
||||||
batch.setStateScissorRect(outlineRect);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
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());
|
||||||
|
@ -331,7 +304,7 @@ const gpu::PipelinePointer& DrawOutline::getPipeline() {
|
||||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||||
state->setDepthTest(gpu::State::DepthTest(false, false));
|
state->setDepthTest(gpu::State::DepthTest(false, false));
|
||||||
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
|
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
|
||||||
state->setScissorEnable(OUTLINE_USE_SCISSOR);
|
state->setStencilTest(true, 0, gpu::State::StencilTest(OUTLINE_STENCIL_MASK, 0xFF, gpu::EQUAL));
|
||||||
|
|
||||||
auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS();
|
auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS();
|
||||||
auto ps = gpu::Shader::createPixel(std::string(Outline_frag));
|
auto ps = gpu::Shader::createPixel(std::string(Outline_frag));
|
||||||
|
@ -351,7 +324,7 @@ 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 _isFilled ? _pipelineFilled : _pipeline;
|
return _sharedParameters->_isFilled.test(_outlineIndex) ? _pipelineFilled : _pipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
DebugOutline::DebugOutline() {
|
DebugOutline::DebugOutline() {
|
||||||
|
@ -380,9 +353,7 @@ void DebugOutline::run(const render::RenderContextPointer& renderContext, const
|
||||||
|
|
||||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||||
batch.setViewportTransform(args->_viewport);
|
batch.setViewportTransform(args->_viewport);
|
||||||
#if OUTLINE_USE_SCISSOR
|
batch.setFramebuffer(outlineRessources->getColorFramebuffer());
|
||||||
batch.setStateScissorRect(outlineRect);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const auto geometryBuffer = DependencyManager::get<GeometryCache>();
|
const auto geometryBuffer = DependencyManager::get<GeometryCache>();
|
||||||
|
|
||||||
|
@ -416,8 +387,8 @@ void DebugOutline::initializePipelines() {
|
||||||
"Could not find source placeholder");
|
"Could not find source placeholder");
|
||||||
|
|
||||||
auto state = std::make_shared<gpu::State>();
|
auto state = std::make_shared<gpu::State>();
|
||||||
state->setDepthTest(gpu::State::DepthTest(false));
|
state->setDepthTest(gpu::State::DepthTest(false, false));
|
||||||
state->setScissorEnable(OUTLINE_USE_SCISSOR);
|
state->setStencilTest(true, 0, gpu::State::StencilTest(OUTLINE_STENCIL_MASK, 0xFF, gpu::EQUAL));
|
||||||
|
|
||||||
const auto vs = gpu::Shader::createVertex(VERTEX_SHADER);
|
const auto vs = gpu::Shader::createVertex(VERTEX_SHADER);
|
||||||
|
|
||||||
|
@ -473,7 +444,7 @@ void DrawOutlineTask::build(JobModel& task, const render::Varying& inputs, rende
|
||||||
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_EQUAL);
|
||||||
state->setColorWriteMask(false, false, false, false);
|
state->setColorWriteMask(false, false, false, false);
|
||||||
state->setScissorEnable(OUTLINE_USE_SCISSOR);
|
|
||||||
initMaskPipelines(*shapePlumber, state);
|
initMaskPipelines(*shapePlumber, state);
|
||||||
}
|
}
|
||||||
auto sharedParameters = std::make_shared<OutlineSharedParameters>();
|
auto sharedParameters = std::make_shared<OutlineSharedParameters>();
|
||||||
|
|
|
@ -33,6 +33,7 @@ protected:
|
||||||
|
|
||||||
gpu::FramebufferPointer _depthFrameBuffer;
|
gpu::FramebufferPointer _depthFrameBuffer;
|
||||||
gpu::FramebufferPointer _colorFrameBuffer;
|
gpu::FramebufferPointer _colorFrameBuffer;
|
||||||
|
gpu::TexturePointer _depthStencilTexture;
|
||||||
|
|
||||||
glm::ivec2 _frameSize;
|
glm::ivec2 _frameSize;
|
||||||
|
|
||||||
|
@ -48,6 +49,7 @@ public:
|
||||||
OutlineSharedParameters();
|
OutlineSharedParameters();
|
||||||
|
|
||||||
std::array<int, render::Scene::MAX_OUTLINE_COUNT> _blurPixelWidths;
|
std::array<int, render::Scene::MAX_OUTLINE_COUNT> _blurPixelWidths;
|
||||||
|
std::bitset<render::Scene::MAX_OUTLINE_COUNT> _isFilled;
|
||||||
};
|
};
|
||||||
|
|
||||||
using OutlineSharedParametersPointer = std::shared_ptr<OutlineSharedParameters>;
|
using OutlineSharedParametersPointer = std::shared_ptr<OutlineSharedParameters>;
|
||||||
|
@ -84,9 +86,10 @@ protected:
|
||||||
unsigned int _outlineIndex;
|
unsigned int _outlineIndex;
|
||||||
render::ShapePlumberPointer _shapePlumber;
|
render::ShapePlumberPointer _shapePlumber;
|
||||||
OutlineSharedParametersPointer _sharedParameters;
|
OutlineSharedParametersPointer _sharedParameters;
|
||||||
|
|
||||||
static glm::ivec4 computeOutlineRect(const render::ShapeBounds& shapes, const ViewFrustum& viewFrustum, glm::ivec2 frameSize);
|
static gpu::BufferPointer _boundsBuffer;
|
||||||
static glm::ivec4 expandRect(glm::ivec4 rect, int amount, glm::ivec2 frameSize);
|
static gpu::PipelinePointer _stencilMaskPipeline;
|
||||||
|
static gpu::PipelinePointer _stencilMaskFillPipeline;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DrawOutlineConfig : public render::Job::Config {
|
class DrawOutlineConfig : public render::Job::Config {
|
||||||
|
@ -158,7 +161,6 @@ private:
|
||||||
OutlineSharedParametersPointer _sharedParameters;
|
OutlineSharedParametersPointer _sharedParameters;
|
||||||
OutlineConfigurationBuffer _configuration;
|
OutlineConfigurationBuffer _configuration;
|
||||||
glm::ivec2 _framebufferSize{ 0,0 };
|
glm::ivec2 _framebufferSize{ 0,0 };
|
||||||
bool _isFilled{ false };
|
|
||||||
float _size;
|
float _size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
103
libraries/render-utils/src/Outline_aabox.slv
Normal file
103
libraries/render-utils/src/Outline_aabox.slv
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
<@include gpu/Config.slh@>
|
||||||
|
<$VERSION_HEADER$>
|
||||||
|
// Generated on <$_SCRIBE_DATE$>
|
||||||
|
//
|
||||||
|
// Draw and transform the fed vertex position with the standard MVP stack
|
||||||
|
// and offset the vertices by a certain amount in the vertex direction
|
||||||
|
//
|
||||||
|
// Created by Olivier Prat on 11/02/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
|
||||||
|
//
|
||||||
|
|
||||||
|
<@include gpu/Transform.slh@>
|
||||||
|
|
||||||
|
<$declareStandardTransform()$>
|
||||||
|
|
||||||
|
struct ItemBound {
|
||||||
|
vec4 id_boundPos;
|
||||||
|
vec4 boundDim_s;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(GPU_GL410)
|
||||||
|
uniform samplerBuffer ssbo0Buffer;
|
||||||
|
ItemBound getItemBound(int i) {
|
||||||
|
int offset = 2 * i;
|
||||||
|
ItemBound bound;
|
||||||
|
bound.id_boundPos = texelFetch(ssbo0Buffer, offset);
|
||||||
|
bound.boundDim_s = texelFetch(ssbo0Buffer, offset + 1);
|
||||||
|
return bound;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
layout(std140) buffer ssbo0Buffer {
|
||||||
|
ItemBound bounds[];
|
||||||
|
};
|
||||||
|
ItemBound getItemBound(int i) {
|
||||||
|
ItemBound bound = bounds[i];
|
||||||
|
return bound;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uniform vec2 outlineWidth;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
const vec3 UNIT_BOX_VERTICES[8] = vec3[8](
|
||||||
|
vec3(0.0, 1.0, 0.0),
|
||||||
|
vec3(1.0, 1.0, 0.0),
|
||||||
|
vec3(1.0, 0.0, 0.0),
|
||||||
|
vec3(0.0, 0.0, 0.0),
|
||||||
|
vec3(0.0, 1.0, 1.0),
|
||||||
|
vec3(1.0, 1.0, 1.0),
|
||||||
|
vec3(1.0, 0.0, 1.0),
|
||||||
|
vec3(0.0, 0.0, 1.0)
|
||||||
|
);
|
||||||
|
const vec3 UNIT_BOX_NORMALS[8] = vec3[8](
|
||||||
|
vec3(-1.0, 1.0, -1.0),
|
||||||
|
vec3(1.0, 1.0, -1.0),
|
||||||
|
vec3(1.0, -1.0, -1.0),
|
||||||
|
vec3(-1.0, -1.0, -1.0),
|
||||||
|
vec3(-1.0, 1.0, 1.0),
|
||||||
|
vec3(1.0, 1.0, 1.0),
|
||||||
|
vec3(1.0, -1.0, 1.0),
|
||||||
|
vec3(-1.0, -1.0, 1.0)
|
||||||
|
);
|
||||||
|
const int NUM_VERTICES_PER_CUBE = 36;
|
||||||
|
const int UNIT_BOX_TRIANGLE_INDICES[NUM_VERTICES_PER_CUBE] = int[NUM_VERTICES_PER_CUBE](
|
||||||
|
0, 1, 2,
|
||||||
|
0, 2, 3,
|
||||||
|
3, 2, 6,
|
||||||
|
3, 6, 7,
|
||||||
|
7, 6, 5,
|
||||||
|
7, 5, 4,
|
||||||
|
4, 5, 1,
|
||||||
|
4, 1, 0,
|
||||||
|
1, 5, 6,
|
||||||
|
1, 6, 2,
|
||||||
|
4, 0, 3,
|
||||||
|
4, 3, 7
|
||||||
|
);
|
||||||
|
|
||||||
|
int boundID = gl_VertexID / NUM_VERTICES_PER_CUBE;
|
||||||
|
int vertexID = gl_VertexID - boundID * NUM_VERTICES_PER_CUBE;
|
||||||
|
int triangleIndex = UNIT_BOX_TRIANGLE_INDICES[vertexID];
|
||||||
|
vec3 cubeVec = UNIT_BOX_VERTICES[triangleIndex];
|
||||||
|
|
||||||
|
ItemBound bound = getItemBound(boundID);
|
||||||
|
vec3 boundPos = bound.id_boundPos.yzw;
|
||||||
|
vec3 boundDim = bound.boundDim_s.xyz;
|
||||||
|
|
||||||
|
vec4 pos = vec4(boundPos + boundDim * cubeVec.xyz, 1.0);
|
||||||
|
|
||||||
|
// standard transform
|
||||||
|
TransformCamera cam = getTransformCamera();
|
||||||
|
TransformObject obj = getTransformObject();
|
||||||
|
<$transformModelToClipPos(cam, obj, pos, gl_Position)$>
|
||||||
|
|
||||||
|
// Offset the vertex to take into account the outline width
|
||||||
|
pos.xyz += UNIT_BOX_NORMALS[triangleIndex];
|
||||||
|
vec4 offsetPosition;
|
||||||
|
<$transformModelToClipPos(cam, obj, pos, offsetPosition)$>
|
||||||
|
gl_Position.xy += normalize(offsetPosition.xy-gl_Position.xy) * outlineWidth * gl_Position.w;
|
||||||
|
}
|
|
@ -1,20 +1,20 @@
|
||||||
// glsl / C++ compatible source as interface for Outline
|
// glsl / C++ compatible source as interface for Outline
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
# define VEC2 glm::vec2
|
# define TVEC2 glm::vec2
|
||||||
# define VEC3 glm::vec3
|
# define TVEC3 glm::vec3
|
||||||
# define VEC4 glm::vec4
|
# define TVEC4 glm::vec4
|
||||||
#else
|
#else
|
||||||
# define VEC2 vec2
|
# define TVEC2 vec2
|
||||||
# define VEC3 vec3
|
# define TVEC3 vec3
|
||||||
# define VEC4 vec4
|
# define TVEC4 vec4
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct OutlineParameters
|
struct OutlineParameters
|
||||||
{
|
{
|
||||||
VEC3 _color;
|
TVEC3 _color;
|
||||||
float _intensity;
|
float _intensity;
|
||||||
|
|
||||||
VEC2 _size;
|
TVEC2 _size;
|
||||||
float _unoccludedFillOpacity;
|
float _unoccludedFillOpacity;
|
||||||
float _occludedFillOpacity;
|
float _occludedFillOpacity;
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include "TextureCache.h"
|
#include "TextureCache.h"
|
||||||
#include "ZoneRenderer.h"
|
#include "ZoneRenderer.h"
|
||||||
#include "FadeEffect.h"
|
#include "FadeEffect.h"
|
||||||
|
#include "RenderUtilsLogging.h"
|
||||||
|
|
||||||
#include "AmbientOcclusionEffect.h"
|
#include "AmbientOcclusionEffect.h"
|
||||||
#include "AntialiasingEffect.h"
|
#include "AntialiasingEffect.h"
|
||||||
|
@ -471,6 +472,7 @@ void Blit::run(const RenderContextPointer& renderContext, const gpu::Framebuffer
|
||||||
auto blitFbo = renderArgs->_blitFramebuffer;
|
auto blitFbo = renderArgs->_blitFramebuffer;
|
||||||
|
|
||||||
if (!blitFbo) {
|
if (!blitFbo) {
|
||||||
|
qCWarning(renderutils) << "Blit::run - no blit frame buffer.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -74,9 +74,13 @@ void render::depthSortItems(const RenderContextPointer& renderContext, bool fron
|
||||||
std::sort(itemBoundSorts.begin(), itemBoundSorts.end(), backToFrontSort);
|
std::sort(itemBoundSorts.begin(), itemBoundSorts.end(), backToFrontSort);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally once sorted result to a list of itemID
|
// Finally once sorted result to a list of itemID and keep uniques
|
||||||
|
render::ItemID previousID = Item::INVALID_ITEM_ID;
|
||||||
for (auto& item : itemBoundSorts) {
|
for (auto& item : itemBoundSorts) {
|
||||||
outItems.emplace_back(ItemBound(item._id, item._bounds));
|
if (item._id != previousID) {
|
||||||
|
outItems.emplace_back(ItemBound(item._id, item._bounds));
|
||||||
|
previousID = item._id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,22 +8,34 @@
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
import QtQuick 2.5
|
import QtQuick 2.7
|
||||||
import QtQuick.Controls 1.4
|
import QtQuick.Controls 1.4
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
import "outlinePage"
|
import "outlinePage"
|
||||||
|
import "qrc:///qml/styles-uit"
|
||||||
|
import "qrc:///qml/controls-uit" as HifiControls
|
||||||
|
|
||||||
Item {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
|
HifiConstants { id: hifi;}
|
||||||
|
color: hifi.colors.baseGray;
|
||||||
|
anchors.margins: hifi.dimensions.contentMargin.x
|
||||||
|
|
||||||
property var debugConfig: Render.getConfig("RenderMainView.OutlineDebug")
|
property var debugConfig: Render.getConfig("RenderMainView.OutlineDebug")
|
||||||
signal sendToScript(var message);
|
signal sendToScript(var message);
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
spacing: 8
|
spacing: 5
|
||||||
anchors.fill: parent
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.margins: hifi.dimensions.contentMargin.x
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
spacing: 8
|
spacing: 10
|
||||||
CheckBox {
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
HifiControls.CheckBox {
|
||||||
id: debug
|
id: debug
|
||||||
text: "View Mask"
|
text: "View Mask"
|
||||||
checked: root.debugConfig["viewMask"]
|
checked: root.debugConfig["viewMask"]
|
||||||
|
@ -31,14 +43,14 @@ Item {
|
||||||
root.debugConfig["viewMask"] = checked;
|
root.debugConfig["viewMask"] = checked;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CheckBox {
|
HifiControls.CheckBox {
|
||||||
text: "Hover select"
|
text: "Hover select"
|
||||||
checked: false
|
checked: false
|
||||||
onCheckedChanged: {
|
onCheckedChanged: {
|
||||||
sendToScript("pick "+checked.toString())
|
sendToScript("pick "+checked.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CheckBox {
|
HifiControls.CheckBox {
|
||||||
text: "Add to selection"
|
text: "Add to selection"
|
||||||
checked: false
|
checked: false
|
||||||
onCheckedChanged: {
|
onCheckedChanged: {
|
||||||
|
@ -56,28 +68,13 @@ Item {
|
||||||
sendToScript("outline "+currentIndex)
|
sendToScript("outline "+currentIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
Tab {
|
Repeater {
|
||||||
title: "Outl.0"
|
model: [ 0, 1, 2, 3 ]
|
||||||
OutlinePage {
|
Tab {
|
||||||
outlineIndex: 0
|
title: "Outl."+modelData
|
||||||
}
|
OutlinePage {
|
||||||
}
|
outlineIndex: modelData
|
||||||
Tab {
|
}
|
||||||
title: "Outl.1"
|
|
||||||
OutlinePage {
|
|
||||||
outlineIndex: 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Tab {
|
|
||||||
title: "Outl.2"
|
|
||||||
OutlinePage {
|
|
||||||
outlineIndex: 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Tab {
|
|
||||||
title: "Outl.3"
|
|
||||||
OutlinePage {
|
|
||||||
outlineIndex: 3
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,19 +8,28 @@
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
import QtQuick 2.5
|
import QtQuick 2.7
|
||||||
import QtQuick.Controls 1.4
|
import QtQuick.Controls 1.4
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
import "../configSlider"
|
import "../configSlider"
|
||||||
|
import "qrc:///qml/styles-uit"
|
||||||
|
import "qrc:///qml/controls-uit" as HifiControls
|
||||||
|
|
||||||
Item {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
property var outlineIndex: 0
|
property var outlineIndex: 0
|
||||||
property var drawConfig: Render.getConfig("RenderMainView.OutlineEffect"+outlineIndex)
|
property var drawConfig: Render.getConfig("RenderMainView.OutlineEffect"+outlineIndex)
|
||||||
|
|
||||||
Column {
|
HifiConstants { id: hifi;}
|
||||||
spacing: 8
|
anchors.margins: hifi.dimensions.contentMargin.x
|
||||||
|
|
||||||
CheckBox {
|
Column {
|
||||||
|
spacing: 5
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.margins: hifi.dimensions.contentMargin.x
|
||||||
|
|
||||||
|
HifiControls.CheckBox {
|
||||||
id: glow
|
id: glow
|
||||||
text: "Glow"
|
text: "Glow"
|
||||||
checked: root.drawConfig["glow"]
|
checked: root.drawConfig["glow"]
|
||||||
|
@ -28,84 +37,78 @@ Item {
|
||||||
root.drawConfig["glow"] = checked;
|
root.drawConfig["glow"] = checked;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ConfigSlider {
|
Repeater {
|
||||||
label: "Width"
|
model: ["Width:width:5.0:0.0",
|
||||||
integral: false
|
"Intensity:intensity:1.0:0.0"
|
||||||
config: root.drawConfig
|
]
|
||||||
property: "width"
|
ConfigSlider {
|
||||||
max: 5.0
|
label: qsTr(modelData.split(":")[0])
|
||||||
min: 0.0
|
integral: false
|
||||||
width: 280
|
config: root.drawConfig
|
||||||
}
|
property: modelData.split(":")[1]
|
||||||
ConfigSlider {
|
max: modelData.split(":")[2]
|
||||||
label: "Intensity"
|
min: modelData.split(":")[3]
|
||||||
integral: false
|
|
||||||
config: root.drawConfig
|
anchors.left: parent.left
|
||||||
property: "intensity"
|
anchors.right: parent.right
|
||||||
max: 1.0
|
}
|
||||||
min: 0.0
|
}
|
||||||
width: 280
|
|
||||||
}
|
|
||||||
|
|
||||||
GroupBox {
|
GroupBox {
|
||||||
title: "Color"
|
title: "Color"
|
||||||
width: 280
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
Column {
|
Column {
|
||||||
spacing: 8
|
spacing: 10
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.margins: hifi.dimensions.contentMargin.x
|
||||||
|
|
||||||
ConfigSlider {
|
Repeater {
|
||||||
label: "Red"
|
model: ["Red:colorR:1.0:0.0",
|
||||||
integral: false
|
"Green:colorG:1.0:0.0",
|
||||||
config: root.drawConfig
|
"Blue:colorB:1.0:0.0"
|
||||||
property: "colorR"
|
]
|
||||||
max: 1.0
|
ConfigSlider {
|
||||||
min: 0.0
|
label: qsTr(modelData.split(":")[0])
|
||||||
width: 270
|
integral: false
|
||||||
}
|
config: root.drawConfig
|
||||||
ConfigSlider {
|
property: modelData.split(":")[1]
|
||||||
label: "Green"
|
max: modelData.split(":")[2]
|
||||||
integral: false
|
min: modelData.split(":")[3]
|
||||||
config: root.drawConfig
|
|
||||||
property: "colorG"
|
anchors.left: parent.left
|
||||||
max: 1.0
|
anchors.right: parent.right
|
||||||
min: 0.0
|
}
|
||||||
width: 270
|
|
||||||
}
|
|
||||||
ConfigSlider {
|
|
||||||
label: "Blue"
|
|
||||||
integral: false
|
|
||||||
config: root.drawConfig
|
|
||||||
property: "colorB"
|
|
||||||
max: 1.0
|
|
||||||
min: 0.0
|
|
||||||
width: 270
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GroupBox {
|
GroupBox {
|
||||||
title: "Fill Opacity"
|
title: "Fill Opacity"
|
||||||
width: 280
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
Column {
|
Column {
|
||||||
spacing: 8
|
spacing: 10
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.margins: hifi.dimensions.contentMargin.x
|
||||||
|
|
||||||
ConfigSlider {
|
Repeater {
|
||||||
label: "Unoccluded"
|
model: ["Unoccluded:unoccludedFillOpacity:1.0:0.0",
|
||||||
integral: false
|
"Occluded:occludedFillOpacity:1.0:0.0"
|
||||||
config: root.drawConfig
|
]
|
||||||
property: "unoccludedFillOpacity"
|
ConfigSlider {
|
||||||
max: 1.0
|
label: qsTr(modelData.split(":")[0])
|
||||||
min: 0.0
|
integral: false
|
||||||
width: 270
|
config: root.drawConfig
|
||||||
}
|
property: modelData.split(":")[1]
|
||||||
ConfigSlider {
|
max: modelData.split(":")[2]
|
||||||
label: "Occluded"
|
min: modelData.split(":")[3]
|
||||||
integral: false
|
|
||||||
config: root.drawConfig
|
anchors.left: parent.left
|
||||||
property: "occludedFillOpacity"
|
anchors.right: parent.right
|
||||||
max: 1.0
|
}
|
||||||
min: 0.0
|
|
||||||
width: 270
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue