Added distance-based LOD

This commit is contained in:
ksuprynowicz 2023-10-13 19:28:05 +02:00
parent 57a2ebb800
commit 8b648408fd
5 changed files with 116 additions and 11 deletions

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

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

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: 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);
}