From e5f3805d0e3558ab0ecbb4d5ee453fd18d7c9c80 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 5 Feb 2016 16:49:43 -0800 Subject: [PATCH] Fixing the item insert in cell criteria for subcell and adding debgging tool --- .../utilities/tools/debugRenderCulling.js | 81 +++++++ .../render-utils/src/RenderDeferredTask.cpp | 3 +- libraries/render/src/render/CullTask.cpp | 6 +- .../render/src/render/DrawSceneOctree.cpp | 203 ++++++++++++------ libraries/render/src/render/DrawSceneOctree.h | 67 +++++- libraries/render/src/render/Octree.cpp | 6 +- libraries/render/src/render/Octree.h | 5 + 7 files changed, 299 insertions(+), 72 deletions(-) create mode 100644 examples/utilities/tools/debugRenderCulling.js diff --git a/examples/utilities/tools/debugRenderCulling.js b/examples/utilities/tools/debugRenderCulling.js new file mode 100644 index 0000000000..4579f434d0 --- /dev/null +++ b/examples/utilities/tools/debugRenderCulling.js @@ -0,0 +1,81 @@ +// +// debugRenderOctree.js +// examples/utilities/tools +// +// Sam Gateau +// Copyright 2016 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 +// + +Script.include("cookies.js"); + +var panel = new Panel(10, 300); +var drawOctree = Render.RenderDeferredTask.DrawSceneOctree; +Render.RenderDeferredTask.DrawSceneOctree.enabled = true; +Render.RenderDeferredTask.DrawItemSelection.enabled = true; + +panel.newCheckbox("Show Octree Cells", + function(value) { Render.RenderDeferredTask.DrawSceneOctree.showVisibleCells = value; }, + function() { return (Render.RenderDeferredTask.DrawSceneOctree.showVisibleCells); }, + function(value) { return (value); } +); +panel.newCheckbox("Show Empty Cells", + function(value) { Render.RenderDeferredTask.DrawSceneOctree.showEmptyCells = value; }, + function() { return (Render.RenderDeferredTask.DrawSceneOctree.showEmptyCells); }, + function(value) { return (value); } +); +panel.newCheckbox("Freeze Frustum", + function(value) { Render.RenderDeferredTask.DrawSceneOctree.freezeFrustum = value; }, + function() { return (Render.RenderDeferredTask.DrawSceneOctree.freezeFrustum); }, + function(value) { return (value); } +); +panel.newCheckbox("Show Inside Items", + function(value) { Render.RenderDeferredTask.DrawItemSelection.showInsideItems = value; }, + function() { return (Render.RenderDeferredTask.DrawItemSelection.showInsideItems); }, + function(value) { return (value); } +); + +panel.newCheckbox("Show Inside Subcell Items", + function(value) { Render.RenderDeferredTask.DrawItemSelection.showInsideSubcellItems = value; }, + function() { return (Render.RenderDeferredTask.DrawItemSelection.showInsideSubcellItems); }, + function(value) { return (value); } +); + +panel.newCheckbox("Show Partial Items", + function(value) { Render.RenderDeferredTask.DrawItemSelection.showPartialItems = value; }, + function() { return (Render.RenderDeferredTask.DrawItemSelection.showPartialItems); }, + function(value) { return (value); } +); + +panel.newCheckbox("Show Partial Subcell Items", + function(value) { Render.RenderDeferredTask.DrawItemSelection.showPartialSubcellItems = value; }, + function() { return (Render.RenderDeferredTask.DrawItemSelection.showPartialSubcellItems); }, + function(value) { return (value); } +); + +function mouseMoveEvent(event) { + panel.mouseMoveEvent(event); +} + +function mousePressEvent(event) { + panel.mousePressEvent(event); +} + +function mouseReleaseEvent(event) { + panel.mouseReleaseEvent(event); +} + +Controller.mouseMoveEvent.connect(mouseMoveEvent); +Controller.mousePressEvent.connect(mousePressEvent); +Controller.mouseReleaseEvent.connect(mouseReleaseEvent); + +function scriptEnding() { + panel.destroy(); + Render.RenderDeferredTask.DrawSceneOctree.enabled = false; + Render.RenderDeferredTask.DrawItemSelection.enabled = false; +} +Script.scriptEnding.connect(scriptEnding); + + diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index c99b35352e..654e797e1b 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -113,8 +113,7 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) { // Scene Octree Debuging job { addJob("DrawSceneOctree", opaqueSelection); - // _drawStatusJobIndex = (int)_jobs.size() - 1; - // enableJob(_drawStatusJobIndex, false); + addJob("DrawItemSelection", opaqueSelection); } // Status icon rendering job diff --git a/libraries/render/src/render/CullTask.cpp b/libraries/render/src/render/CullTask.cpp index 70cf420e3b..580084cb86 100644 --- a/libraries/render/src/render/CullTask.cpp +++ b/libraries/render/src/render/CullTask.cpp @@ -182,7 +182,11 @@ void FetchSpatialTree::run(const SceneContextPointer& sceneContext, const Render } // Octree selection! - scene->getSpatialTree().selectCellItems(outSelection, _filter, queryFrustum, _lodAngle); + + float angle = glm::degrees(args->_viewFrustum->getAccuracyAngle(args->_sizeScale, args->_boundaryLevelAdjust)); + + + scene->getSpatialTree().selectCellItems(outSelection, _filter, queryFrustum, angle); } diff --git a/libraries/render/src/render/DrawSceneOctree.cpp b/libraries/render/src/render/DrawSceneOctree.cpp index d664af3c9b..f60b20a69f 100644 --- a/libraries/render/src/render/DrawSceneOctree.cpp +++ b/libraries/render/src/render/DrawSceneOctree.cpp @@ -25,6 +25,9 @@ #include "drawCellBounds_frag.h" #include "drawLODReticle_frag.h" +#include "drawItemBounds_vert.h" +#include "drawItemBounds_frag.h" + using namespace render; @@ -76,6 +79,7 @@ const gpu::PipelinePointer DrawSceneOctree::getDrawLODReticlePipeline() { void DrawSceneOctree::configure(const Config& config) { _showVisibleCells = config.showVisibleCells; + _showEmptyCells = config.showEmptyCells; _justFrozeFrustum = (config.freezeFrustum && !_freezeFrustum); _freezeFrustum = config.freezeFrustum; @@ -88,45 +92,7 @@ void DrawSceneOctree::run(const SceneContextPointer& sceneContext, assert(renderContext->args->_viewFrustum); RenderArgs* args = renderContext->args; auto& scene = sceneContext->_scene; - /*const int NUM_STATUS_VEC4_PER_ITEM = 2; - const int VEC4_LENGTH = 4; - // FIrst thing, we update the local buffers with the values coming from Scene octree - int nbCells = 0; - { - if (!_cells) { - _cells = std::make_shared(); - } - - const auto& inCells = scene->getSpatialTree()._cells; - _cells->resize(inCells.size() * sizeof(AABox)); - AABox* cellAABox = reinterpret_cast (_cells->editData()); - for (const auto& cell : inCells) { - (*cellAABox) = scene->getSpatialTree().evalBound(cell.getlocation()); - nbCells++; - cellAABox++; - } - } - - if (nbCells == 0) { - return; - } - - auto queryFrustum = *args->_viewFrustum; - if (_freezeFrustum) { - if (_justFrozeFrustum) { - _justFrozeFrustum = false; - _frozenFrutstum = *args->_viewFrustum; - } - queryFrustum = _frozenFrutstum; - } -*/ - // Try that: - // Octree::CellSelection selection; - // scene->getSpatialTree().selectCells(selection, queryFrustum); - - - // Allright, something to render let's do it gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { glm::mat4 projMat; Transform viewMat; @@ -141,41 +107,50 @@ void DrawSceneOctree::run(const SceneContextPointer& sceneContext, // bind the one gpu::Pipeline we need batch.setPipeline(getDrawCellBoundsPipeline()); - for (const auto& cellID : inSelection.cellSelection.insideCells) { - auto cell = scene->getSpatialTree().getConcreteCell(cellID); + if (_showVisibleCells) { - auto cellLoc = cell.getlocation(); + for (const auto& cellID : inSelection.cellSelection.insideCells) { + auto cell = scene->getSpatialTree().getConcreteCell(cellID); + auto cellLoc = cell.getlocation(); + glm::ivec4 cellLocation(cellLoc.pos.x, cellLoc.pos.y, cellLoc.pos.z, cellLoc.depth); - glm::ivec4 cellLocation(cellLoc.pos.x, cellLoc.pos.y, cellLoc.pos.z, cellLoc.depth); - if (cell.isBrickEmpty() || !cell.hasBrick()) { - cellLocation.w *= -1; + bool doDraw = true; + if (cell.isBrickEmpty() || !cell.hasBrick()) { + if (!_showEmptyCells) { + doDraw = false; + } + cellLocation.w *= -1; + } + if (doDraw) { + batch._glUniform4iv(_drawCellLocationLoc, 1, ((const int*)(&cellLocation))); + batch.draw(gpu::LINES, 24, 0); + } } - batch._glUniform4iv(_drawCellLocationLoc, 1, ((const int*)(&cellLocation))); + for (const auto& cellID : inSelection.cellSelection.partialCells) { + auto cell = scene->getSpatialTree().getConcreteCell(cellID); + auto cellLoc = cell.getlocation(); + glm::ivec4 cellLocation(cellLoc.pos.x, cellLoc.pos.y, cellLoc.pos.z, cellLoc.depth); - batch.draw(gpu::LINES, 24, 0); - } - for (const auto& cellID : inSelection.cellSelection.partialCells) { - auto cell = scene->getSpatialTree().getConcreteCell(cellID); - - auto cellLoc = cell.getlocation(); - - glm::ivec4 cellLocation(cellLoc.pos.x, cellLoc.pos.y, cellLoc.pos.z, cellLoc.depth); - if (cell.isBrickEmpty() || !cell.hasBrick()) { - cellLocation.w *= -1; + bool doDraw = true; + if (cell.isBrickEmpty() || !cell.hasBrick()) { + if (!_showEmptyCells) { + doDraw = false; + } + cellLocation.w *= -1; + } + if (doDraw) { + batch._glUniform4iv(_drawCellLocationLoc, 1, ((const int*)(&cellLocation))); + batch.draw(gpu::LINES, 24, 0); + } } - - batch._glUniform4iv(_drawCellLocationLoc, 1, ((const int*)(&cellLocation))); - - batch.draw(gpu::LINES, 24, 0); } - // Draw the LOD Reticle { float angle = glm::degrees(args->_viewFrustum->getAccuracyAngle(args->_sizeScale, args->_boundaryLevelAdjust)); Transform crosshairModel; - crosshairModel.setTranslation(glm::vec3(0.0, 0.0, -1.0)); - crosshairModel.setScale(tan(glm::radians(angle))); // Scaling at the actual tan of the lod angle => Multiplied by TWO + crosshairModel.setTranslation(glm::vec3(0.0, 0.0, -1000.0)); + crosshairModel.setScale(1000.0 * tan(glm::radians(angle))); // Scaling at the actual tan of the lod angle => Multiplied by TWO batch.setViewTransform(Transform()); batch.setModelTransform(crosshairModel); batch.setPipeline(getDrawLODReticlePipeline()); @@ -183,3 +158,107 @@ void DrawSceneOctree::run(const SceneContextPointer& sceneContext, } }); } + +const gpu::PipelinePointer DrawItemSelection::getDrawItemBoundPipeline() { + if (!_drawItemBoundPipeline) { + auto vs = gpu::Shader::createVertex(std::string(drawItemBounds_vert)); + auto ps = gpu::Shader::createPixel(std::string(drawItemBounds_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); + + gpu::Shader::BindingSet slotBindings; + gpu::Shader::makeProgram(*program, slotBindings); + + _drawItemBoundPosLoc = program->getUniforms().findLocation("inBoundPos"); + _drawItemBoundDimLoc = program->getUniforms().findLocation("inBoundDim"); + + auto state = std::make_shared(); + + state->setDepthTest(true, false, gpu::LESS_EQUAL); + + // Blend on transparent + state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); + + // Good to go add the brand new pipeline + _drawItemBoundPipeline = gpu::Pipeline::create(program, state); + } + return _drawItemBoundPipeline; +} + +void DrawItemSelection::configure(const Config& config) { + _showInsideItems = config.showInsideItems; + _showInsideSubcellItems = config.showInsideSubcellItems; + _showPartialItems = config.showPartialItems; + _showPartialSubcellItems = config.showPartialSubcellItems; +} + + +void DrawItemSelection::run(const SceneContextPointer& sceneContext, + const RenderContextPointer& renderContext, const ItemSpatialTree::ItemSelection& inSelection) { + assert(renderContext->args); + assert(renderContext->args->_viewFrustum); + RenderArgs* args = renderContext->args; + auto& scene = sceneContext->_scene; + + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + glm::mat4 projMat; + Transform viewMat; + args->_viewFrustum->evalProjectionMatrix(projMat); + args->_viewFrustum->evalViewTransform(viewMat); + batch.setViewportTransform(args->_viewport); + + batch.setProjectionTransform(projMat); + batch.setViewTransform(viewMat); + batch.setModelTransform(Transform()); + + // bind the one gpu::Pipeline we need + batch.setPipeline(getDrawItemBoundPipeline()); + + if (_showInsideItems) { + for (const auto& itemID : inSelection.insideItems) { + auto& item = scene->getItem(itemID); + auto itemBound = item.getBound(); + + batch._glUniform3fv(_drawItemBoundPosLoc, 1, (const float*)(&itemBound.getCorner())); + batch._glUniform3fv(_drawItemBoundDimLoc, 1, (const float*)(&itemBound.getScale())); + + batch.draw(gpu::LINES, 24, 0); + } + } + + if (_showInsideSubcellItems) { + for (const auto& itemID : inSelection.insideSubcellItems) { + auto& item = scene->getItem(itemID); + auto itemBound = item.getBound(); + + batch._glUniform3fv(_drawItemBoundPosLoc, 1, (const float*)(&itemBound.getCorner())); + batch._glUniform3fv(_drawItemBoundDimLoc, 1, (const float*)(&itemBound.getScale())); + + batch.draw(gpu::LINES, 24, 0); + } + } + + if (_showPartialItems) { + for (const auto& itemID : inSelection.partialItems) { + auto& item = scene->getItem(itemID); + auto itemBound = item.getBound(); + + batch._glUniform3fv(_drawItemBoundPosLoc, 1, (const float*)(&itemBound.getCorner())); + batch._glUniform3fv(_drawItemBoundDimLoc, 1, (const float*)(&itemBound.getScale())); + + batch.draw(gpu::LINES, 24, 0); + } + } + + if (_showPartialSubcellItems) { + for (const auto& itemID : inSelection.partialSubcellItems) { + auto& item = scene->getItem(itemID); + auto itemBound = item.getBound(); + + batch._glUniform3fv(_drawItemBoundPosLoc, 1, (const float*)(&itemBound.getCorner())); + batch._glUniform3fv(_drawItemBoundDimLoc, 1, (const float*)(&itemBound.getScale())); + + batch.draw(gpu::LINES, 24, 0); + } + } + }); +} diff --git a/libraries/render/src/render/DrawSceneOctree.h b/libraries/render/src/render/DrawSceneOctree.h index ddf22f4e9b..7301a776f3 100644 --- a/libraries/render/src/render/DrawSceneOctree.h +++ b/libraries/render/src/render/DrawSceneOctree.h @@ -19,18 +19,22 @@ namespace render { class DrawSceneOctreeConfig : public Job::Config { Q_OBJECT + Q_PROPERTY(bool enabled MEMBER enabled NOTIFY dirty()) Q_PROPERTY(bool showVisibleCells MEMBER showVisibleCells WRITE setShowVisibleCells) + Q_PROPERTY(bool showEmptyCells MEMBER showEmptyCells WRITE setShowEmptyCells) Q_PROPERTY(bool freezeFrustum MEMBER freezeFrustum WRITE setFreezeFrustum) public: - DrawSceneOctreeConfig() : Job::Config(true) {} // FIXME FOR debug + DrawSceneOctreeConfig() : Job::Config(false) {} - bool showVisibleCells{ true }; // FIXME FOR debug + bool showVisibleCells{ true }; + bool showEmptyCells{ false }; bool freezeFrustum{ false }; public slots: - void setShowVisibleCells(bool enabled) { showVisibleCells = enabled; emit dirty(); } - void setFreezeFrustum(bool enabled) { freezeFrustum = enabled; emit dirty(); } + void setShowVisibleCells(bool show) { showVisibleCells = show; emit dirty(); } + void setShowEmptyCells(bool show) { showEmptyCells = show; emit dirty(); } + void setFreezeFrustum(bool freeze) { freezeFrustum = freeze; emit dirty(); } signals: void dirty(); @@ -44,8 +48,12 @@ namespace render { gpu::PipelinePointer _drawLODReticlePipeline; + int _drawItemBoundPosLoc = -1; + int _drawItemBoundDimLoc = -1; + gpu::PipelinePointer _drawItemBoundPipeline; bool _showVisibleCells; // initialized by Config + bool _showEmptyCells; // initialized by Config bool _freezeFrustum{ false }; // initialized by Config bool _justFrozeFrustum{ false }; ViewFrustum _frozenFrutstum; @@ -61,6 +69,57 @@ namespace render { const gpu::PipelinePointer getDrawCellBoundsPipeline(); const gpu::PipelinePointer getDrawLODReticlePipeline(); + const gpu::PipelinePointer getDrawItemBoundPipeline(); + }; + + + class DrawItemSelectionConfig : public Job::Config { + Q_OBJECT + Q_PROPERTY(bool enabled MEMBER enabled NOTIFY dirty()) + Q_PROPERTY(bool showInsideItems MEMBER showInsideItems WRITE setShowInsideItems) + Q_PROPERTY(bool showInsideSubcellItems MEMBER showInsideSubcellItems WRITE setShowInsideSubcellItems) + Q_PROPERTY(bool showPartialItems MEMBER showPartialItems WRITE setShowPartialItems) + Q_PROPERTY(bool showPartialSubcellItems MEMBER showPartialSubcellItems WRITE setShowPartialSubcellItems) + public: + + DrawItemSelectionConfig() : Job::Config(false) {} + + bool showInsideItems{ true }; + bool showInsideSubcellItems{ true }; + bool showPartialItems{ true }; + bool showPartialSubcellItems{ true }; + + public slots: + void setShowInsideItems(bool show) { showInsideItems = show; emit dirty(); } + void setShowInsideSubcellItems(bool show) { showInsideSubcellItems = show; emit dirty(); } + void setShowPartialItems(bool show) { showPartialItems = show; emit dirty(); } + void setShowPartialSubcellItems(bool show) { showPartialSubcellItems = show; emit dirty(); } + + signals: + void dirty(); + }; + + class DrawItemSelection { + + int _drawItemBoundPosLoc = -1; + int _drawItemBoundDimLoc = -1; + gpu::PipelinePointer _drawItemBoundPipeline; + + bool _showInsideItems; // initialized by Config + bool _showInsideSubcellItems; // initialized by Config + bool _showPartialItems; // initialized by Config + bool _showPartialSubcellItems; // initialized by Config + + public: + using Config = DrawItemSelectionConfig; + using JobModel = Job::ModelI; + + DrawItemSelection() {} + + void configure(const Config& config); + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemSpatialTree::ItemSelection& selection); + + const gpu::PipelinePointer getDrawItemBoundPipeline(); }; } diff --git a/libraries/render/src/render/Octree.cpp b/libraries/render/src/render/Octree.cpp index 3ccad4d7b3..c78013c19d 100644 --- a/libraries/render/src/render/Octree.cpp +++ b/libraries/render/src/render/Octree.cpp @@ -243,9 +243,8 @@ ItemSpatialTree::Index ItemSpatialTree::resetItem(Index oldCell, const ItemKey& // Compare range size vs cell location size and tag itemKey accordingly auto rangeSizef = maxCoordf - minCoordf; - const float SQRT_OF_3 = 1.73205; - float cellDiagonalSquare = 3 * (float)getDepthDimension(location.depth); - bool subcellItem = glm::dot(rangeSizef, rangeSizef) < cellDiagonalSquare; + float cellFitSize = getCellHalfDiagonalSquare(location.depth); + bool subcellItem = glm::dot(rangeSizef, rangeSizef) < cellFitSize; newKey.setSmaller(subcellItem); auto newCell = indexCell(location); @@ -255,6 +254,7 @@ ItemSpatialTree::Index ItemSpatialTree::resetItem(Index oldCell, const ItemKey& // Did the key changed, if yes update if (newKey._flags != oldKey._flags) { updateItem(newCell, oldKey, newKey, item); + return newCell; } return newCell; } diff --git a/libraries/render/src/render/Octree.h b/libraries/render/src/render/Octree.h index 6309ea8d6b..356da469ff 100644 --- a/libraries/render/src/render/Octree.h +++ b/libraries/render/src/render/Octree.h @@ -327,6 +327,11 @@ namespace render { float getCellWidth(Depth depth) const { return (float) _size * getInvDepthDimension(depth); } float getInvCellWidth(Depth depth) const { return (float) getDepthDimension(depth) * _invSize; } + float getCellHalfDiagonalSquare(Depth depth) const { + float cellHalfWidth = 0.5f * getCellWidth(depth); + return 3.0f * cellHalfWidth * cellHalfWidth; + } + glm::vec3 evalPos(const Coord3& coord, Depth depth = Octree::METRIC_COORD_DEPTH) const { return getOrigin() + glm::vec3(coord) * getCellWidth(depth); }