From 8b648408fdf53bddf32e30d692150f540ba3dfd1 Mon Sep 17 00:00:00 2001 From: ksuprynowicz <ksuprynowicz@post.pl> Date: Fri, 13 Oct 2023 19:28:05 +0200 Subject: [PATCH 1/6] Added distance-based LOD --- interface/src/Application.cpp | 3 +- interface/src/LODManager.cpp | 56 +++++++++++++++++++++++- interface/src/LODManager.h | 37 +++++++++++++++- libraries/render/src/render/Args.h | 26 ++++++++--- libraries/render/src/render/CullTask.cpp | 5 ++- 5 files changed, 116 insertions(+), 11 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 628d9173b8..04fb78c496 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -6829,7 +6829,8 @@ void Application::updateRenderArgs(float deltaTime) { _viewFrustum.calculate(); } appRenderArgs._renderArgs = RenderArgs(_graphicsEngine.getGPUContext(), lodManager->getVisibilityDistance(), - lodManager->getBoundaryLevelAdjust(), lodManager->getLODHalfAngleTan(), RenderArgs::DEFAULT_RENDER_MODE, + lodManager->getBoundaryLevelAdjust(), lodManager->getLODFarHalfAngleTan(), lodManager->getLODNearHalfAngleTan(), + lodManager->getLODFarDistance(), lodManager->getLODNearDistance(), RenderArgs::DEFAULT_RENDER_MODE, RenderArgs::MONO, RenderArgs::DEFERRED, RenderArgs::RENDER_DEBUG_NONE); appRenderArgs._renderArgs._scene = getMain3DScene(); diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index 1eb8580ac7..ef4a181a91 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -172,7 +172,8 @@ void LODManager::autoAdjustLOD(float realTimeDelta) { _pidOutputs.w = output; // And now add the output of the controller to the LODAngle where we will guarantee it is in the proper range - setLODAngleDeg(oldLODAngle + output); + float newLODAngle = std::min(oldLODAngle + output, glm::degrees(_farMaxAngle)); + setLODAngleDeg(newLODAngle); if (oldLODAngle != getLODAngleDeg()) { auto lodToolsDialog = DependencyManager::get<DialogsManager>()->getLodToolsDialog(); @@ -185,6 +186,16 @@ void LODManager::autoAdjustLOD(float realTimeDelta) { float LODManager::getLODHalfAngleTan() const { return tan(_lodHalfAngle); } +float LODManager::getLODFarHalfAngleTan() const { + return tan(std::min(_lodHalfAngle, _farMaxAngle / 2.0f)); +} +float LODManager::getLODNearHalfAngleTan() const { + if (_farMaxAngle > 0) { + return tan(std::min(_lodHalfAngle / (_farMaxAngle / 2.0f) * (_nearMaxAngle / 2.0f), _nearMaxAngle / 2.0f)); + } else { + return 0.0f; + } +} float LODManager::getLODAngle() const { return 2.0f * _lodHalfAngle; } @@ -192,6 +203,37 @@ float LODManager::getLODAngleDeg() const { return glm::degrees(getLODAngle()); } +void LODManager::setLODFarDistance(float value) { + _farDistance = value; + updateLODAfterSettingsChange(); +} + +void LODManager::setLODNearDistance(float value) { + _nearDistance = value; + updateLODAfterSettingsChange(); +} + +void LODManager::setLODFarMaxAngleDeg(float value) { + _farMaxAngle = glm::radians(value); + updateLODAfterSettingsChange(); +} + +float LODManager::getLODFarMaxAngleDeg() const { + return glm::degrees(_farMaxAngle); +} + +void LODManager::setLODNearMaxAngle(float value) { + _nearMaxAngle = glm::radians(value); + updateLODAfterSettingsChange(); +} + +void LODManager::updateLODAfterSettingsChange() {} + +float LODManager::getLODNearMaxAngle() const { + return glm::degrees(_nearMaxAngle); +} + + float LODManager::getVisibilityDistance() const { float systemDistance = getVisibilityDistanceFromHalfAngle(_lodHalfAngle); // Maintain behavior with deprecated _boundaryLevelAdjust property @@ -274,9 +316,19 @@ bool LODManager::shouldRender(const RenderArgs* args, const AABox& bounds) { // we are comparing the square of the half tangent apparent angle for the bound against the LODAngle Half tangent square // if smaller, the bound is too small and we should NOT render it, return true otherwise. + // TODO: maybe include avatar size in calculating near and far distance? + // Tangent Adjacent side is eye to bound center vector length auto pos = args->getViewFrustum().getPosition() - bounds.calcCenter(); auto halfTanAdjacentSq = glm::dot(pos, pos); + auto distSq = halfTanAdjacentSq; + + if (distSq <= args->_lodNearDistSq) { + return true; + } + + float farNearRatio = (distSq > args->_lodFarDistSq) ? 1.0f : (distSq - args->_lodNearDistSq)/(args->_lodFarDistSq - args->_lodNearDistSq); + float lodAngleHalfTanSq = (farNearRatio * (args->_lodFarAngleHalfTanSq - args->_lodNearAngleHalfTanSq)) + args->_lodNearAngleHalfTanSq; // Tangent Opposite side is the half length of the dimensions vector of the bound auto dim = bounds.getDimensions(); @@ -286,7 +338,7 @@ bool LODManager::shouldRender(const RenderArgs* args, const AABox& bounds) { // isVisible = halfTanSq >= lodHalfTanSq = (halfTanOppositeSq / halfTanAdjacentSq) >= lodHalfTanSq // which we express as below to avoid division // (halfTanOppositeSq) >= lodHalfTanSq * halfTanAdjacentSq - return (halfTanOppositeSq >= args->_lodAngleHalfTanSq * halfTanAdjacentSq); + return (halfTanOppositeSq >= lodAngleHalfTanSq * halfTanAdjacentSq); }; void LODManager::setOctreeSizeScale(float sizeScale) { diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index 125dd0dd93..f903aa8997 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -49,7 +49,7 @@ enum WorldDetailQuality { }; Q_DECLARE_METATYPE(WorldDetailQuality); -const bool DEFAULT_LOD_AUTO_ADJUST = false; // true for auto, false for manual. +const bool DEFAULT_LOD_AUTO_ADJUST = true; // true for auto, false for manual. #ifdef Q_OS_ANDROID const float DEFAULT_LOD_QUALITY_LEVEL = 0.2f; // default quality level setting is High (lower framerate) @@ -120,6 +120,17 @@ class AABox; * @property {number} lodAngleDeg - The minimum angular dimension (relative to the camera position) of an entity in order for * it to be rendered, in degrees. The angular dimension is calculated as a sphere of radius half the diagonal of the * entity's AA box. + + * @property {number} lodFarMaxAngleDeg - The upper limit of how big the minimum angular dimension (relative to the camera position) + * of an entity in order for it to be rendered, in degrees at distance specified by lodFarDistance. The angular dimension is + * calculated as a sphere of radius half the diagonal of the entity's AA box. + * @property {number} lodNearMaxAngleDeg - The upper limit of how big the minimum angular dimension (relative to the camera position) + * of an entity in order for it to be rendered, in degrees at distance specified by lodFarDistance. The angular dimension is + * calculated as a sphere of radius half the diagonal of the entity's AA box. + + * @property {number} lodFarDistance - Distance for which lodFarMaxAngleDeg limit is applied + * @property {number} lodNearDistance - Distance for which lodNearMaxAngleDeg limit is applied + * * @property {number} pidKp - <em>Not used.</em> * @property {number} pidKi - <em>Not used.</em> @@ -157,6 +168,11 @@ class LODManager : public QObject, public Dependency { Q_PROPERTY(float lodAngleDeg READ getLODAngleDeg WRITE setLODAngleDeg) + Q_PROPERTY(float lodFarMaxAngleDeg READ getLODFarMaxAngleDeg WRITE setLODFarMaxAngleDeg) + Q_PROPERTY(float lodNearMaxAngleDeg READ getLODNearMaxAngle WRITE setLODNearMaxAngle) + Q_PROPERTY(float lodFarDistance READ getLODFarDistance WRITE setLODFarDistance) + Q_PROPERTY(float lodNearDistance READ getLODNearDistance WRITE setLODNearDistance) + Q_PROPERTY(float pidKp READ getPidKp WRITE setPidKp) Q_PROPERTY(float pidKi READ getPidKi WRITE setPidKi) Q_PROPERTY(float pidKd READ getPidKd WRITE setPidKd) @@ -292,7 +308,8 @@ public: float getLODAngleDeg() const; void setLODAngleDeg(float lodAngle); - float getLODHalfAngleTan() const; + float getLODFarHalfAngleTan() const; + float getLODNearHalfAngleTan() const; float getLODAngle() const; float getVisibilityDistance() const; void setVisibilityDistance(float distance); @@ -311,6 +328,15 @@ public: float getPidOd() const; float getPidO() const; + void setLODFarDistance(float value); + float getLODFarDistance() const { return _farDistance; } + void setLODNearDistance(float value); + float getLODNearDistance() const { return _nearDistance; } + void setLODFarMaxAngleDeg(float value); + float getLODFarMaxAngleDeg() const; + void setLODNearMaxAngle(float value); + float getLODNearMaxAngle() const; + signals: /*@jsdoc @@ -354,7 +380,9 @@ signals: private: LODManager(); + float getLODHalfAngleTan() const; void setWorldDetailQuality(WorldDetailQuality quality, bool isHMDMode); + void updateLODAfterSettingsChange(); std::mutex _automaticLODLock; bool _automaticLODAdjust = DEFAULT_LOD_AUTO_ADJUST; @@ -364,6 +392,11 @@ private: float _batchTime{ 0.0f }; // msec float _gpuTime{ 0.0f }; // msec + float _farDistance{ 200.0f }; + float _nearDistance{ 4.0f }; + float _farMaxAngle{ 15.0f / 180.f * (float)M_PI }; + float _nearMaxAngle{ 1.0f / 180.f * (float)M_PI }; + float _nowRenderTime{ 0.0f }; // msec float _smoothScale{ 10.0f }; // smooth is evaluated over 10 times longer than now float _smoothRenderTime{ 0.0f }; // msec diff --git a/libraries/render/src/render/Args.h b/libraries/render/src/render/Args.h index 5fee00b370..d09b0d2f2f 100644 --- a/libraries/render/src/render/Args.h +++ b/libraries/render/src/render/Args.h @@ -76,7 +76,11 @@ namespace render { Args(const gpu::ContextPointer& context, float sizeScale = 1.0f, int boundaryLevelAdjust = 0, - float lodAngleHalfTan = 0.1f, + float lodFarAngleHalfTan = 0.1f, + float lodNearAngleHalfTan = 0.01f, + //float lodAngleHalfTan = 0.1f, + float lodFarDist = 200.0f, + float lodNearDist = 4.0f, RenderMode renderMode = DEFAULT_RENDER_MODE, DisplayMode displayMode = MONO, RenderMethod renderMethod = DEFERRED, @@ -85,8 +89,14 @@ namespace render { _context(context), _sizeScale(sizeScale), _boundaryLevelAdjust(boundaryLevelAdjust), - _lodAngleHalfTan(lodAngleHalfTan), - _lodAngleHalfTanSq(lodAngleHalfTan * lodAngleHalfTan), + _lodFarAngleHalfTan(lodFarAngleHalfTan), + _lodFarAngleHalfTanSq(lodFarAngleHalfTan * lodFarAngleHalfTan), + _lodNearAngleHalfTan(lodNearAngleHalfTan), + _lodNearAngleHalfTanSq(lodNearAngleHalfTan * lodNearAngleHalfTan), + _lodFarDist(lodFarDist), + _lodNearDist(lodNearDist), + _lodFarDistSq(lodFarDist * lodFarDist), + _lodNearDistSq(lodNearDist * lodNearDist), _renderMode(renderMode), _displayMode(displayMode), _renderMethod(renderMethod), @@ -116,8 +126,14 @@ namespace render { float _sizeScale { 1.0f }; int _boundaryLevelAdjust { 0 }; - float _lodAngleHalfTan{ 0.1f }; - float _lodAngleHalfTanSq{ _lodAngleHalfTan * _lodAngleHalfTan }; + float _lodFarAngleHalfTan{ 0.1f }; + float _lodFarAngleHalfTanSq{ _lodFarAngleHalfTan * _lodFarAngleHalfTan }; + float _lodNearAngleHalfTan{ 0.01f }; + float _lodNearAngleHalfTanSq{ _lodNearAngleHalfTan * _lodNearAngleHalfTan }; + float _lodFarDist { 200.0f }; + float _lodNearDist { 4.0f }; + float _lodFarDistSq { _lodFarDist * _lodFarDist }; + float _lodNearDistSq { _lodNearDist * _lodNearDist }; RenderMode _renderMode { DEFAULT_RENDER_MODE }; DisplayMode _displayMode { MONO }; diff --git a/libraries/render/src/render/CullTask.cpp b/libraries/render/src/render/CullTask.cpp index 68bb467f66..a7e811130e 100644 --- a/libraries/render/src/render/CullTask.cpp +++ b/libraries/render/src/render/CullTask.cpp @@ -127,7 +127,10 @@ void FetchSpatialTree::run(const RenderContextPointer& renderContext, const Inpu // Octree selection! float threshold = 0.0f; if (queryFrustum.isPerspective()) { - threshold = args->_lodAngleHalfTan; + //TODO: It was: + // threshold = args->_lodFarAngleHalfTan; + // But now should be dependent on distance + threshold = args->_lodFarAngleHalfTan; if (frustumResolution.y > 0) { threshold = glm::max(queryFrustum.getFieldOfView() / frustumResolution.y, threshold); } From c6e9772def4be6d87feade6af3a7eb6f7f5f0b4d Mon Sep 17 00:00:00 2001 From: ksuprynowicz <ksuprynowicz@post.pl> Date: Fri, 13 Oct 2023 22:12:06 +0200 Subject: [PATCH 2/6] Update comment in interface/src/LODManager.cpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Julian Groß <julian.g@posteo.de> --- interface/src/LODManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index ef4a181a91..fdd1b51fb3 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -316,7 +316,7 @@ bool LODManager::shouldRender(const RenderArgs* args, const AABox& bounds) { // we are comparing the square of the half tangent apparent angle for the bound against the LODAngle Half tangent square // if smaller, the bound is too small and we should NOT render it, return true otherwise. - // TODO: maybe include avatar size in calculating near and far distance? + // TODO: maybe include own avatar size in calculating near and far distance? // Tangent Adjacent side is eye to bound center vector length auto pos = args->getViewFrustum().getPosition() - bounds.calcCenter(); From f74725042ed3164be7366ef00ceebf4ea2f0e578 Mon Sep 17 00:00:00 2001 From: Karol Suprynowicz <ksuprynowicz@post.pl> Date: Sun, 15 Oct 2023 18:46:47 +0200 Subject: [PATCH 3/6] Better name for LOD options and clearer documentation --- .../hifi/dialogs/graphics/GraphicsSettings.qml | 8 ++++---- interface/src/LODManager.h | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/interface/resources/qml/hifi/dialogs/graphics/GraphicsSettings.qml b/interface/resources/qml/hifi/dialogs/graphics/GraphicsSettings.qml index 707a890edb..1e1ee376a8 100644 --- a/interface/resources/qml/hifi/dialogs/graphics/GraphicsSettings.qml +++ b/interface/resources/qml/hifi/dialogs/graphics/GraphicsSettings.qml @@ -144,7 +144,7 @@ Flickable { HifiStylesUit.RalewayRegular { id: worldDetailHeader - text: "World Detail" + text: "Target frame rate" anchors.left: parent.left anchors.top: parent.top width: 130 @@ -157,13 +157,13 @@ Flickable { id: worldDetailModel ListElement { - text: "Low World Detail" + text: "High Frame Rate/Low Detail" } ListElement { - text: "Medium World Detail" + text: "Medium Frame Rate/Medium Detail" } ListElement { - text: "Full World Detail" + text: "Low Frame Rate/High Detail" } } diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index f903aa8997..ff453ae28a 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -29,15 +29,15 @@ class ScriptEngine; /*@jsdoc - * <p>The world detail quality rendered.</p> + * <p>The balance between target framerate and world detail quality rendered.</p> * <table> * <thead> * <tr><th>Value</th><th>Description</th></tr> * </thead> * <tbody> - * <tr><td><code>0</code></td><td>Low world detail quality.</td></tr> - * <tr><td><code>1</code></td><td>Medium world detail quality.</td></tr> - * <tr><td><code>2</code></td><td>High world detail quality.</td></tr> + * <tr><td><code>0</code></td><td>High frame rate / Low detail quality.</td></tr> + * <tr><td><code>1</code></td><td>Medium frame rate / Medium detail quality.</td></tr> + * <tr><td><code>2</code></td><td>Low frame rate / High detail quality.</td></tr> * </tbody> * </table> * @typedef {number} LODManager.WorldDetailQuality @@ -121,11 +121,11 @@ class AABox; * it to be rendered, in degrees. The angular dimension is calculated as a sphere of radius half the diagonal of the * entity's AA box. - * @property {number} lodFarMaxAngleDeg - The upper limit of how big the minimum angular dimension (relative to the camera position) - * of an entity in order for it to be rendered, in degrees at distance specified by lodFarDistance. The angular dimension is + * @property {number} lodFarMaxAngleDeg - The maximum angular size (relative to the camera position) + * of an entity that is allowed to be culled by LOD Manager, in degrees at distance specified by lodFarDistance. The angular dimension is * calculated as a sphere of radius half the diagonal of the entity's AA box. - * @property {number} lodNearMaxAngleDeg - The upper limit of how big the minimum angular dimension (relative to the camera position) - * of an entity in order for it to be rendered, in degrees at distance specified by lodFarDistance. The angular dimension is + * @property {number} lodNearMaxAngleDeg - The maximum angular size (relative to the camera position) +* of an entity that is allowed to be culled by LOD Manager, in degrees at distance specified by lodNearDistance. The angular dimension is * calculated as a sphere of radius half the diagonal of the entity's AA box. * @property {number} lodFarDistance - Distance for which lodFarMaxAngleDeg limit is applied From 68f6e466bf1e2ad5f91ddc66d1b63c551548f341 Mon Sep 17 00:00:00 2001 From: Karol Suprynowicz <ksuprynowicz@post.pl> Date: Sun, 15 Oct 2023 20:21:47 +0200 Subject: [PATCH 4/6] Default to higher LOD framerate target on High graphics setting --- interface/src/PerformanceManager.cpp | 2 +- interface/src/scripting/PerformanceScriptingInterface.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/PerformanceManager.cpp b/interface/src/PerformanceManager.cpp index f74cfab88a..560d11e4e7 100644 --- a/interface/src/PerformanceManager.cpp +++ b/interface/src/PerformanceManager.cpp @@ -99,7 +99,7 @@ void PerformanceManager::applyPerformancePreset(PerformanceManager::PerformanceP RenderScriptingInterface::getInstance()->setShadowsEnabled(true); qApp->getRefreshRateManager().setRefreshRateProfile(RefreshRateManager::RefreshRateProfile::REALTIME); - DependencyManager::get<LODManager>()->setWorldDetailQuality(WORLD_DETAIL_HIGH); + DependencyManager::get<LODManager>()->setWorldDetailQuality(WORLD_DETAIL_MEDIUM); break; case PerformancePreset::MID: diff --git a/interface/src/scripting/PerformanceScriptingInterface.h b/interface/src/scripting/PerformanceScriptingInterface.h index 249706a5ea..6a06986aaf 100644 --- a/interface/src/scripting/PerformanceScriptingInterface.h +++ b/interface/src/scripting/PerformanceScriptingInterface.h @@ -99,7 +99,7 @@ public slots: /*@jsdoc * Sets graphics performance to a preset. * @function Performance.setPerformancePreset - * @param {Performance.PerformancePreset} performancePreset - The graphics performance preset to to use. + * @param {Performance.PerformancePreset} performancePreset - The graphics performance preset to use. */ void setPerformancePreset(PerformancePreset performancePreset); From f04c3b5840b04d0c22bc93ba58545bedae75682e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20Gro=C3=9F?= <julian.g@posteo.de> Date: Mon, 16 Oct 2023 21:24:26 +0200 Subject: [PATCH 5/6] Make comment more coherent --- libraries/render/src/render/CullTask.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/render/src/render/CullTask.cpp b/libraries/render/src/render/CullTask.cpp index a7e811130e..039cf01c86 100644 --- a/libraries/render/src/render/CullTask.cpp +++ b/libraries/render/src/render/CullTask.cpp @@ -127,9 +127,9 @@ void FetchSpatialTree::run(const RenderContextPointer& renderContext, const Inpu // Octree selection! float threshold = 0.0f; if (queryFrustum.isPerspective()) { - //TODO: It was: - // threshold = args->_lodFarAngleHalfTan; - // But now should be dependent on distance + // TODO: Before our LOD took distance into account it used: + // threshold = args->_lodAngleHalfTan; + // We should make it dependent on distance in the future. threshold = args->_lodFarAngleHalfTan; if (frustumResolution.y > 0) { threshold = glm::max(queryFrustum.getFieldOfView() / frustumResolution.y, threshold); @@ -426,4 +426,4 @@ void ClearContainingZones::run(const RenderContextPointer& renderContext) { // of the next frame CullTest::_prevContainingZones = CullTest::_containingZones; CullTest::_containingZones.clear(); -} \ No newline at end of file +} From 6ea4cdb434be75da22c1a2d35b4f4f78debcac82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20Gro=C3=9F?= <julian.g@posteo.de> Date: Mon, 16 Oct 2023 22:02:10 +0200 Subject: [PATCH 6/6] Update interface/src/LODManager.h --- interface/src/LODManager.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index ff453ae28a..4571747908 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -125,7 +125,7 @@ class AABox; * of an entity that is allowed to be culled by LOD Manager, in degrees at distance specified by lodFarDistance. The angular dimension is * calculated as a sphere of radius half the diagonal of the entity's AA box. * @property {number} lodNearMaxAngleDeg - The maximum angular size (relative to the camera position) -* of an entity that is allowed to be culled by LOD Manager, in degrees at distance specified by lodNearDistance. The angular dimension is + * of an entity that is allowed to be culled by LOD Manager, in degrees at distance specified by lodNearDistance. The angular dimension is * calculated as a sphere of radius half the diagonal of the entity's AA box. * @property {number} lodFarDistance - Distance for which lodFarMaxAngleDeg limit is applied