mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-15 08:40:00 +02:00
add a heuristic for deciding when it's safe to enable bullet
This commit is contained in:
parent
83494c4a96
commit
e4c91e5064
3 changed files with 78 additions and 29 deletions
|
@ -3197,7 +3197,19 @@ void Application::cameraMenuChanged() {
|
|||
}
|
||||
}
|
||||
|
||||
void Application::resetPhysicsReadyInformation() {
|
||||
// we've changed domains or cleared out caches or something. we no longer know enough about the
|
||||
// collision information of nearby entities to make running bullet be safe.
|
||||
_fullSceneReceivedCounter = 0;
|
||||
_fullSceneCounterAtLastPhysicsCheck = 0;
|
||||
_nearbyEntitiesCountAtLastPhysicsCheck = 0;
|
||||
_nearbyEntitiesStabilityCount = 0;
|
||||
_physicsEnabled = false;
|
||||
}
|
||||
|
||||
|
||||
void Application::reloadResourceCaches() {
|
||||
resetPhysicsReadyInformation();
|
||||
// Clear entities out of view frustum
|
||||
_viewFrustum.setPosition(glm::vec3(0.0f, 0.0f, TREE_SCALE));
|
||||
_viewFrustum.setOrientation(glm::quat());
|
||||
|
@ -3254,21 +3266,34 @@ void Application::update(float deltaTime) {
|
|||
|
||||
updateLOD();
|
||||
|
||||
if (!_physicsEnabled && _processOctreeStatsCounter > 0) {
|
||||
if (!_physicsEnabled) {
|
||||
// we haven't yet enabled physics. we wait until we think we have all the collision information
|
||||
// for nearby entities before starting bullet up.
|
||||
quint64 now = usecTimestampNow();
|
||||
bool timeout = false;
|
||||
const int PHYSICS_CHECK_TIMEOUT = 2 * USECS_PER_SECOND;
|
||||
if (_lastPhysicsCheckTime > 0 && now - _lastPhysicsCheckTime > PHYSICS_CHECK_TIMEOUT) {
|
||||
timeout = true;
|
||||
}
|
||||
|
||||
// process octree stats packets are sent in between full sends of a scene.
|
||||
// We keep physics disabled until we've received a full scene and everything near the avatar in that
|
||||
// scene is ready to compute its collision shape.
|
||||
if (timeout || _fullSceneReceivedCounter > _fullSceneCounterAtLastPhysicsCheck) {
|
||||
// we've received a new full-scene octree stats packet, or it's been long enough to try again anyway
|
||||
_lastPhysicsCheckTime = now;
|
||||
_fullSceneCounterAtLastPhysicsCheck = _fullSceneReceivedCounter;
|
||||
|
||||
if (nearbyEntitiesAreReadyForPhysics()) {
|
||||
_physicsEnabled = true;
|
||||
getMyAvatar()->updateMotionBehaviorFromMenu();
|
||||
} else {
|
||||
auto characterController = getMyAvatar()->getCharacterController();
|
||||
if (characterController) {
|
||||
// if we have a character controller, disable it here so the avatar doesn't get stuck due to
|
||||
// a non-loading collision hull.
|
||||
characterController->setEnabled(false);
|
||||
// process octree stats packets are sent in between full sends of a scene (this isn't currently true).
|
||||
// We keep physics disabled until we've received a full scene and everything near the avatar in that
|
||||
// scene is ready to compute its collision shape.
|
||||
if (nearbyEntitiesAreReadyForPhysics()) {
|
||||
_physicsEnabled = true;
|
||||
getMyAvatar()->updateMotionBehaviorFromMenu();
|
||||
} else {
|
||||
auto characterController = getMyAvatar()->getCharacterController();
|
||||
if (characterController) {
|
||||
// if we have a character controller, disable it here so the avatar doesn't get stuck due to
|
||||
// a non-loading collision hull.
|
||||
characterController->setEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4153,7 +4178,7 @@ void Application::clearDomainOctreeDetails() {
|
|||
qCDebug(interfaceapp) << "Clearing domain octree details...";
|
||||
// reset the environment so that we don't erroneously end up with multiple
|
||||
|
||||
_physicsEnabled = false;
|
||||
resetPhysicsReadyInformation();
|
||||
|
||||
// reset our node to stats and node to jurisdiction maps... since these must be changing...
|
||||
_entityServerJurisdictions.withWriteLock([&] {
|
||||
|
@ -4177,7 +4202,7 @@ void Application::domainChanged(const QString& domainHostname) {
|
|||
updateWindowTitle();
|
||||
clearDomainOctreeDetails();
|
||||
// disable physics until we have enough information about our new location to not cause craziness.
|
||||
_physicsEnabled = false;
|
||||
resetPhysicsReadyInformation();
|
||||
}
|
||||
|
||||
|
||||
|
@ -4310,15 +4335,31 @@ bool Application::nearbyEntitiesAreReadyForPhysics() {
|
|||
entityTree->findEntities(box, entities);
|
||||
});
|
||||
|
||||
foreach (EntityItemPointer entity, entities) {
|
||||
if (entity->shouldBePhysical() && !entity->isReadyToComputeShape()) {
|
||||
static QString repeatedMessage =
|
||||
LogHandler::getInstance().addRepeatedMessageRegex("Physics disabled until entity loads: .*");
|
||||
qCDebug(interfaceapp) << "Physics disabled until entity loads: " << entity->getID() << entity->getName();
|
||||
return false;
|
||||
}
|
||||
// For reasons I haven't found, we don't necessarily have the full scene when we receive a stats packet. Apply
|
||||
// a heuristic to try to decide when we actually know about all of the nearby entities.
|
||||
int nearbyCount = entities.size();
|
||||
if (nearbyCount == _nearbyEntitiesCountAtLastPhysicsCheck) {
|
||||
_nearbyEntitiesStabilityCount++;
|
||||
} else {
|
||||
_nearbyEntitiesStabilityCount = 0;
|
||||
}
|
||||
return true;
|
||||
_nearbyEntitiesCountAtLastPhysicsCheck = nearbyCount;
|
||||
|
||||
const uint32_t MINIMUM_NEARBY_ENTITIES_STABILITY_COUNT = 3;
|
||||
if (_nearbyEntitiesStabilityCount >= MINIMUM_NEARBY_ENTITIES_STABILITY_COUNT) {
|
||||
// We've seen the same number of nearby entities for several stats packets in a row. assume we've got all
|
||||
// the local entities.
|
||||
foreach (EntityItemPointer entity, entities) {
|
||||
if (entity->shouldBePhysical() && !entity->isReadyToComputeShape()) {
|
||||
static QString repeatedMessage =
|
||||
LogHandler::getInstance().addRepeatedMessageRegex("Physics disabled until entity loads: .*");
|
||||
qCDebug(interfaceapp) << "Physics disabled until entity loads: " << entity->getID() << entity->getName();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int Application::processOctreeStats(ReceivedMessage& message, SharedNodePointer sendingNode) {
|
||||
|
@ -4335,6 +4376,10 @@ int Application::processOctreeStats(ReceivedMessage& message, SharedNodePointer
|
|||
OctreeSceneStats& octreeStats = _octreeServerSceneStats[nodeUUID];
|
||||
statsMessageLength = octreeStats.unpackFromPacket(message);
|
||||
|
||||
if (octreeStats.isFullScene()) {
|
||||
_fullSceneReceivedCounter++;
|
||||
}
|
||||
|
||||
// see if this is the first we've heard of this node...
|
||||
NodeToJurisdictionMap* jurisdiction = nullptr;
|
||||
QString serverType;
|
||||
|
@ -4366,8 +4411,6 @@ int Application::processOctreeStats(ReceivedMessage& message, SharedNodePointer
|
|||
});
|
||||
});
|
||||
|
||||
_processOctreeStatsCounter++;
|
||||
|
||||
return statsMessageLength;
|
||||
}
|
||||
|
||||
|
|
|
@ -271,6 +271,8 @@ public slots:
|
|||
void toggleOverlays();
|
||||
void setOverlaysVisible(bool visible);
|
||||
|
||||
void resetPhysicsReadyInformation();
|
||||
|
||||
void reloadResourceCaches();
|
||||
|
||||
void updateHeartbeat() const;
|
||||
|
@ -514,7 +516,11 @@ private:
|
|||
std::map<void*, std::function<void()>> _preRenderLambdas;
|
||||
std::mutex _preRenderLambdasLock;
|
||||
|
||||
std::atomic<uint32_t> _processOctreeStatsCounter { 0 };
|
||||
std::atomic<uint32_t> _fullSceneReceivedCounter { 0 }; // how many times have we received a full-scene octree stats packet
|
||||
uint32_t _fullSceneCounterAtLastPhysicsCheck { 0 }; // _fullSceneReceivedCounter last time we checked physics ready
|
||||
uint32_t _nearbyEntitiesCountAtLastPhysicsCheck { 0 }; // how many in-range entities last time we checked physics ready
|
||||
uint32_t _nearbyEntitiesStabilityCount { 0 }; // how many times has _nearbyEntitiesCountAtLastPhysicsCheck been the same
|
||||
quint64 _lastPhysicsCheckTime { 0 }; // when did we last check to see if physics was ready
|
||||
|
||||
bool _keyboardDeviceHasFocus { true };
|
||||
|
||||
|
|
|
@ -699,7 +699,7 @@ void EntityTreeElement::getEntities(const glm::vec3& searchPosition, float searc
|
|||
|
||||
// if the sphere doesn't intersect with our world frame AABox, we don't need to consider the more complex case
|
||||
glm::vec3 penetration;
|
||||
if (success && entityBox.findSpherePenetration(searchPosition, searchRadius, penetration)) {
|
||||
if (!success || entityBox.findSpherePenetration(searchPosition, searchRadius, penetration)) {
|
||||
|
||||
glm::vec3 dimensions = entity->getDimensions();
|
||||
|
||||
|
@ -764,7 +764,7 @@ void EntityTreeElement::getEntities(const AACube& cube, QVector<EntityItemPointe
|
|||
//
|
||||
|
||||
// If the entities AABox touches the search cube then consider it to be found
|
||||
if (success && entityBox.touches(cube)) {
|
||||
if (!success || entityBox.touches(cube)) {
|
||||
foundEntities.push_back(entity);
|
||||
}
|
||||
});
|
||||
|
@ -790,7 +790,7 @@ void EntityTreeElement::getEntities(const AABox& box, QVector<EntityItemPointer>
|
|||
//
|
||||
|
||||
// If the entities AABox touches the search cube then consider it to be found
|
||||
if (success && entityBox.touches(box)) {
|
||||
if (!success || entityBox.touches(box)) {
|
||||
foundEntities.push_back(entity);
|
||||
}
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue