From 8b648408fdf53bddf32e30d692150f540ba3dfd1 Mon Sep 17 00:00:00 2001 From: ksuprynowicz Date: Fri, 13 Oct 2023 19:28:05 +0200 Subject: [PATCH] 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()->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 - Not used. * @property {number} pidKi - Not used. @@ -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); }