diff --git a/libraries/render-utils/src/OutlineEffect.cpp b/libraries/render-utils/src/OutlineEffect.cpp index ad4c59b35a..a42cbfe358 100644 --- a/libraries/render-utils/src/OutlineEffect.cpp +++ b/libraries/render-utils/src/OutlineEffect.cpp @@ -11,7 +11,6 @@ #include "OutlineEffect.h" #include "GeometryCache.h" -#include "RenderUtilsLogging.h" #include "CubeProjectedPolygon.h" @@ -28,10 +27,11 @@ #include "debug_deferred_buffer_frag.h" #include "Outline_frag.h" #include "Outline_filled_frag.h" +#include "Outline_aabox_vert.h" using namespace render; -#define OUTLINE_USE_SCISSOR false +#define OUTLINE_STENCIL_MASK 1 OutlineRessources::OutlineRessources() { } @@ -56,15 +56,16 @@ void OutlineRessources::update(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->setDepthStencilBuffer(_depthStencilTexture, _depthStencilTexture->getTexelFormat()); } void OutlineRessources::allocateDepthBuffer(const gpu::FramebufferPointer& primaryFrameBuffer) { - auto depthFormat = gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH); - auto depthTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(depthFormat, _frameSize.x, _frameSize.y)); + auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); + _depthStencilTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(depthFormat, _frameSize.x, _frameSize.y)); _depthFrameBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("outlineDepth")); - _depthFrameBuffer->setDepthStencilBuffer(depthTexture, depthFormat); + _depthFrameBuffer->setDepthStencilBuffer(_depthStencilTexture, depthFormat); } gpu::FramebufferPointer OutlineRessources::getDepthFramebuffer() { @@ -73,10 +74,10 @@ gpu::FramebufferPointer OutlineRessources::getDepthFramebuffer() { } gpu::TexturePointer OutlineRessources::getDepthTexture() { - return getDepthFramebuffer()->getDepthStencilBuffer(); + return _depthStencilTexture; } -gpu::FramebufferPointer OutlineRessources::getColorFramebuffer() { +gpu::FramebufferPointer OutlineRessources::getColorFramebuffer() { assert(_colorFrameBuffer); return _colorFrameBuffer; } @@ -96,6 +97,10 @@ void PrepareDrawOutline::run(const render::RenderContextPointer& renderContext, outputs = _ressources; } +gpu::PipelinePointer DrawOutlineMask::_stencilMaskPipeline; +gpu::PipelinePointer DrawOutlineMask::_stencilMaskFillPipeline; +gpu::BufferPointer DrawOutlineMask::_boundsBuffer; + DrawOutlineMask::DrawOutlineMask(unsigned int outlineIndex, render::ShapePlumberPointer shapePlumber, OutlineSharedParametersPointer parameters) : _outlineIndex{ outlineIndex }, @@ -108,26 +113,42 @@ void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, con assert(renderContext->args->hasViewFrustum()); 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(sizeof(render::ItemBound)); + } + if (!inShapes.empty()) { auto ressources = inputs.get1(); RenderArgs* args = renderContext->args; 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 outputs = args->_viewport; -#endif // Clear the framebuffer without stereo // 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) { batch.enableStereo(false); 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) { args->_batch = &batch; auto maskPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder); 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 batch.setViewportTransform(args->_viewport); batch.setProjectionTransform(projMat); @@ -164,7 +182,8 @@ void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, con // Iterate through all inShapes and render the unskinned args->_shapePipeline = maskPipeline; 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()) { skinnedShapeKeys.push_back(items.first); } else { @@ -182,72 +201,34 @@ void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, con args->_shapePipeline = 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 { // Outline rect should be null as there are no outlined shapes 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::max(), - std::numeric_limits::max(), - -std::numeric_limits::max(), - -std::numeric_limits::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::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::_pipelineFilled; @@ -270,7 +251,7 @@ void DrawOutline::configure(const Config& config) { _parameters._size.x = (_size * _framebufferSize.y) / _framebufferSize.x; _parameters._size.y = _size; _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; } @@ -278,9 +259,6 @@ void DrawOutline::run(const render::RenderContextPointer& renderContext, const I auto outlineFrameBuffer = inputs.get1(); 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) { auto sceneDepthBuffer = inputs.get2(); 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) { -#if !OUTLINE_USE_SCISSOR batch.enableStereo(false); -#endif batch.setFramebuffer(destinationFrameBuffer); batch.setViewportTransform(args->_viewport); @@ -312,9 +288,6 @@ void DrawOutline::run(const render::RenderContextPointer& renderContext, const I batch.resetViewTransform(); batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, args->_viewport)); batch.setPipeline(pipeline); -#if OUTLINE_USE_SCISSOR - batch.setStateScissorRect(outlineRect); -#endif batch.setUniformBuffer(OUTLINE_PARAMS_SLOT, _configuration); batch.setUniformBuffer(FRAME_TRANSFORM_SLOT, frameTransform->getFrameTransformBuffer()); @@ -331,7 +304,7 @@ const gpu::PipelinePointer& DrawOutline::getPipeline() { gpu::StatePointer state = gpu::StatePointer(new gpu::State()); 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->setScissorEnable(OUTLINE_USE_SCISSOR); + state->setStencilTest(true, 0, gpu::State::StencilTest(OUTLINE_STENCIL_MASK, 0xFF, gpu::EQUAL)); auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); auto ps = gpu::Shader::createPixel(std::string(Outline_frag)); @@ -351,7 +324,7 @@ const gpu::PipelinePointer& DrawOutline::getPipeline() { gpu::Shader::makeProgram(*program, slotBindings); _pipelineFilled = gpu::Pipeline::create(program, state); } - return _isFilled ? _pipelineFilled : _pipeline; + return _sharedParameters->_isFilled.test(_outlineIndex) ? _pipelineFilled : _pipeline; } DebugOutline::DebugOutline() { @@ -380,9 +353,7 @@ void DebugOutline::run(const render::RenderContextPointer& renderContext, const gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { batch.setViewportTransform(args->_viewport); -#if OUTLINE_USE_SCISSOR - batch.setStateScissorRect(outlineRect); -#endif + batch.setFramebuffer(outlineRessources->getColorFramebuffer()); const auto geometryBuffer = DependencyManager::get(); @@ -416,8 +387,8 @@ void DebugOutline::initializePipelines() { "Could not find source placeholder"); auto state = std::make_shared(); - state->setDepthTest(gpu::State::DepthTest(false)); - state->setScissorEnable(OUTLINE_USE_SCISSOR); + state->setDepthTest(gpu::State::DepthTest(false, false)); + state->setStencilTest(true, 0, gpu::State::StencilTest(OUTLINE_STENCIL_MASK, 0xFF, gpu::EQUAL)); 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(); state->setDepthTest(true, true, gpu::LESS_EQUAL); state->setColorWriteMask(false, false, false, false); - state->setScissorEnable(OUTLINE_USE_SCISSOR); + initMaskPipelines(*shapePlumber, state); } auto sharedParameters = std::make_shared(); diff --git a/libraries/render-utils/src/OutlineEffect.h b/libraries/render-utils/src/OutlineEffect.h index ee5e503de9..a2bfc88c81 100644 --- a/libraries/render-utils/src/OutlineEffect.h +++ b/libraries/render-utils/src/OutlineEffect.h @@ -33,6 +33,7 @@ protected: gpu::FramebufferPointer _depthFrameBuffer; gpu::FramebufferPointer _colorFrameBuffer; + gpu::TexturePointer _depthStencilTexture; glm::ivec2 _frameSize; @@ -48,6 +49,7 @@ public: OutlineSharedParameters(); std::array _blurPixelWidths; + std::bitset _isFilled; }; using OutlineSharedParametersPointer = std::shared_ptr; @@ -84,9 +86,10 @@ protected: unsigned int _outlineIndex; render::ShapePlumberPointer _shapePlumber; OutlineSharedParametersPointer _sharedParameters; - - static glm::ivec4 computeOutlineRect(const render::ShapeBounds& shapes, const ViewFrustum& viewFrustum, glm::ivec2 frameSize); - static glm::ivec4 expandRect(glm::ivec4 rect, int amount, glm::ivec2 frameSize); + + static gpu::BufferPointer _boundsBuffer; + static gpu::PipelinePointer _stencilMaskPipeline; + static gpu::PipelinePointer _stencilMaskFillPipeline; }; class DrawOutlineConfig : public render::Job::Config { @@ -158,7 +161,6 @@ private: OutlineSharedParametersPointer _sharedParameters; OutlineConfigurationBuffer _configuration; glm::ivec2 _framebufferSize{ 0,0 }; - bool _isFilled{ false }; float _size; }; diff --git a/libraries/render-utils/src/Outline_aabox.slv b/libraries/render-utils/src/Outline_aabox.slv new file mode 100644 index 0000000000..1a46ccd9c7 --- /dev/null +++ b/libraries/render-utils/src/Outline_aabox.slv @@ -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; +} diff --git a/libraries/render-utils/src/Outline_shared.slh b/libraries/render-utils/src/Outline_shared.slh index 2ebece8903..3fd089e2fc 100644 --- a/libraries/render-utils/src/Outline_shared.slh +++ b/libraries/render-utils/src/Outline_shared.slh @@ -1,20 +1,20 @@ // glsl / C++ compatible source as interface for Outline #ifdef __cplusplus -# define VEC2 glm::vec2 -# define VEC3 glm::vec3 -# define VEC4 glm::vec4 +# define TVEC2 glm::vec2 +# define TVEC3 glm::vec3 +# define TVEC4 glm::vec4 #else -# define VEC2 vec2 -# define VEC3 vec3 -# define VEC4 vec4 +# define TVEC2 vec2 +# define TVEC3 vec3 +# define TVEC4 vec4 #endif struct OutlineParameters { - VEC3 _color; + TVEC3 _color; float _intensity; - VEC2 _size; + TVEC2 _size; float _unoccludedFillOpacity; float _occludedFillOpacity; diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 63936b0809..16db1281f5 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -35,6 +35,7 @@ #include "TextureCache.h" #include "ZoneRenderer.h" #include "FadeEffect.h" +#include "RenderUtilsLogging.h" #include "AmbientOcclusionEffect.h" #include "AntialiasingEffect.h" @@ -471,6 +472,7 @@ void Blit::run(const RenderContextPointer& renderContext, const gpu::Framebuffer auto blitFbo = renderArgs->_blitFramebuffer; if (!blitFbo) { + qCWarning(renderutils) << "Blit::run - no blit frame buffer."; return; } diff --git a/libraries/render/src/render/SortTask.cpp b/libraries/render/src/render/SortTask.cpp index 5b7ead4b6a..00146e393d 100644 --- a/libraries/render/src/render/SortTask.cpp +++ b/libraries/render/src/render/SortTask.cpp @@ -74,9 +74,13 @@ void render::depthSortItems(const RenderContextPointer& renderContext, bool fron 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) { - outItems.emplace_back(ItemBound(item._id, item._bounds)); + if (item._id != previousID) { + outItems.emplace_back(ItemBound(item._id, item._bounds)); + previousID = item._id; + } } } diff --git a/scripts/developer/utilities/render/outline.qml b/scripts/developer/utilities/render/outline.qml index 39acd854ac..8269ea830e 100644 --- a/scripts/developer/utilities/render/outline.qml +++ b/scripts/developer/utilities/render/outline.qml @@ -8,22 +8,34 @@ // Distributed under the Apache License, Version 2.0. // 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.Layouts 1.3 import "outlinePage" +import "qrc:///qml/styles-uit" +import "qrc:///qml/controls-uit" as HifiControls -Item { +Rectangle { id: root + HifiConstants { id: hifi;} + color: hifi.colors.baseGray; + anchors.margins: hifi.dimensions.contentMargin.x + property var debugConfig: Render.getConfig("RenderMainView.OutlineDebug") signal sendToScript(var message); Column { - spacing: 8 - anchors.fill: parent + spacing: 5 + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: hifi.dimensions.contentMargin.x Row { - spacing: 8 - CheckBox { + spacing: 10 + anchors.left: parent.left + anchors.right: parent.right + + HifiControls.CheckBox { id: debug text: "View Mask" checked: root.debugConfig["viewMask"] @@ -31,14 +43,14 @@ Item { root.debugConfig["viewMask"] = checked; } } - CheckBox { + HifiControls.CheckBox { text: "Hover select" checked: false onCheckedChanged: { sendToScript("pick "+checked.toString()) } } - CheckBox { + HifiControls.CheckBox { text: "Add to selection" checked: false onCheckedChanged: { @@ -56,28 +68,13 @@ Item { sendToScript("outline "+currentIndex) } - Tab { - title: "Outl.0" - OutlinePage { - outlineIndex: 0 - } - } - Tab { - title: "Outl.1" - OutlinePage { - outlineIndex: 1 - } - } - Tab { - title: "Outl.2" - OutlinePage { - outlineIndex: 2 - } - } - Tab { - title: "Outl.3" - OutlinePage { - outlineIndex: 3 + Repeater { + model: [ 0, 1, 2, 3 ] + Tab { + title: "Outl."+modelData + OutlinePage { + outlineIndex: modelData + } } } } diff --git a/scripts/developer/utilities/render/outlinePage/OutlinePage.qml b/scripts/developer/utilities/render/outlinePage/OutlinePage.qml index a78bf02d3e..ff1d7fa23b 100644 --- a/scripts/developer/utilities/render/outlinePage/OutlinePage.qml +++ b/scripts/developer/utilities/render/outlinePage/OutlinePage.qml @@ -8,19 +8,28 @@ // Distributed under the Apache License, Version 2.0. // 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.Layouts 1.3 import "../configSlider" +import "qrc:///qml/styles-uit" +import "qrc:///qml/controls-uit" as HifiControls -Item { +Rectangle { id: root property var outlineIndex: 0 property var drawConfig: Render.getConfig("RenderMainView.OutlineEffect"+outlineIndex) - Column { - spacing: 8 + HifiConstants { id: hifi;} + 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 text: "Glow" checked: root.drawConfig["glow"] @@ -28,84 +37,78 @@ Item { root.drawConfig["glow"] = checked; } } - ConfigSlider { - label: "Width" - integral: false - config: root.drawConfig - property: "width" - max: 5.0 - min: 0.0 - width: 280 - } - ConfigSlider { - label: "Intensity" - integral: false - config: root.drawConfig - property: "intensity" - max: 1.0 - min: 0.0 - width: 280 - } + Repeater { + model: ["Width:width:5.0:0.0", + "Intensity:intensity:1.0:0.0" + ] + ConfigSlider { + label: qsTr(modelData.split(":")[0]) + integral: false + config: root.drawConfig + property: modelData.split(":")[1] + max: modelData.split(":")[2] + min: modelData.split(":")[3] + + anchors.left: parent.left + anchors.right: parent.right + } + } GroupBox { title: "Color" - width: 280 + anchors.left: parent.left + anchors.right: parent.right Column { - spacing: 8 + spacing: 10 + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: hifi.dimensions.contentMargin.x - ConfigSlider { - label: "Red" - integral: false - config: root.drawConfig - property: "colorR" - max: 1.0 - min: 0.0 - width: 270 - } - ConfigSlider { - label: "Green" - integral: false - config: root.drawConfig - property: "colorG" - max: 1.0 - min: 0.0 - width: 270 - } - ConfigSlider { - label: "Blue" - integral: false - config: root.drawConfig - property: "colorB" - max: 1.0 - min: 0.0 - width: 270 + Repeater { + model: ["Red:colorR:1.0:0.0", + "Green:colorG:1.0:0.0", + "Blue:colorB:1.0:0.0" + ] + ConfigSlider { + label: qsTr(modelData.split(":")[0]) + integral: false + config: root.drawConfig + property: modelData.split(":")[1] + max: modelData.split(":")[2] + min: modelData.split(":")[3] + + anchors.left: parent.left + anchors.right: parent.right + } } } } GroupBox { title: "Fill Opacity" - width: 280 + anchors.left: parent.left + anchors.right: parent.right Column { - spacing: 8 + spacing: 10 + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: hifi.dimensions.contentMargin.x - ConfigSlider { - label: "Unoccluded" - integral: false - config: root.drawConfig - property: "unoccludedFillOpacity" - max: 1.0 - min: 0.0 - width: 270 - } - ConfigSlider { - label: "Occluded" - integral: false - config: root.drawConfig - property: "occludedFillOpacity" - max: 1.0 - min: 0.0 - width: 270 + Repeater { + model: ["Unoccluded:unoccludedFillOpacity:1.0:0.0", + "Occluded:occludedFillOpacity:1.0:0.0" + ] + ConfigSlider { + label: qsTr(modelData.split(":")[0]) + integral: false + config: root.drawConfig + property: modelData.split(":")[1] + max: modelData.split(":")[2] + min: modelData.split(":")[3] + + anchors.left: parent.left + anchors.right: parent.right + } } } }