fixed bugs in MovingEntitiesOperator, improved getDistanceToBottomOfEntity, isRestingOnSurface

This commit is contained in:
ZappoMan 2014-09-12 07:45:33 -07:00
parent 77dff69805
commit 54ef5d4698
8 changed files with 176 additions and 46 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -42,6 +42,8 @@ private:
bool subTreeContainsOldEntity(OctreeElement* element);
bool subTreeContainsNewEntity(OctreeElement* element);
bool _wantDebug;
};
#endif // hifi_UpdateEntityOperator_h