From 921a3fb8c0ec2b17f8d6ac09d4209fa7835971d6 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 15 Oct 2014 20:18:04 -0700 Subject: [PATCH 1/6] switch QList<> to QVector<> and add some guards against out of range indices --- interface/src/renderer/Model.cpp | 12 ++++++++++-- interface/src/renderer/Model.h | 32 ++++++++++++++++---------------- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 72a6ab7afe..c38e768381 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1393,7 +1393,7 @@ int Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, bool cullMeshParts = args && !Menu::getInstance()->isOptionChecked(MenuOption::DontCullMeshParts); // depending on which parameters we were called with, pick the correct mesh group to render - QList* whichList = NULL; + QVector* whichList = NULL; if (translucent && !hasTangents && !hasSpecular && !isSkinned) { whichList = &_meshesTranslucent; } else if (translucent && hasTangents && !hasSpecular && !isSkinned) { @@ -1434,7 +1434,7 @@ int Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, qDebug() << "unexpected!!! we don't know which list of meshes to render..."; return 0; } - QList& list = *whichList; + QVector& list = *whichList; ProgramObject* program = &_program; Locations* locations = &_locations; @@ -1486,6 +1486,14 @@ int Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, // i is the "index" from the original networkMeshes QVector... foreach (int i, list) { + + // if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshesGroupsKnown + // to false to rebuild out mesh groups. + + if (i < 0 || i >= networkMeshes.size() || i > geometry.meshes.size()) { + _meshesGroupsKnown = false; // regenerate these lists next time around. + continue; + } // exit early if the translucency doesn't match what we're drawing const NetworkMesh& networkMesh = networkMeshes.at(i); diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 55a2eed9d1..b3c319543b 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -337,25 +337,25 @@ private: bool _meshesGroupsKnown; - QList _meshesTranslucent; - QList _meshesTranslucentTangents; - QList _meshesTranslucentTangentsSpecular; - QList _meshesTranslucentSpecular; + QVector _meshesTranslucent; + QVector _meshesTranslucentTangents; + QVector _meshesTranslucentTangentsSpecular; + QVector _meshesTranslucentSpecular; - QList _meshesTranslucentSkinned; - QList _meshesTranslucentTangentsSkinned; - QList _meshesTranslucentTangentsSpecularSkinned; - QList _meshesTranslucentSpecularSkinned; + QVector _meshesTranslucentSkinned; + QVector _meshesTranslucentTangentsSkinned; + QVector _meshesTranslucentTangentsSpecularSkinned; + QVector _meshesTranslucentSpecularSkinned; - QList _meshesOpaque; - QList _meshesOpaqueTangents; - QList _meshesOpaqueTangentsSpecular; - QList _meshesOpaqueSpecular; + QVector _meshesOpaque; + QVector _meshesOpaqueTangents; + QVector _meshesOpaqueTangentsSpecular; + QVector _meshesOpaqueSpecular; - QList _meshesOpaqueSkinned; - QList _meshesOpaqueTangentsSkinned; - QList _meshesOpaqueTangentsSpecularSkinned; - QList _meshesOpaqueSpecularSkinned; + QVector _meshesOpaqueSkinned; + QVector _meshesOpaqueTangentsSkinned; + QVector _meshesOpaqueTangentsSpecularSkinned; + QVector _meshesOpaqueSpecularSkinned; }; From 4c7ecba57971f7210012dbd0f058ce3677f1cad3 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 15 Oct 2014 20:23:04 -0700 Subject: [PATCH 2/6] spelling change --- interface/src/renderer/Model.cpp | 16 ++++++++-------- interface/src/renderer/Model.h | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index c38e768381..d18f4c95e1 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -47,7 +47,7 @@ Model::Model(QObject* parent) : _blendNumber(0), _appliedBlendNumber(0), _calculatedMeshBoxesValid(false), - _meshesGroupsKnown(false) { + _meshGroupsKnown(false) { // we may have been created in the network thread, but we live in the main thread moveToThread(Application::getInstance()->thread()); @@ -273,7 +273,7 @@ void Model::reset() { _jointStates[i].setRotationInConstrainedFrame(geometry.joints.at(i).rotation, 0.0f); } - _meshesGroupsKnown = false; + _meshGroupsKnown = false; } bool Model::updateGeometry() { @@ -323,7 +323,7 @@ bool Model::updateGeometry() { deleteGeometry(); _dilatedTextures.clear(); _geometry = geometry; - _meshesGroupsKnown = false; + _meshGroupsKnown = false; setJointStates(newJointStates); needToRebuild = true; } else if (_jointStates.isEmpty()) { @@ -426,7 +426,7 @@ bool Model::render(float alpha, RenderMode mode, RenderArgs* args) { } } - if (!_meshesGroupsKnown) { + if (!_meshGroupsKnown) { segregateMeshGroups(); } @@ -1247,7 +1247,7 @@ void Model::applyNextGeometry() { // we retain a reference to the base geometry so that its reference count doesn't fall to zero _baseGeometry = _nextBaseGeometry; _geometry = _nextGeometry; - _meshesGroupsKnown = false; + _meshGroupsKnown = false; _nextBaseGeometry.reset(); _nextGeometry.reset(); } @@ -1380,7 +1380,7 @@ void Model::segregateMeshGroups() { qDebug() << "unexpected!!! this mesh didn't fall into any or our groups???"; } } - _meshesGroupsKnown = true; + _meshGroupsKnown = true; } int Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, @@ -1487,11 +1487,11 @@ int Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, // i is the "index" from the original networkMeshes QVector... foreach (int i, list) { - // if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshesGroupsKnown + // if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown // to false to rebuild out mesh groups. if (i < 0 || i >= networkMeshes.size() || i > geometry.meshes.size()) { - _meshesGroupsKnown = false; // regenerate these lists next time around. + _meshGroupsKnown = false; // regenerate these lists next time around. continue; } diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index b3c319543b..80a9fe474d 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -335,7 +335,7 @@ private: void segregateMeshGroups(); // used to calculate our list of translucent vs opaque meshes - bool _meshesGroupsKnown; + bool _meshGroupsKnown; QVector _meshesTranslucent; QVector _meshesTranslucentTangents; From bf77adc4bc7865504363961a92490ea94b5c04c5 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 16 Oct 2014 00:30:24 -0700 Subject: [PATCH 3/6] add support for LOD occulsion for too small meshes in Model::render() --- interface/src/Menu.cpp | 25 +++++++ interface/src/Menu.h | 2 + interface/src/entities/EntityTreeRenderer.cpp | 66 ++++++------------- interface/src/entities/EntityTreeRenderer.h | 4 -- interface/src/renderer/Model.cpp | 11 +++- interface/src/renderer/Model.h | 1 + interface/src/ui/Stats.cpp | 10 ++- libraries/octree/src/OctreeRenderer.cpp | 5 +- libraries/octree/src/OctreeRenderer.h | 6 ++ libraries/octree/src/ViewFrustum.cpp | 7 ++ libraries/octree/src/ViewFrustum.h | 2 + 11 files changed, 84 insertions(+), 55 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index bf70b8a134..784914f335 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1595,6 +1595,31 @@ void Menu::setBoundaryLevelAdjust(int boundaryLevelAdjust) { bumpSettings(); } +// TODO: This could be optimized to be a table, or something that doesn't require recalculation on every +// render call for every entity +// TODO: This is essentially the same logic used to render voxels, but since models are more detailed then voxels +// I've added a voxelToModelRatio that adjusts how much closer to a model you have to be to see it. +bool Menu::shouldRenderMesh(float largestDimension, float distanceToCamera) const { + const float voxelToMeshRatio = 4.0f; // must be this many times closer to a mesh than a voxel to see it. + float voxelSizeScale = getVoxelSizeScale(); + int boundaryLevelAdjust = getBoundaryLevelAdjust(); + + float scale = (float)TREE_SCALE; + float visibleDistanceAtScale = boundaryDistanceForRenderLevel(boundaryLevelAdjust, voxelSizeScale) / voxelToMeshRatio; + + while (scale > largestDimension) { + scale /= 2.0f; + visibleDistanceAtScale /= 2.0f; + } + + if (scale < largestDimension) { + visibleDistanceAtScale *= 2.0f; + } + + return (distanceToCamera <= visibleDistanceAtScale); +} + + void Menu::lodTools() { if (!_lodToolsDialog) { _lodToolsDialog = new LodToolsDialog(Application::getInstance()->getGLWidget()); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index a7291581eb..7a861ee2a8 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -143,6 +143,8 @@ public: void setBoundaryLevelAdjust(int boundaryLevelAdjust); int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; } + bool shouldRenderMesh(float largestDimension, float distanceToCamera) const; + #ifdef Q_OS_MAC SpeechRecognizer* getSpeechRecognizer() { return &_speechRecognizer; } #endif diff --git a/interface/src/entities/EntityTreeRenderer.cpp b/interface/src/entities/EntityTreeRenderer.cpp index c7849c136d..2c7c970376 100644 --- a/interface/src/entities/EntityTreeRenderer.cpp +++ b/interface/src/entities/EntityTreeRenderer.cpp @@ -162,36 +162,6 @@ void renderElementProxy(EntityTreeElement* entityTreeElement) { } } -float EntityTreeRenderer::distanceToCamera(const glm::vec3& center, const ViewFrustum& viewFrustum) const { - glm::vec3 temp = viewFrustum.getPosition() - center; - float distanceToVoxelCenter = sqrtf(glm::dot(temp, temp)); - return distanceToVoxelCenter; -} - -// TODO: This could be optimized to be a table, or something that doesn't require recalculation on every -// render call for every entity -// TODO: This is essentially the same logic used to render voxels, but since models are more detailed then voxels -// I've added a voxelToModelRatio that adjusts how much closer to a model you have to be to see it. -bool EntityTreeRenderer::shouldRenderEntity(float largestDimension, float distanceToCamera) const { - const float voxelToModelRatio = 4.0f; // must be this many times closer to a model than a voxel to see it. - float voxelSizeScale = Menu::getInstance()->getVoxelSizeScale(); - int boundaryLevelAdjust = Menu::getInstance()->getBoundaryLevelAdjust(); - - float scale = (float)TREE_SCALE; - float visibleDistanceAtScale = boundaryDistanceForRenderLevel(boundaryLevelAdjust, voxelSizeScale) / voxelToModelRatio; - - while (scale > largestDimension) { - scale /= 2.0f; - visibleDistanceAtScale /= 2.0f; - } - - if (scale < largestDimension) { - visibleDistanceAtScale *= 2.0f; - } - - return (distanceToCamera <= visibleDistanceAtScale); -} - void EntityTreeRenderer::renderProxies(const EntityItem* entity, RenderArgs* args) { bool isShadowMode = args->_renderMode == OctreeRenderer::SHADOW_RENDER_MODE; bool displayModelBounds = Menu::getInstance()->isOptionChecked(MenuOption::DisplayModelBounds); @@ -287,7 +257,7 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) // TODO: some entity types (like lights) might want to be rendered even // when they are outside of the view frustum... - float distance = distanceToCamera(entityBox.calcCenter(), *args->_viewFrustum); + float distance = args->_viewFrustum->distanceToCamera(entityBox.calcCenter()); if (wantDebug) { qDebug() << "------- renderElement() ----------"; @@ -299,24 +269,28 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) qDebug() << " entityBox:" << entityItem->getAABox(); qDebug() << " dimensions:" << entityItem->getDimensionsInMeters() << "in meters"; qDebug() << " largestDimension:" << entityBox.getLargestDimension() << "in meters"; - qDebug() << " shouldRender:" << shouldRenderEntity(entityBox.getLargestDimension(), distance); + qDebug() << " shouldRender:" << Menu::getInstance()->shouldRenderMesh(entityBox.getLargestDimension(), distance); qDebug() << " in frustum:" << (args->_viewFrustum->boxInFrustum(entityBox) != ViewFrustum::OUTSIDE); } - - if (shouldRenderEntity(entityBox.getLargestDimension(), distance) && - args->_viewFrustum->boxInFrustum(entityBox) != ViewFrustum::OUTSIDE) { - - - renderProxies(entityItem, args); - Glower* glower = NULL; - if (entityItem->getGlowLevel() > 0.0f) { - glower = new Glower(entityItem->getGlowLevel()); - } - entityItem->render(args); - args->_itemsRendered++; - if (glower) { - delete glower; + bool outOfView = args->_viewFrustum->boxInFrustum(entityBox) == ViewFrustum::OUTSIDE; + if (!outOfView) { + bool bigEnoughToRender = Menu::getInstance()->shouldRenderMesh(entityBox.getLargestDimension(), distance); + + if (bigEnoughToRender) { + renderProxies(entityItem, args); + + Glower* glower = NULL; + if (entityItem->getGlowLevel() > 0.0f) { + glower = new Glower(entityItem->getGlowLevel()); + } + entityItem->render(args); + args->_itemsRendered++; + if (glower) { + delete glower; + } + } else { + args->_itemsTooSmall++; } } else { args->_itemsOutOfView++; diff --git a/interface/src/entities/EntityTreeRenderer.h b/interface/src/entities/EntityTreeRenderer.h index 9e0368b61b..7ce984a97d 100644 --- a/interface/src/entities/EntityTreeRenderer.h +++ b/interface/src/entities/EntityTreeRenderer.h @@ -76,11 +76,7 @@ public: void deleteReleasedModels(); private: QList _releasedModels; - - float distanceToCamera(const glm::vec3& center, const ViewFrustum& viewFrustum) const; - bool shouldRenderEntity(float largestDimension, float distanceToCamera) const; void renderProxies(const EntityItem* entity, RenderArgs* args); - }; #endif // hifi_EntityTreeRenderer_h diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index d18f4c95e1..941c7123b5 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1514,12 +1514,21 @@ int Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, if (cullMeshParts && args->_viewFrustum) { shouldRender = args->_viewFrustum->boxInFrustum(_calculatedMeshBoxes.at(i)) != ViewFrustum::OUTSIDE; + if (shouldRender) { + float distance = args->_viewFrustum->distanceToCamera(_calculatedMeshBoxes.at(i).calcCenter()); + shouldRender = Menu::getInstance()->shouldRenderMesh(_calculatedMeshBoxes.at(i).getLargestDimension(), + distance); + if (!shouldRender) { + args->_meshesTooSmall++; + } + } else { + args->_meshesOutOfView++; + } } if (shouldRender) { args->_meshesRendered++; } else { - args->_meshesOutOfView++; continue; // skip this mesh } } diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 80a9fe474d..f03e3f5e38 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -31,6 +31,7 @@ class QScriptEngine; class AnimationHandle; class Shape; class RenderArgs; +class ViewFrustum; typedef QSharedPointer AnimationHandlePointer; typedef QWeakPointer WeakAnimationHandlePointer; diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index e78297323a..90e21e9caf 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -459,7 +459,7 @@ void Stats::display( VoxelSystem* voxels = Application::getInstance()->getVoxels(); - lines = _expanded ? 14 : 3; + lines = _expanded ? 15 : 3; if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessing)) { lines += 10; // spatial audio processing adds 1 spacing line and 8 extra lines of info } @@ -472,12 +472,16 @@ void Stats::display( // Model/Entity render details EntityTreeRenderer* entities = Application::getInstance()->getEntities(); voxelStats.str(""); - voxelStats << "Entity Items rendered: " << entities->getItemsRendered() << " Out of view:" << entities->getItemsOutOfView(); + voxelStats << "Entity Items rendered: " << entities->getItemsRendered() + << " Out of view:" << entities->getItemsOutOfView() + << " Too small:" << entities->getItemsTooSmall(); verticalOffset += STATS_PELS_PER_LINE; drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color); voxelStats.str(""); - voxelStats << "Meshes rendered: " << entities->getMeshesRendered() << " Out of view:" << entities->getMeshesOutOfView(); + voxelStats << "Meshes rendered: " << entities->getMeshesRendered() + << " Out of view:" << entities->getMeshesOutOfView() + << " Too small:" << entities->getMeshesTooSmall(); verticalOffset += STATS_PELS_PER_LINE; drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color); diff --git a/libraries/octree/src/OctreeRenderer.cpp b/libraries/octree/src/OctreeRenderer.cpp index 21c085c5df..006255bfff 100644 --- a/libraries/octree/src/OctreeRenderer.cpp +++ b/libraries/octree/src/OctreeRenderer.cpp @@ -162,7 +162,8 @@ bool OctreeRenderer::renderOperation(OctreeElement* element, void* extraData) { } void OctreeRenderer::render(RenderMode renderMode) { - RenderArgs args = { this, _viewFrustum, getSizeScale(), getBoundaryLevelAdjust(), renderMode, 0, 0, 0, 0, 0, 0, 0, 0 }; + RenderArgs args = { this, _viewFrustum, getSizeScale(), getBoundaryLevelAdjust(), renderMode, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; if (_tree) { _tree->lockForRead(); _tree->recurseTreeWithOperation(renderOperation, &args); @@ -171,10 +172,12 @@ void OctreeRenderer::render(RenderMode renderMode) { _meshesConsidered = args._meshesConsidered; _meshesRendered = args._meshesRendered; _meshesOutOfView = args._meshesOutOfView; + _meshesTooSmall = args._meshesTooSmall; _elementsTouched = args._elementsTouched; _itemsRendered = args._itemsRendered; _itemsOutOfView = args._itemsOutOfView; + _itemsTooSmall = args._itemsTooSmall; _trianglesRendered = args._trianglesRendered; _quadsRendered = args._quadsRendered; diff --git a/libraries/octree/src/OctreeRenderer.h b/libraries/octree/src/OctreeRenderer.h index 6d734d113e..528235ed86 100644 --- a/libraries/octree/src/OctreeRenderer.h +++ b/libraries/octree/src/OctreeRenderer.h @@ -67,10 +67,12 @@ public: int getElementsTouched() const { return _elementsTouched; } int getItemsRendered() const { return _itemsRendered; } int getItemsOutOfView() const { return _itemsOutOfView; } + int getItemsTooSmall() const { return _itemsTooSmall; } int getMeshesConsidered() const { return _meshesConsidered; } int getMeshesRendered() const { return _meshesRendered; } int getMeshesOutOfView() const { return _meshesOutOfView; } + int getMeshesTooSmall() const { return _meshesTooSmall; } int getTrianglesRendered() const { return _trianglesRendered; } int getQuadsRendered() const { return _quadsRendered; } @@ -86,10 +88,12 @@ protected: int _elementsTouched; int _itemsRendered; int _itemsOutOfView; + int _itemsTooSmall; int _meshesConsidered; int _meshesRendered; int _meshesOutOfView; + int _meshesTooSmall; int _trianglesRendered; int _quadsRendered; @@ -109,10 +113,12 @@ public: int _elementsTouched; int _itemsRendered; int _itemsOutOfView; + int _itemsTooSmall; int _meshesConsidered; int _meshesRendered; int _meshesOutOfView; + int _meshesTooSmall; int _trianglesRendered; int _quadsRendered; diff --git a/libraries/octree/src/ViewFrustum.cpp b/libraries/octree/src/ViewFrustum.cpp index 1e8dc41cdd..c1348e28c7 100644 --- a/libraries/octree/src/ViewFrustum.cpp +++ b/libraries/octree/src/ViewFrustum.cpp @@ -876,3 +876,10 @@ void ViewFrustum::getFurthestPointFromCameraVoxelScale(const AACube& box, glm::v } } +float ViewFrustum::distanceToCamera(const glm::vec3& point) const { + glm::vec3 temp = getPosition() - point; + float distanceToPoint = sqrtf(glm::dot(temp, temp)); + return distanceToPoint; +} + + diff --git a/libraries/octree/src/ViewFrustum.h b/libraries/octree/src/ViewFrustum.h index a23ec2af92..4b2b57fab2 100644 --- a/libraries/octree/src/ViewFrustum.h +++ b/libraries/octree/src/ViewFrustum.h @@ -118,6 +118,8 @@ public: // assumes box is in voxel scale, not TREE_SCALE, will scale view frustum's position accordingly void getFurthestPointFromCameraVoxelScale(const AACube& box, glm::vec3& furthestPoint) const; + + float distanceToCamera(const glm::vec3& point) const; private: // Used for keyhole calculations From d238d06df58fae568201a9822733942d54da72a0 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 16 Oct 2014 01:00:32 -0700 Subject: [PATCH 4/6] build a cached lookup table for the shouldRenderMesh() LOD method --- interface/src/Menu.cpp | 48 ++++++++++++++++++++++++++++++------------ interface/src/Menu.h | 5 ++++- 2 files changed, 38 insertions(+), 15 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 784914f335..4c7018e7f9 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -122,7 +122,8 @@ Menu::Menu() : _hasLoginDialogDisplayed(false), _snapshotsLocation(), _scriptsLocation(), - _walletPrivateKey() + _walletPrivateKey(), + _shouldRenderTableNeedsRebuilding(true) { Application *appInstance = Application::getInstance(); @@ -1551,6 +1552,7 @@ void Menu::autoAdjustLOD(float currentFPS) { && _voxelSizeScale > ADJUST_LOD_MIN_SIZE_SCALE) { _voxelSizeScale *= ADJUST_LOD_DOWN_BY; + if (_voxelSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) { _voxelSizeScale = ADJUST_LOD_MIN_SIZE_SCALE; } @@ -1573,6 +1575,7 @@ void Menu::autoAdjustLOD(float currentFPS) { } if (changed) { + _shouldRenderTableNeedsRebuilding = true; if (_lodToolsDialog) { _lodToolsDialog->reloadSliders(); } @@ -1587,36 +1590,53 @@ void Menu::resetLODAdjust() { void Menu::setVoxelSizeScale(float sizeScale) { _voxelSizeScale = sizeScale; + _shouldRenderTableNeedsRebuilding = true; bumpSettings(); } void Menu::setBoundaryLevelAdjust(int boundaryLevelAdjust) { _boundaryLevelAdjust = boundaryLevelAdjust; + _shouldRenderTableNeedsRebuilding = true; bumpSettings(); } -// TODO: This could be optimized to be a table, or something that doesn't require recalculation on every -// render call for every entity // TODO: This is essentially the same logic used to render voxels, but since models are more detailed then voxels // I've added a voxelToModelRatio that adjusts how much closer to a model you have to be to see it. -bool Menu::shouldRenderMesh(float largestDimension, float distanceToCamera) const { +bool Menu::shouldRenderMesh(float largestDimension, float distanceToCamera) { const float voxelToMeshRatio = 4.0f; // must be this many times closer to a mesh than a voxel to see it. float voxelSizeScale = getVoxelSizeScale(); int boundaryLevelAdjust = getBoundaryLevelAdjust(); + float maxScale = (float)TREE_SCALE; + float visibleDistanceAtMaxScale = boundaryDistanceForRenderLevel(boundaryLevelAdjust, voxelSizeScale) / voxelToMeshRatio; - float scale = (float)TREE_SCALE; - float visibleDistanceAtScale = boundaryDistanceForRenderLevel(boundaryLevelAdjust, voxelSizeScale) / voxelToMeshRatio; + if (_shouldRenderTableNeedsRebuilding) { + _shouldRenderTable.clear(); - while (scale > largestDimension) { - scale /= 2.0f; - visibleDistanceAtScale /= 2.0f; - } - - if (scale < largestDimension) { - visibleDistanceAtScale *= 2.0f; + float SMALLEST_SCALE_IN_TABLE = 0.001f; // 1mm is plenty small + float scale = maxScale; + float visibleDistanceAtScale = visibleDistanceAtMaxScale; + + while (scale > SMALLEST_SCALE_IN_TABLE) { + scale /= 2.0f; + visibleDistanceAtScale /= 2.0f; + _shouldRenderTable[scale] = visibleDistanceAtScale; + } + _shouldRenderTableNeedsRebuilding = false; } - return (distanceToCamera <= visibleDistanceAtScale); + float closestScale = maxScale; + float visibleDistanceAtClosestScale = visibleDistanceAtMaxScale; + QMap::const_iterator lowerBound = _shouldRenderTable.lowerBound(largestDimension); + if (lowerBound != _shouldRenderTable.constEnd()) { + closestScale = lowerBound.key(); + visibleDistanceAtClosestScale = lowerBound.value(); + } + + if (closestScale < largestDimension) { + visibleDistanceAtClosestScale *= 2.0f; + } + + return (distanceToCamera <= visibleDistanceAtClosestScale); } diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 7a861ee2a8..244e82219d 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -143,7 +143,7 @@ public: void setBoundaryLevelAdjust(int boundaryLevelAdjust); int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; } - bool shouldRenderMesh(float largestDimension, float distanceToCamera) const; + bool shouldRenderMesh(float largestDimension, float distanceToCamera); #ifdef Q_OS_MAC SpeechRecognizer* getSpeechRecognizer() { return &_speechRecognizer; } @@ -312,6 +312,9 @@ private: QString _snapshotsLocation; QString _scriptsLocation; QByteArray _walletPrivateKey; + + bool _shouldRenderTableNeedsRebuilding; + QMap _shouldRenderTable; }; From ffb7bcf9d350f284c0fb196a6c9cd0aece22a1b7 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 16 Oct 2014 09:32:24 -0700 Subject: [PATCH 5/6] wire up different culling options to debug menus --- interface/src/Menu.cpp | 4 +++- interface/src/Menu.h | 3 ++- interface/src/renderer/Model.cpp | 12 +++++++----- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 4c7018e7f9..35ee52f273 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -424,10 +424,12 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderFocusIndicator, 0, false); QMenu* modelDebugMenu = developerMenu->addMenu("Models"); - addCheckableActionToQMenuAndActionHash(modelDebugMenu, MenuOption::DontCullMeshParts, 0, false); addCheckableActionToQMenuAndActionHash(modelDebugMenu, MenuOption::DisplayModelBounds, 0, false); addCheckableActionToQMenuAndActionHash(modelDebugMenu, MenuOption::DisplayModelElementProxy, 0, false); addCheckableActionToQMenuAndActionHash(modelDebugMenu, MenuOption::DisplayModelElementChildProxies, 0, false); + QMenu* modelCullingMenu = modelDebugMenu->addMenu("Culling"); + addCheckableActionToQMenuAndActionHash(modelCullingMenu, MenuOption::DontCullOutOfViewMeshParts, 0, false); + addCheckableActionToQMenuAndActionHash(modelCullingMenu, MenuOption::DontCullTooSmallMeshParts, 0, false); QMenu* voxelOptionsMenu = developerMenu->addMenu("Voxels"); addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::VoxelTextures); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 244e82219d..3e2c095924 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -372,7 +372,8 @@ namespace MenuOption { const QString Collisions = "Collisions"; const QString Console = "Console..."; const QString ControlWithSpeech = "Control With Speech"; - const QString DontCullMeshParts = "Don't Cull Mesh Parts"; + const QString DontCullOutOfViewMeshParts = "Don't Cull Out Of View Mesh Parts"; + const QString DontCullTooSmallMeshParts = "Don't Cull Too Small Mesh Parts"; const QString DecreaseAvatarSize = "Decrease Avatar Size"; const QString DecreaseVoxelSize = "Decrease Voxel Size"; const QString DisableActivityLogger = "Disable Activity Logger"; diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 941c7123b5..40359c309d 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1390,8 +1390,6 @@ int Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, const FBXGeometry& geometry = _geometry->getFBXGeometry(); const QVector& networkMeshes = _geometry->getMeshes(); - bool cullMeshParts = args && !Menu::getInstance()->isOptionChecked(MenuOption::DontCullMeshParts); - // depending on which parameters we were called with, pick the correct mesh group to render QVector* whichList = NULL; if (translucent && !hasTangents && !hasSpecular && !isSkinned) { @@ -1509,12 +1507,16 @@ int Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, // if we got here, then check to see if this mesh is in view if (args) { + bool dontCullOutOfViewMeshParts = Menu::getInstance()->isOptionChecked(MenuOption::DontCullOutOfViewMeshParts); + bool cullTooSmallMeshParts = !Menu::getInstance()->isOptionChecked(MenuOption::DontCullTooSmallMeshParts); + bool shouldRender = true; args->_meshesConsidered++; - if (cullMeshParts && args->_viewFrustum) { - shouldRender = args->_viewFrustum->boxInFrustum(_calculatedMeshBoxes.at(i)) != ViewFrustum::OUTSIDE; - if (shouldRender) { + if (args->_viewFrustum) { + shouldRender = dontCullOutOfViewMeshParts || + args->_viewFrustum->boxInFrustum(_calculatedMeshBoxes.at(i)) != ViewFrustum::OUTSIDE; + if (shouldRender && cullTooSmallMeshParts) { float distance = args->_viewFrustum->distanceToCamera(_calculatedMeshBoxes.at(i).calcCenter()); shouldRender = Menu::getInstance()->shouldRenderMesh(_calculatedMeshBoxes.at(i).getLargestDimension(), distance); From 8b54569480d1951e1029c131706102c9b910ec7a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 16 Oct 2014 10:20:12 -0700 Subject: [PATCH 6/6] experimental hair tuning submitted by Ryan --- interface/src/Hair.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/interface/src/Hair.cpp b/interface/src/Hair.cpp index 34114430df..e9c110d4ac 100644 --- a/interface/src/Hair.cpp +++ b/interface/src/Hair.cpp @@ -8,7 +8,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -// Creates single flexible vertlet-integrated strands that can be used for hair/fur/grass +// Creates single flexible verlet-integrated strands that can be used for hair/fur/grass #include "Hair.h" @@ -39,7 +39,7 @@ Hair::Hair(int strands, _angularVelocity(0.0f), _angularAcceleration(0.0f), _gravity(0.0f), - _loudness() + _loudness(0.0f) { _hairPosition = new glm::vec3[_strands * _links]; _hairOriginalPosition = new glm::vec3[_strands * _links]; @@ -90,7 +90,9 @@ Hair::Hair(int strands, } } } - } +} + +const float SOUND_THRESHOLD = 50.0f; void Hair::simulate(float deltaTime) { deltaTime = glm::clamp(deltaTime, 0.0f, 1.0f / 30.0f); @@ -119,10 +121,10 @@ void Hair::simulate(float deltaTime) { (_radius - glm::length(_hairPosition[vertexIndex])); } // Add random thing driven by loudness - const float LOUD_BASE = 0.0005f; - float loudnessFactor = (_loudness > 0.0f) ? logf(_loudness) / 2000.0f : 0.0f; + float loudnessFactor = (_loudness > SOUND_THRESHOLD) ? logf(_loudness - SOUND_THRESHOLD) / 8000.0f : 0.0f; - _hairPosition[vertexIndex] += randVector() * (LOUD_BASE + loudnessFactor) * ((float)link / (float)_links); + const float QUIESCENT_LOUDNESS = 0.0f; + _hairPosition[vertexIndex] += randVector() * (QUIESCENT_LOUDNESS + loudnessFactor) * ((float)link / (float)_links); // Add gravity const float SCALE_GRAVITY = 0.10f; @@ -178,7 +180,7 @@ void Hair::simulate(float deltaTime) { } } - // Store start position for next vertlet pass + // Store start position for next verlet pass _hairLastPosition[vertexIndex] = thisPosition; } } @@ -189,9 +191,9 @@ void Hair::render() { // // Before calling this function, translate/rotate to the origin of the owning object // - float loudnessFactor = (_loudness > 0.0f) ? logf(_loudness) / 16.0f : 0.0f; + float loudnessFactor = (_loudness > SOUND_THRESHOLD) ? logf(_loudness - SOUND_THRESHOLD) / 16.0f : 0.0f; const int SPARKLE_EVERY = 5; - const float HAIR_SETBACK = 0.125f; + const float HAIR_SETBACK = 0.0f; int sparkleIndex = (int) (randFloat() * SPARKLE_EVERY); glPushMatrix(); glTranslatef(0.f, 0.f, HAIR_SETBACK);