mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-05 02:50:23 +02:00
fixed bugs in MovingEntitiesOperator, improved getDistanceToBottomOfEntity, isRestingOnSurface
This commit is contained in:
parent
77dff69805
commit
54ef5d4698
8 changed files with 176 additions and 46 deletions
|
@ -29,7 +29,7 @@ const float EntityItem::DEFAULT_MASS = 1.0f;
|
|||
const float EntityItem::DEFAULT_LIFETIME = EntityItem::IMMORTAL;
|
||||
const float EntityItem::DEFAULT_DAMPING = 0.5f;
|
||||
const glm::vec3 EntityItem::NO_VELOCITY = glm::vec3(0, 0, 0);
|
||||
const float EntityItem::EPSILON_VELOCITY_LENGTH = (1.0f / 10000.0f) / (float)TREE_SCALE; // really small
|
||||
const float EntityItem::EPSILON_VELOCITY_LENGTH = (1.0f / 1000.0f) / (float)TREE_SCALE; // really small: 1mm/second
|
||||
const glm::vec3 EntityItem::DEFAULT_VELOCITY = EntityItem::NO_VELOCITY;
|
||||
const glm::vec3 EntityItem::NO_GRAVITY = glm::vec3(0, 0, 0);
|
||||
const glm::vec3 EntityItem::REGULAR_GRAVITY = glm::vec3(0, (-9.8f / TREE_SCALE), 0);
|
||||
|
@ -499,23 +499,57 @@ void EntityItem::adjustEditPacketForClockSkew(unsigned char* editPacketBuffer, s
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: we probably want to change this to make "down" be the direction of the entity's gravity vector
|
||||
// for now, this is always true DOWN even if entity has non-down gravity.
|
||||
// TODO: the old code had "&& _velocity.y >= -EPSILON && _velocity.y <= EPSILON" --- what was I thinking?
|
||||
bool EntityItem::isRestingOnSurface() const {
|
||||
// TODO: change this to support registration point
|
||||
glm::vec3 downwardVelocity = glm::vec3(0.0f, _velocity.y, 0.0f);
|
||||
|
||||
return _position.y <= getDistanceToBottomOfEntity()
|
||||
&& _velocity.y >= -EPSILON && _velocity.y <= EPSILON
|
||||
&& (glm::length(downwardVelocity) <= EPSILON_VELOCITY_LENGTH)
|
||||
&& _gravity.y < 0.0f;
|
||||
}
|
||||
|
||||
void EntityItem::update(const quint64& updateTime) {
|
||||
bool wantDebug = false;
|
||||
bool wantDebug = true;
|
||||
|
||||
float timeElapsed = (float)(updateTime - _lastUpdated) / (float)(USECS_PER_SECOND);
|
||||
|
||||
if (wantDebug) {
|
||||
qDebug() << "********** EntityItem::update()";
|
||||
qDebug() << " entity ID=" << getEntityItemID();
|
||||
qDebug() << " updateTime=" << updateTime;
|
||||
qDebug() << " _lastUpdated=" << _lastUpdated;
|
||||
qDebug() << " timeElapsed=" << timeElapsed;
|
||||
qDebug() << " hasVelocity=" << hasVelocity();
|
||||
qDebug() << " hasGravity=" << hasGravity();
|
||||
qDebug() << " isRestingOnSurface=" << isRestingOnSurface();
|
||||
qDebug() << " hasAngularVelocity=" << hasAngularVelocity();
|
||||
qDebug() << " getAngularVelocity=" << getAngularVelocity();
|
||||
qDebug() << " isMortal=" << isMortal();
|
||||
qDebug() << " getAge()=" << getAge();
|
||||
qDebug() << " getLifetime()=" << getLifetime();
|
||||
|
||||
|
||||
if (hasVelocity() || (hasGravity() && !isRestingOnSurface())) {
|
||||
qDebug() << " MOVING...=";
|
||||
qDebug() << " hasVelocity=" << hasVelocity();
|
||||
qDebug() << " hasGravity=" << hasGravity();
|
||||
qDebug() << " isRestingOnSurface=" << isRestingOnSurface();
|
||||
qDebug() << " hasAngularVelocity=" << hasAngularVelocity();
|
||||
qDebug() << " getAngularVelocity=" << getAngularVelocity();
|
||||
}
|
||||
if (hasAngularVelocity()) {
|
||||
qDebug() << " CHANGING...=";
|
||||
qDebug() << " hasAngularVelocity=" << hasAngularVelocity();
|
||||
qDebug() << " getAngularVelocity=" << getAngularVelocity();
|
||||
}
|
||||
if (isMortal()) {
|
||||
qDebug() << " MORTAL...=";
|
||||
qDebug() << " isMortal=" << isMortal();
|
||||
qDebug() << " getAge()=" << getAge();
|
||||
qDebug() << " getLifetime()=" << getLifetime();
|
||||
}
|
||||
}
|
||||
|
||||
_lastUpdated = updateTime;
|
||||
|
@ -562,7 +596,8 @@ void EntityItem::update(const quint64& updateTime) {
|
|||
qDebug() << " old AACube:" << getMaximumAACube();
|
||||
qDebug() << " old position:" << position;
|
||||
qDebug() << " old velocity:" << velocity;
|
||||
qDebug() << " getDistanceToBottomOfEntity():" << getDistanceToBottomOfEntity();
|
||||
qDebug() << " old getAABox:" << getAABox();
|
||||
qDebug() << " getDistanceToBottomOfEntity():" << getDistanceToBottomOfEntity() * (float)TREE_SCALE << " in meters";
|
||||
qDebug() << " newPosition:" << newPosition;
|
||||
qDebug() << " glm::distance(newPosition, position):" << glm::distance(newPosition, position);
|
||||
}
|
||||
|
@ -604,21 +639,23 @@ void EntityItem::update(const quint64& updateTime) {
|
|||
|
||||
if (wantDebug) {
|
||||
qDebug() << " velocity AFTER dampingResistance:" << velocity;
|
||||
qDebug() << " glm::length(velocity):" << glm::length(velocity);
|
||||
qDebug() << " EPSILON_VELOCITY_LENGTH:" << EPSILON_VELOCITY_LENGTH;
|
||||
}
|
||||
|
||||
// round velocity to zero if it's close enough...
|
||||
if (glm::length(velocity) <= EPSILON_VELOCITY_LENGTH) {
|
||||
velocity = NO_VELOCITY;
|
||||
}
|
||||
|
||||
setPosition(position);
|
||||
setVelocity(velocity);
|
||||
|
||||
if (wantDebug) {
|
||||
qDebug() << " new position:" << position;
|
||||
qDebug() << " new velocity:" << velocity;
|
||||
}
|
||||
setPosition(position);
|
||||
setVelocity(velocity);
|
||||
if (wantDebug) {
|
||||
qDebug() << " new AACube:" << getMaximumAACube();
|
||||
qDebug() << " old getAABox:" << getAABox();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -722,21 +759,8 @@ float EntityItem::getSize() const {
|
|||
}
|
||||
|
||||
float EntityItem::getDistanceToBottomOfEntity() const {
|
||||
// the AABox from getAABox() is the true minimum bounding box for the entity
|
||||
// so it's minimum y is indeed the distance to the bottom of the entity
|
||||
glm::vec3 minimumPoint = getAABox().getMinimumPoint();
|
||||
return minimumPoint.y;
|
||||
}
|
||||
|
||||
// TODO: doesn't this need to handle rotation?
|
||||
glm::vec3 EntityItem::getMinimumPoint() const {
|
||||
return _position - (_dimensions * _registrationPoint);
|
||||
}
|
||||
|
||||
// TODO: doesn't this need to handle rotation?
|
||||
glm::vec3 EntityItem::getMaximumPoint() const {
|
||||
glm::vec3 registrationRemainder = glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint;
|
||||
return _position + (_dimensions * registrationRemainder);
|
||||
return getPosition().y - minimumPoint.y;
|
||||
}
|
||||
|
||||
// TODO: doesn't this need to handle rotation?
|
||||
|
|
|
@ -196,8 +196,6 @@ public:
|
|||
|
||||
// position, size, and bounds related helpers
|
||||
float getSize() const; /// get maximum dimension in domain scale units (0.0 - 1.0)
|
||||
glm::vec3 getMinimumPoint() const;
|
||||
glm::vec3 getMaximumPoint() const;
|
||||
AACube getMaximumAACube() const;
|
||||
AACube getMinimumAACube() const;
|
||||
AABox getAABox() const; /// axis aligned bounding box in domain scale units (0.0 - 1.0)
|
||||
|
|
|
@ -659,6 +659,7 @@ void EntityTree::updateMovingEntities(quint64 now, QSet<EntityItemID>& entitiesT
|
|||
// check to see if this movement has sent the entity outside of the domain.
|
||||
AACube domainBounds(glm::vec3(0.0f,0.0f,0.0f), 1.0f);
|
||||
if (!domainBounds.touches(newCube)) {
|
||||
qDebug() << "Entity " << thisEntity->getEntityItemID() << " moved out of domain bounds.";
|
||||
entitiesToDelete << thisEntity->getEntityItemID();
|
||||
entitiesBecomingStatic << thisEntity;
|
||||
} else {
|
||||
|
|
|
@ -410,30 +410,18 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData
|
|||
}
|
||||
|
||||
bool EntityTreeElement::containsEntityBounds(const EntityItem* entity) const {
|
||||
// Here we have a choice to make, do we want to "tight fit" the actual minimum for the
|
||||
// entity into the the element, or do we want to use the entities "relaxed" bounds
|
||||
// which can handle all potential rotations?
|
||||
// the getMaximumAACube is the relaxed form.
|
||||
return containsBounds(entity->getMaximumAACube());
|
||||
}
|
||||
|
||||
bool EntityTreeElement::bestFitEntityBounds(const EntityItem* entity) const {
|
||||
// Here we have a choice to make, do we want to "tight fit" the actual minimum for the
|
||||
// entity into the the element, or do we want to use the entities "relaxed" bounds
|
||||
// which can handle all potential rotations?
|
||||
// the getMaximumAACube is the relaxed form.
|
||||
return bestFitBounds(entity->getMaximumAACube());
|
||||
}
|
||||
|
||||
bool EntityTreeElement::containsBounds(const EntityItemProperties& properties) const {
|
||||
// TODO: this needs to be updated to have the similar behavior support for registration point and rotation
|
||||
// as EntityItem does
|
||||
return containsBounds(properties.getMaximumAACubeInTreeUnits());
|
||||
}
|
||||
|
||||
bool EntityTreeElement::bestFitBounds(const EntityItemProperties& properties) const {
|
||||
// TODO: this needs to be updated to have the similar behavior support for registration point and rotation
|
||||
// as EntityItem does
|
||||
return bestFitBounds(properties.getMaximumAACubeInTreeUnits());
|
||||
}
|
||||
|
||||
|
|
|
@ -20,21 +20,53 @@ MovingEntitiesOperator::MovingEntitiesOperator(EntityTree* tree) :
|
|||
_changeTime(usecTimestampNow()),
|
||||
_foundOldCount(0),
|
||||
_foundNewCount(0),
|
||||
_lookingCount(0)
|
||||
_lookingCount(0),
|
||||
_wantDebug(false)
|
||||
{
|
||||
}
|
||||
|
||||
MovingEntitiesOperator::~MovingEntitiesOperator() {
|
||||
if (_wantDebug) {
|
||||
bool stopExecution = false;
|
||||
qDebug() << "MovingEntitiesOperator::~MovingEntitiesOperator() -----------------------------";
|
||||
qDebug() << " _lookingCount:" << _lookingCount;
|
||||
qDebug() << " _foundOldCount:" << _foundOldCount;
|
||||
qDebug() << " _foundNewCount:" << _foundNewCount;
|
||||
if (_foundOldCount < _lookingCount) {
|
||||
qDebug() << " FAILURE: **** _foundOldCount < _lookingCount ******";
|
||||
stopExecution = true;
|
||||
}
|
||||
if (_foundNewCount < _lookingCount) {
|
||||
qDebug() << " FAILURE: **** _foundNewCount < _lookingCount ******";
|
||||
stopExecution = true;
|
||||
}
|
||||
qDebug() << "--------------------------------------------------------------------------";
|
||||
if(stopExecution) {
|
||||
debug();
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MovingEntitiesOperator::addEntityToMoveList(EntityItem* entity, const AACube& oldCube, const AACube& newCube) {
|
||||
EntityTreeElement* oldContainingElement = _tree->getContainingElement(entity->getEntityItemID());
|
||||
AABox newBox = newCube.clamp(0.0f, 1.0f);
|
||||
AABox newCubeClamped = newCube.clamp(0.0f, 1.0f);
|
||||
AABox oldCubeClamped = oldCube.clamp(0.0f, 1.0f);
|
||||
|
||||
if (_wantDebug) {
|
||||
qDebug() << "MovingEntitiesOperator::addEntityToMoveList() -----------------------------";
|
||||
qDebug() << " oldCube:" << oldCube;
|
||||
qDebug() << " newCube:" << newCube;
|
||||
qDebug() << " oldCubeClamped:" << oldCubeClamped;
|
||||
qDebug() << " newCubeClamped:" << newCubeClamped;
|
||||
qDebug() << " oldContainingElement:" << oldContainingElement->getAACube();
|
||||
qDebug() << " oldContainingElement->bestFitBounds(newCubeClamped):" << oldContainingElement->bestFitBounds(newCubeClamped);
|
||||
}
|
||||
|
||||
// If the original containing element is the best fit for the requested newCube locations then
|
||||
// we don't actually need to add the entity for moving and we can short circuit all this work
|
||||
if (!oldContainingElement->bestFitBounds(newBox)) {
|
||||
if (!oldContainingElement->bestFitBounds(newCubeClamped)) {
|
||||
// check our tree, to determine if this entity is known
|
||||
EntityToMoveDetails details;
|
||||
details.oldContainingElement = oldContainingElement;
|
||||
|
@ -44,9 +76,29 @@ void MovingEntitiesOperator::addEntityToMoveList(EntityItem* entity, const AACub
|
|||
details.newFound = false;
|
||||
details.oldCube = oldCube;
|
||||
details.newCube = newCube;
|
||||
details.newBox = newBox;
|
||||
details.oldCubeClamped = oldCubeClamped;
|
||||
details.newCubeClamped = newCubeClamped;
|
||||
_entitiesToMove << details;
|
||||
_lookingCount++;
|
||||
|
||||
if (_wantDebug) {
|
||||
qDebug() << "MovingEntitiesOperator::addEntityToMoveList() -----------------------------";
|
||||
qDebug() << " details.entity:" << details.entity->getEntityItemID();
|
||||
qDebug() << " details.oldContainingElementCube:" << details.oldContainingElementCube;
|
||||
qDebug() << " details.oldCube:" << details.oldCube;
|
||||
qDebug() << " details.newCube:" << details.newCube;
|
||||
qDebug() << " details.newCubeClamped:" << details.newCubeClamped;
|
||||
qDebug() << " _lookingCount:" << _lookingCount;
|
||||
qDebug() << "--------------------------------------------------------------------------";
|
||||
}
|
||||
} else {
|
||||
if (_wantDebug) {
|
||||
qDebug() << " oldContainingElement->bestFitBounds(newCubeClamped) IS BEST FIT... NOTHING TO DO";
|
||||
}
|
||||
}
|
||||
|
||||
if (_wantDebug) {
|
||||
qDebug() << "--------------------------------------------------------------------------";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,11 +110,29 @@ bool MovingEntitiesOperator::shouldRecurseSubTree(OctreeElement* element) {
|
|||
// check the bounds
|
||||
if (_entitiesToMove.size() > 0) {
|
||||
AACube elementCube = element->getAACube();
|
||||
int detailIndex = 0;
|
||||
foreach(const EntityToMoveDetails& details, _entitiesToMove) {
|
||||
if (elementCube.contains(details.oldCube) || elementCube.contains(details.newCube)) {
|
||||
|
||||
if (_wantDebug) {
|
||||
qDebug() << "MovingEntitiesOperator::shouldRecurseSubTree() details["<< detailIndex <<"]-----------------------------";
|
||||
qDebug() << " element:" << element->getAACube();
|
||||
qDebug() << " details.entity:" << details.entity->getEntityItemID();
|
||||
qDebug() << " details.oldContainingElementCube:" << details.oldContainingElementCube;
|
||||
qDebug() << " details.oldCube:" << details.oldCube;
|
||||
qDebug() << " details.newCube:" << details.newCube;
|
||||
qDebug() << " details.newCubeClamped:" << details.newCubeClamped;
|
||||
qDebug() << " elementCube.contains(details.oldCube)" << elementCube.contains(details.oldCube);
|
||||
qDebug() << " elementCube.contains(details.newCube)" << elementCube.contains(details.newCube);
|
||||
qDebug() << " elementCube.contains(details.oldCubeClamped)" << elementCube.contains(details.oldCubeClamped);
|
||||
qDebug() << " elementCube.contains(details.newCubeClamped)" << elementCube.contains(details.newCubeClamped);
|
||||
qDebug() << "--------------------------------------------------------------------------";
|
||||
}
|
||||
|
||||
if (elementCube.contains(details.oldCubeClamped) || elementCube.contains(details.newCubeClamped)) {
|
||||
containsEntity = true;
|
||||
break; // if it contains at least one, we're good to go
|
||||
}
|
||||
detailIndex++;
|
||||
}
|
||||
}
|
||||
return containsEntity;
|
||||
|
@ -87,13 +157,36 @@ bool MovingEntitiesOperator::preRecursion(OctreeElement* element) {
|
|||
if (keepSearching && shouldRecurseSubTree(element)) {
|
||||
|
||||
// check against each of our search entities
|
||||
int detailIndex = 0;
|
||||
foreach(const EntityToMoveDetails& details, _entitiesToMove) {
|
||||
|
||||
if (_wantDebug) {
|
||||
qDebug() << "MovingEntitiesOperator::preRecursion() details["<< detailIndex <<"]-----------------------------";
|
||||
qDebug() << " entityTreeElement:" << entityTreeElement->getAACube();
|
||||
qDebug() << " entityTreeElement->bestFitBounds(details.newCube):" << entityTreeElement->bestFitBounds(details.newCube);
|
||||
qDebug() << " details.entity:" << details.entity->getEntityItemID();
|
||||
qDebug() << " details.oldContainingElementCube:" << details.oldContainingElementCube;
|
||||
qDebug() << " entityTreeElement:" << entityTreeElement;
|
||||
qDebug() << " details.oldCube:" << details.oldCube;
|
||||
qDebug() << " details.newCube:" << details.newCube;
|
||||
qDebug() << " details.newCubeClamped:" << details.newCubeClamped;
|
||||
qDebug() << " _lookingCount:" << _lookingCount;
|
||||
qDebug() << " _foundOldCount:" << _foundOldCount;
|
||||
qDebug() << "--------------------------------------------------------------------------";
|
||||
}
|
||||
|
||||
|
||||
// If this is one of the old elements we're looking for, then ask it to remove the old entity
|
||||
if (!details.oldFound && entityTreeElement == details.oldContainingElement) {
|
||||
entityTreeElement->removeEntityItem(details.entity);
|
||||
_foundOldCount++;
|
||||
//details.oldFound = true; // TODO: would be nice to add this optimization
|
||||
if (_wantDebug) {
|
||||
qDebug() << "MovingEntitiesOperator::preRecursion() -----------------------------";
|
||||
qDebug() << " FOUND OLD - REMOVING";
|
||||
qDebug() << " entityTreeElement == details.oldContainingElement";
|
||||
qDebug() << "--------------------------------------------------------------------------";
|
||||
}
|
||||
}
|
||||
|
||||
// If this element is the best fit for the new bounds of this entity then add the entity to the element
|
||||
|
@ -103,7 +196,14 @@ bool MovingEntitiesOperator::preRecursion(OctreeElement* element) {
|
|||
_tree->setContainingElement(entityItemID, entityTreeElement);
|
||||
_foundNewCount++;
|
||||
//details.newFound = true; // TODO: would be nice to add this optimization
|
||||
if (_wantDebug) {
|
||||
qDebug() << "MovingEntitiesOperator::preRecursion() -----------------------------";
|
||||
qDebug() << " FOUND NEW - ADDING";
|
||||
qDebug() << " entityTreeElement->bestFitBounds(details.newCube)";
|
||||
qDebug() << "--------------------------------------------------------------------------";
|
||||
}
|
||||
}
|
||||
detailIndex++;
|
||||
}
|
||||
// if we haven't found all of our search for entities, then keep looking
|
||||
keepSearching = (_foundOldCount < _lookingCount) || (_foundNewCount < _lookingCount);
|
||||
|
@ -163,9 +263,9 @@ OctreeElement* MovingEntitiesOperator::possiblyCreateChildAt(OctreeElement* elem
|
|||
foreach(const EntityToMoveDetails& details, _entitiesToMove) {
|
||||
|
||||
// if the scale of our desired cube is smaller than our children, then consider making a child
|
||||
if (details.newBox.getLargestDimension() <= childElementScale) {
|
||||
if (details.newCubeClamped.getLargestDimension() <= childElementScale) {
|
||||
|
||||
int indexOfChildContainingNewEntity = element->getMyChildContaining(details.newBox);
|
||||
int indexOfChildContainingNewEntity = element->getMyChildContaining(details.newCubeClamped);
|
||||
|
||||
// If the childIndex we were asked if we wanted to create contains this newCube,
|
||||
// then we will create this branch and continue. We can exit this loop immediately
|
||||
|
|
|
@ -17,7 +17,8 @@ public:
|
|||
EntityItem* entity;
|
||||
AACube oldCube;
|
||||
AACube newCube;
|
||||
AABox newBox;
|
||||
AABox oldCubeClamped;
|
||||
AABox newCubeClamped;
|
||||
EntityTreeElement* oldContainingElement;
|
||||
AACube oldContainingElementCube;
|
||||
bool oldFound;
|
||||
|
@ -50,6 +51,8 @@ private:
|
|||
int _foundNewCount;
|
||||
int _lookingCount;
|
||||
bool shouldRecurseSubTree(OctreeElement* element);
|
||||
|
||||
bool _wantDebug;
|
||||
};
|
||||
|
||||
#endif // hifi_MovingEntitiesOperator_h
|
||||
|
|
|
@ -31,7 +31,8 @@ UpdateEntityOperator::UpdateEntityOperator(EntityTree* tree,
|
|||
_dontMove(false), // assume we'll be moving
|
||||
_changeTime(usecTimestampNow()),
|
||||
_oldEntityCube(),
|
||||
_newEntityCube()
|
||||
_newEntityCube(),
|
||||
_wantDebug(false)
|
||||
{
|
||||
// caller must have verified existence of containingElement and oldEntity
|
||||
assert(_containingElement && _existingEntity);
|
||||
|
@ -80,6 +81,19 @@ UpdateEntityOperator::UpdateEntityOperator(EntityTree* tree,
|
|||
}
|
||||
|
||||
_newEntityBox = _newEntityCube.clamp(0.0f, 1.0f); // clamp to domain bounds
|
||||
|
||||
|
||||
if (_wantDebug) {
|
||||
qDebug() << "UpdateEntityOperator::UpdateEntityOperator() -----------------------------";
|
||||
qDebug() << " _entityItemID:" << _entityItemID;
|
||||
qDebug() << " _containingElementCube:" << _containingElementCube;
|
||||
qDebug() << " _oldEntityCube:" << _oldEntityCube;
|
||||
qDebug() << " _oldEntityBox:" << _oldEntityBox;
|
||||
qDebug() << " _newEntityCube:" << _newEntityCube;
|
||||
qDebug() << " _newEntityBox:" << _newEntityBox;
|
||||
qDebug() << "--------------------------------------------------------------------------";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -42,6 +42,8 @@ private:
|
|||
|
||||
bool subTreeContainsOldEntity(OctreeElement* element);
|
||||
bool subTreeContainsNewEntity(OctreeElement* element);
|
||||
|
||||
bool _wantDebug;
|
||||
};
|
||||
|
||||
#endif // hifi_UpdateEntityOperator_h
|
||||
|
|
Loading…
Reference in a new issue