mirror of
https://github.com/AleziaKurdis/overte.git
synced 2025-04-16 18:18:19 +02:00
Merge pull request #6848 from ZappoMan/entityServerSideSizeCheck
Include checking the angular size of entities on the server side for LOD support
This commit is contained in:
commit
5caf10beed
16 changed files with 105 additions and 128 deletions
|
@ -3507,14 +3507,6 @@ glm::vec3 Application::getSunDirection() {
|
|||
// FIXME, preprocessor guard this check to occur only in DEBUG builds
|
||||
static QThread * activeRenderingThread = nullptr;
|
||||
|
||||
float Application::getSizeScale() const {
|
||||
return DependencyManager::get<LODManager>()->getOctreeSizeScale();
|
||||
}
|
||||
|
||||
int Application::getBoundaryLevelAdjust() const {
|
||||
return DependencyManager::get<LODManager>()->getBoundaryLevelAdjust();
|
||||
}
|
||||
|
||||
PickRay Application::computePickRay(float x, float y) const {
|
||||
vec2 pickPoint { x, y };
|
||||
PickRay result;
|
||||
|
|
|
@ -170,8 +170,6 @@ public:
|
|||
|
||||
virtual ViewFrustum* getCurrentViewFrustum() { return getDisplayViewFrustum(); }
|
||||
virtual QThread* getMainThread() { return thread(); }
|
||||
virtual float getSizeScale() const;
|
||||
virtual int getBoundaryLevelAdjust() const;
|
||||
virtual PickRay computePickRay(float x, float y) const;
|
||||
virtual glm::vec3 getAvatarPosition() const;
|
||||
virtual void overrideEnvironmentData(const EnvironmentData& newData) { _environment.override(newData); }
|
||||
|
|
|
@ -25,7 +25,7 @@ Setting::Handle<float> hmdLODDecreaseFPS("hmdLODDecreaseFPS", DEFAULT_HMD_LOD_DO
|
|||
// pid: renderDistance is adjusted by a PID such that frame rate targets are met.
|
||||
// acuity: a pseudo-acuity target is held, or adjusted to match minimum frame rates (and a PID controlls avatar rendering distance)
|
||||
// If unspecified, acuity is used only if user has specified non-default minumum frame rates.
|
||||
Setting::Handle<int> lodPreference("lodPreference", (int)LODManager::LODPreference::unspecified);
|
||||
Setting::Handle<int> lodPreference("lodPreference", (int)LODManager::LODPreference::acuity);
|
||||
const float SMALLEST_REASONABLE_HORIZON = 50.0f; // meters
|
||||
Setting::Handle<float> renderDistanceInverseHighLimit("renderDistanceInverseHighLimit", 1.0f / SMALLEST_REASONABLE_HORIZON);
|
||||
void LODManager::setRenderDistanceInverseHighLimit(float newValue) {
|
||||
|
@ -183,7 +183,6 @@ void LODManager::autoAdjustLOD(float currentFPS) {
|
|||
|
||||
if (changed) {
|
||||
calculateAvatarLODDistanceMultiplier();
|
||||
_shouldRenderTableNeedsRebuilding = true;
|
||||
auto lodToolsDialog = DependencyManager::get<DialogsManager>()->getLodToolsDialog();
|
||||
if (lodToolsDialog) {
|
||||
lodToolsDialog->reloadSliders();
|
||||
|
@ -253,7 +252,7 @@ QString LODManager::getLODStatsRenderText() {
|
|||
const QString label = "Rendered objects: ";
|
||||
return label + QString::number(getRenderedCount()) + " w/in " + QString::number((int)getRenderDistance()) + "m";
|
||||
}
|
||||
// compare audoAdjustLOD()
|
||||
// compare autoAdjustLOD()
|
||||
void LODManager::updatePIDRenderDistance(float targetFps, float measuredFps, float deltaTime, bool isThrottled) {
|
||||
float distance;
|
||||
if (!isThrottled) {
|
||||
|
@ -274,96 +273,26 @@ void LODManager::updatePIDRenderDistance(float targetFps, float measuredFps, flo
|
|||
}
|
||||
|
||||
bool LODManager::shouldRender(const RenderArgs* args, const AABox& bounds) {
|
||||
float distanceToCamera = glm::length(bounds.calcCenter() - args->_viewFrustum->getPosition());
|
||||
float largestDimension = bounds.getLargestDimension();
|
||||
// NOTE: this branch of code is the alternate form of LOD that uses PID controllers.
|
||||
if (!getUseAcuity()) {
|
||||
float distanceToCamera = glm::length(bounds.calcCenter() - args->_viewFrustum->getPosition());
|
||||
float largestDimension = bounds.getLargestDimension();
|
||||
const float scenerySize = 300; // meters
|
||||
bool isRendered = (largestDimension > scenerySize) || // render scenery regardless of distance
|
||||
(distanceToCamera < renderDistance + largestDimension);
|
||||
renderedCount += isRendered ? 1 : 0;
|
||||
return isRendered;
|
||||
}
|
||||
|
||||
const float maxScale = (float)TREE_SCALE;
|
||||
const float octreeToMeshRatio = 4.0f; // must be this many times closer to a mesh than a voxel to see it.
|
||||
float octreeSizeScale = args->_sizeScale;
|
||||
int boundaryLevelAdjust = args->_boundaryLevelAdjust;
|
||||
float visibleDistanceAtMaxScale = boundaryDistanceForRenderLevel(boundaryLevelAdjust, octreeSizeScale) / octreeToMeshRatio;
|
||||
|
||||
static bool shouldRenderTableNeedsBuilding = true;
|
||||
static QMap<float, float> shouldRenderTable;
|
||||
if (shouldRenderTableNeedsBuilding) {
|
||||
float SMALLEST_SCALE_IN_TABLE = 0.001f; // 1mm is plenty small
|
||||
float scale = maxScale;
|
||||
float factor = 1.0f;
|
||||
|
||||
while (scale > SMALLEST_SCALE_IN_TABLE) {
|
||||
scale /= 2.0f;
|
||||
factor /= 2.0f;
|
||||
shouldRenderTable[scale] = factor;
|
||||
}
|
||||
|
||||
shouldRenderTableNeedsBuilding = false;
|
||||
}
|
||||
|
||||
float closestScale = maxScale;
|
||||
float visibleDistanceAtClosestScale = visibleDistanceAtMaxScale;
|
||||
QMap<float, float>::const_iterator lowerBound = shouldRenderTable.lowerBound(largestDimension);
|
||||
if (lowerBound != shouldRenderTable.constEnd()) {
|
||||
closestScale = lowerBound.key();
|
||||
visibleDistanceAtClosestScale = visibleDistanceAtMaxScale * lowerBound.value();
|
||||
}
|
||||
|
||||
if (closestScale < largestDimension) {
|
||||
visibleDistanceAtClosestScale *= 2.0f;
|
||||
}
|
||||
|
||||
return distanceToCamera <= visibleDistanceAtClosestScale;
|
||||
// FIXME - eventually we want to use the render accuracy as an indicator for the level of detail
|
||||
// to use in rendering.
|
||||
float renderAccuracy = args->_viewFrustum->calculateRenderAccuracy(bounds, args->_sizeScale, args->_boundaryLevelAdjust);
|
||||
return (renderAccuracy > 0.0f);
|
||||
};
|
||||
|
||||
// TODO: This is essentially the same logic used to render octree cells, but since models are more detailed then octree cells
|
||||
// I've added a voxelToModelRatio that adjusts how much closer to a model you have to be to see it.
|
||||
bool LODManager::shouldRenderMesh(float largestDimension, float distanceToCamera) {
|
||||
const float octreeToMeshRatio = 4.0f; // must be this many times closer to a mesh than a voxel to see it.
|
||||
float octreeSizeScale = getOctreeSizeScale();
|
||||
int boundaryLevelAdjust = getBoundaryLevelAdjust();
|
||||
float maxScale = (float)TREE_SCALE;
|
||||
float visibleDistanceAtMaxScale = boundaryDistanceForRenderLevel(boundaryLevelAdjust, octreeSizeScale) / octreeToMeshRatio;
|
||||
|
||||
if (_shouldRenderTableNeedsRebuilding) {
|
||||
_shouldRenderTable.clear();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
float closestScale = maxScale;
|
||||
float visibleDistanceAtClosestScale = visibleDistanceAtMaxScale;
|
||||
QMap<float, float>::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);
|
||||
}
|
||||
|
||||
void LODManager::setOctreeSizeScale(float sizeScale) {
|
||||
_octreeSizeScale = sizeScale;
|
||||
calculateAvatarLODDistanceMultiplier();
|
||||
_shouldRenderTableNeedsRebuilding = true;
|
||||
}
|
||||
|
||||
void LODManager::calculateAvatarLODDistanceMultiplier() {
|
||||
|
@ -372,7 +301,6 @@ void LODManager::calculateAvatarLODDistanceMultiplier() {
|
|||
|
||||
void LODManager::setBoundaryLevelAdjust(int boundaryLevelAdjust) {
|
||||
_boundaryLevelAdjust = boundaryLevelAdjust;
|
||||
_shouldRenderTableNeedsRebuilding = true;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -104,7 +104,6 @@ public:
|
|||
QString getLODStatsRenderText();
|
||||
|
||||
static bool shouldRender(const RenderArgs* args, const AABox& bounds);
|
||||
bool shouldRenderMesh(float largestDimension, float distanceToCamera);
|
||||
void autoAdjustLOD(float currentFPS);
|
||||
|
||||
void loadSettings();
|
||||
|
@ -136,9 +135,6 @@ private:
|
|||
SimpleMovingAverage _fpsAverageDownWindow = DOWN_SHIFT_SAMPLES_OF_FRAMES;
|
||||
SimpleMovingAverage _fpsAverageUpWindow = UP_SHIFT_SAMPLES_OF_FRAMES;
|
||||
|
||||
bool _shouldRenderTableNeedsRebuilding = true;
|
||||
QMap<float, float> _shouldRenderTable;
|
||||
|
||||
PIDController _renderDistanceController{};
|
||||
SimpleMovingAverage _renderDistanceAverage{ 10 };
|
||||
};
|
||||
|
|
|
@ -417,15 +417,6 @@ const FBXGeometry* EntityTreeRenderer::getCollisionGeometryForEntity(EntityItemP
|
|||
return result;
|
||||
}
|
||||
|
||||
float EntityTreeRenderer::getSizeScale() const {
|
||||
return _viewState->getSizeScale();
|
||||
}
|
||||
|
||||
int EntityTreeRenderer::getBoundaryLevelAdjust() const {
|
||||
return _viewState->getBoundaryLevelAdjust();
|
||||
}
|
||||
|
||||
|
||||
void EntityTreeRenderer::processEraseMessage(ReceivedMessage& message, const SharedNodePointer& sourceNode) {
|
||||
std::static_pointer_cast<EntityTree>(_tree)->processEraseMessage(message, sourceNode);
|
||||
}
|
||||
|
|
|
@ -41,8 +41,6 @@ public:
|
|||
virtual char getMyNodeType() const { return NodeType::EntityServer; }
|
||||
virtual PacketType getMyQueryMessageType() const { return PacketType::EntityQuery; }
|
||||
virtual PacketType getExpectedPacketType() const { return PacketType::EntityData; }
|
||||
virtual float getSizeScale() const;
|
||||
virtual int getBoundaryLevelAdjust() const;
|
||||
virtual void setTree(OctreePointer newTree);
|
||||
|
||||
void shutdown();
|
||||
|
|
|
@ -307,9 +307,42 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData
|
|||
if (!success || params.viewFrustum->cubeInFrustum(entityCube) == ViewFrustum::OUTSIDE) {
|
||||
includeThisEntity = false; // out of view, don't include it
|
||||
}
|
||||
|
||||
// Now check the size of the entity, it's possible that a "too small to see" entity is included in a
|
||||
// larger octree cell because of it's position (for example if it crosses the boundary of a cell it
|
||||
// pops to the next higher cell. So we want to check to see that the entity is large enough to be seen
|
||||
// before we consider including it.
|
||||
if (includeThisEntity) {
|
||||
AABox entityBounds = entity->getAABox(success);
|
||||
if (success) {
|
||||
auto renderAccuracy = params.viewFrustum->calculateRenderAccuracy(entityBounds,
|
||||
params.octreeElementSizeScale, params.boundaryLevelAdjust);
|
||||
|
||||
if (renderAccuracy <= 0.0f) {
|
||||
includeThisEntity = false; // too small, don't include it
|
||||
|
||||
#ifdef WANT_LOD_DEBUGGING
|
||||
qDebug() << "skipping entity - TOO SMALL - \n"
|
||||
<< "......id:" << entity->getID() << "\n"
|
||||
<< "....name:" << entity->getName() << "\n"
|
||||
<< "..bounds:" << entityBounds << "\n"
|
||||
<< "....cell:" << getAACube();
|
||||
#endif
|
||||
|
||||
}
|
||||
} else {
|
||||
includeThisEntity = false; // couldn't get box, don't include it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (includeThisEntity) {
|
||||
#ifdef WANT_LOD_DEBUGGING
|
||||
qDebug() << "including entity - \n"
|
||||
<< "......id:" << entity->getID() << "\n"
|
||||
<< "....name:" << entity->getName() << "\n"
|
||||
<< "....cell:" << getAACube();
|
||||
#endif
|
||||
indexesOfEntitiesToInclude << i;
|
||||
numberOfEntities++;
|
||||
}
|
||||
|
|
|
@ -50,10 +50,6 @@
|
|||
|
||||
QVector<QString> PERSIST_EXTENSIONS = {"svo", "json", "json.gz"};
|
||||
|
||||
float boundaryDistanceForRenderLevel(unsigned int renderLevel, float voxelSizeScale) {
|
||||
return voxelSizeScale / powf(2, renderLevel);
|
||||
}
|
||||
|
||||
Octree::Octree(bool shouldReaverage) :
|
||||
_rootElement(NULL),
|
||||
_isDirty(true),
|
||||
|
|
|
@ -385,6 +385,4 @@ protected:
|
|||
bool _isServer;
|
||||
};
|
||||
|
||||
float boundaryDistanceForRenderLevel(unsigned int renderLevel, float voxelSizeScale);
|
||||
|
||||
#endif // hifi_Octree_h
|
||||
|
|
|
@ -23,6 +23,12 @@ const int HALF_TREE_SCALE = TREE_SCALE / 2;
|
|||
// This controls the LOD. Larger number will make smaller voxels visible at greater distance.
|
||||
const float DEFAULT_OCTREE_SIZE_SCALE = TREE_SCALE * 400.0f;
|
||||
|
||||
// Since entities like models live inside of octree cells, and they themselves can have very small mesh parts,
|
||||
// we want to have some constant that controls have big a mesh part must be to render even if the octree cell itself
|
||||
// would be visible. This constanct controls that. It basically means you must be this many times closer to a mesh
|
||||
// than an octree cell to see the mesh.
|
||||
const float OCTREE_TO_MESH_RATIO = 4.0f;
|
||||
|
||||
// This is used in the LOD Tools to translate between the size scale slider and the values used to set the OctreeSizeScale
|
||||
const float MAX_LOD_SIZE_MULTIPLIER = 4000.0f;
|
||||
|
||||
|
|
|
@ -14,11 +14,7 @@
|
|||
#include "OctreeLogging.h"
|
||||
#include "OctreeHeadlessViewer.h"
|
||||
|
||||
OctreeHeadlessViewer::OctreeHeadlessViewer() :
|
||||
OctreeRenderer(),
|
||||
_voxelSizeScale(DEFAULT_OCTREE_SIZE_SCALE),
|
||||
_boundaryLevelAdjust(0),
|
||||
_maxPacketsPerSecond(DEFAULT_MAX_OCTREE_PPS)
|
||||
OctreeHeadlessViewer::OctreeHeadlessViewer() : OctreeRenderer()
|
||||
{
|
||||
_viewFrustum.setProjection(glm::perspective(glm::radians(DEFAULT_FIELD_OF_VIEW_DEGREES), DEFAULT_ASPECT_RATIO, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP));
|
||||
}
|
||||
|
@ -57,9 +53,8 @@ void OctreeHeadlessViewer::queryOctree() {
|
|||
_octreeQuery.setCameraFarClip(_viewFrustum.getFarClip());
|
||||
_octreeQuery.setCameraEyeOffsetPosition(glm::vec3());
|
||||
_octreeQuery.setKeyholeRadius(_viewFrustum.getKeyholeRadius());
|
||||
|
||||
_octreeQuery.setOctreeSizeScale(getVoxelSizeScale());
|
||||
_octreeQuery.setBoundaryLevelAdjust(getBoundaryLevelAdjust());
|
||||
_octreeQuery.setOctreeSizeScale(_voxelSizeScale);
|
||||
_octreeQuery.setBoundaryLevelAdjust(_boundaryLevelAdjust);
|
||||
|
||||
// Iterate all of the nodes, and get a count of how many voxel servers we have...
|
||||
int totalServers = 0;
|
||||
|
|
|
@ -59,7 +59,7 @@ public slots:
|
|||
|
||||
// getters for LOD and PPS
|
||||
float getVoxelSizeScale() const { return _voxelSizeScale; }
|
||||
int getBoundaryLevelAdjust() const override { return _boundaryLevelAdjust; }
|
||||
int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; }
|
||||
int getMaxPacketsPerSecond() const { return _maxPacketsPerSecond; }
|
||||
|
||||
unsigned getOctreeElementsCount() const { return _tree->getOctreeElementsCount(); }
|
||||
|
@ -68,9 +68,10 @@ private:
|
|||
ViewFrustum _viewFrustum;
|
||||
JurisdictionListener* _jurisdictionListener = nullptr;
|
||||
OctreeQuery _octreeQuery;
|
||||
float _voxelSizeScale;
|
||||
int _boundaryLevelAdjust;
|
||||
int _maxPacketsPerSecond;
|
||||
|
||||
float _voxelSizeScale { DEFAULT_OCTREE_SIZE_SCALE };
|
||||
int _boundaryLevelAdjust { 0 };
|
||||
int _maxPacketsPerSecond { DEFAULT_MAX_OCTREE_PPS };
|
||||
};
|
||||
|
||||
#endif // hifi_OctreeHeadlessViewer_h
|
||||
|
|
|
@ -39,8 +39,6 @@ public:
|
|||
virtual PacketType getMyQueryMessageType() const = 0;
|
||||
virtual PacketType getExpectedPacketType() const = 0;
|
||||
virtual void renderElement(OctreeElementPointer element, RenderArgs* args) { }
|
||||
virtual float getSizeScale() const { return DEFAULT_OCTREE_SIZE_SCALE; }
|
||||
virtual int getBoundaryLevelAdjust() const { return 0; }
|
||||
|
||||
virtual void setTree(OctreePointer newTree);
|
||||
|
||||
|
|
|
@ -750,3 +750,46 @@ void ViewFrustum::evalViewTransform(Transform& view) const {
|
|||
view.setTranslation(getPosition());
|
||||
view.setRotation(getOrientation());
|
||||
}
|
||||
|
||||
float ViewFrustum::calculateRenderAccuracy(const AABox& bounds, float octreeSizeScale, int boundaryLevelAdjust) const {
|
||||
float distanceToCamera = glm::length(bounds.calcCenter() - getPosition());
|
||||
float largestDimension = bounds.getLargestDimension();
|
||||
|
||||
const float maxScale = (float)TREE_SCALE;
|
||||
float visibleDistanceAtMaxScale = boundaryDistanceForRenderLevel(boundaryLevelAdjust, octreeSizeScale) / OCTREE_TO_MESH_RATIO;
|
||||
|
||||
static std::once_flag once;
|
||||
static QMap<float, float> shouldRenderTable;
|
||||
std::call_once(once, [&] {
|
||||
float SMALLEST_SCALE_IN_TABLE = 0.001f; // 1mm is plenty small
|
||||
float scale = maxScale;
|
||||
float factor = 1.0f;
|
||||
|
||||
while (scale > SMALLEST_SCALE_IN_TABLE) {
|
||||
scale /= 2.0f;
|
||||
factor /= 2.0f;
|
||||
shouldRenderTable[scale] = factor;
|
||||
}
|
||||
});
|
||||
|
||||
float closestScale = maxScale;
|
||||
float visibleDistanceAtClosestScale = visibleDistanceAtMaxScale;
|
||||
QMap<float, float>::const_iterator lowerBound = shouldRenderTable.lowerBound(largestDimension);
|
||||
if (lowerBound != shouldRenderTable.constEnd()) {
|
||||
closestScale = lowerBound.key();
|
||||
visibleDistanceAtClosestScale = visibleDistanceAtMaxScale * lowerBound.value();
|
||||
}
|
||||
|
||||
if (closestScale < largestDimension) {
|
||||
visibleDistanceAtClosestScale *= 2.0f;
|
||||
}
|
||||
|
||||
// FIXME - for now, it's either visible or not visible. We want to adjust this to eventually return
|
||||
// a floating point for objects that have small angular size to indicate that they may be rendered
|
||||
// with lower preciscion
|
||||
return (distanceToCamera <= visibleDistanceAtClosestScale) ? 1.0f : 0.0f;
|
||||
}
|
||||
|
||||
float boundaryDistanceForRenderLevel(unsigned int renderLevel, float voxelSizeScale) {
|
||||
return voxelSizeScale / powf(2, renderLevel);
|
||||
}
|
||||
|
|
|
@ -108,6 +108,11 @@ public:
|
|||
void evalProjectionMatrix(glm::mat4& proj) const;
|
||||
void evalViewTransform(Transform& view) const;
|
||||
|
||||
/// renderAccuracy represents a floating point "visibility" of an object based on it's view from the camera. At a simple
|
||||
/// level it returns 0.0f for things that are so small for the current settings that they could not be visible.
|
||||
float calculateRenderAccuracy(const AABox& bounds, float octreeSizeScale = DEFAULT_OCTREE_SIZE_SCALE,
|
||||
int boundaryLevelAdjust = 0) const;
|
||||
|
||||
private:
|
||||
// Used for keyhole calculations
|
||||
ViewFrustum::location pointInKeyhole(const glm::vec3& point) const;
|
||||
|
@ -152,5 +157,6 @@ private:
|
|||
glm::mat4 _ourModelViewProjectionMatrix;
|
||||
};
|
||||
|
||||
float boundaryDistanceForRenderLevel(unsigned int renderLevel, float voxelSizeScale);
|
||||
|
||||
#endif // hifi_ViewFrustum_h
|
||||
|
|
|
@ -41,8 +41,6 @@ public:
|
|||
|
||||
virtual QThread* getMainThread() = 0;
|
||||
|
||||
virtual float getSizeScale() const = 0;
|
||||
virtual int getBoundaryLevelAdjust() const = 0;
|
||||
virtual PickRay computePickRay(float x, float y) const = 0;
|
||||
|
||||
virtual glm::vec3 getAvatarPosition() const = 0;
|
||||
|
|
Loading…
Reference in a new issue