Merge pull request #663 from overte-org/feature/new_LOD

Added distance-based LOD
This commit is contained in:
ksuprynowicz 2023-10-16 22:59:10 +02:00 committed by GitHub
commit b6f148576a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 127 additions and 22 deletions

View file

@ -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"
}
}

View file

@ -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();

View file

@ -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 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();
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) {

View file

@ -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
@ -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 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 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
* @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

View file

@ -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:

View file

@ -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);

View file

@ -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 };

View file

@ -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: 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);
}
@ -423,4 +426,4 @@ void ClearContainingZones::run(const RenderContextPointer& renderContext) {
// of the next frame
CullTest::_prevContainingZones = CullTest::_containingZones;
CullTest::_containingZones.clear();
}
}