reconcile use of getAACube() and handle rotations properly

This commit is contained in:
ZappoMan 2014-09-11 16:43:53 -07:00
parent 2148baae21
commit 695569b64b
9 changed files with 100 additions and 107 deletions

View file

@ -294,15 +294,15 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args)
if (entityItem->isVisible()) {
// render entityItem
AACube entityCube = entityItem->getAACube();
AABox entityBox = entityItem->getAABox();
entityCube.scale(TREE_SCALE);
entityBox.scale(TREE_SCALE);
// TODO: some entity types (like lights) might want to be rendered even
// when they are outside of the view frustum...
float distance = distanceToCamera(entityCube.calcCenter(), *args->_viewFrustum);
if (shouldRenderEntity(entityCube.getLargestDimension(), distance) &&
args->_viewFrustum->cubeInFrustum(entityCube) != ViewFrustum::OUTSIDE) {
float distance = distanceToCamera(entityBox.calcCenter(), *args->_viewFrustum);
if (shouldRenderEntity(entityBox.getLargestDimension(), distance) &&
args->_viewFrustum->boxInFrustum(entityBox) != ViewFrustum::OUTSIDE) {
renderProxies(entityItem, args);

View file

@ -26,7 +26,12 @@ AddEntityOperator::AddEntityOperator(EntityTree* tree,
// caller must have verified existence of newEntity
assert(_newEntity);
_newEntityBox = _newEntity->getAACube().clamp(0.0f, 1.0f);
// 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.
_newEntityBox = _newEntity->getMaximumAACube().clamp(0.0f, 1.0f);
}
bool AddEntityOperator::preRecursion(OctreeElement* element) {

View file

@ -559,7 +559,7 @@ void EntityItem::update(const quint64& updateTime) {
if (wantDebug) {
qDebug() << "EntityItem::update()....";
qDebug() << " timeElapsed:" << timeElapsed;
qDebug() << " old AACube:" << getAACube();
qDebug() << " old AACube:" << getMaximumAACube();
qDebug() << " old position:" << position;
qDebug() << " old velocity:" << velocity;
qDebug() << " getDistanceToBottomOfEntity():" << getDistanceToBottomOfEntity();
@ -618,7 +618,7 @@ void EntityItem::update(const quint64& updateTime) {
setPosition(position);
setVelocity(velocity);
if (wantDebug) {
qDebug() << " new AACube:" << getAACube();
qDebug() << " new AACube:" << getMaximumAACube();
}
}
}
@ -721,11 +721,10 @@ float EntityItem::getSize() const {
return glm::length(_dimensions);
}
// TODO: fix this to correctly handle rotation... since _dimensions is in entity space,
// if the entity has been rotated, then the distance to world.y=0 is not the same
// as the dimensions.y
float EntityItem::getDistanceToBottomOfEntity() const {
glm::vec3 minimumPoint = getMinimumPoint();
// 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;
}

View file

@ -200,7 +200,6 @@ public:
glm::vec3 getMaximumPoint() const;
AACube getMaximumAACube() const;
AACube getMinimumAACube() const;
AACube getAACube() const { return getMaximumAACube(); } /// axis aligned bounding cube in domain scale units (0.0 - 1.0)
AABox getAABox() const; /// axis aligned bounding box in domain scale units (0.0 - 1.0)
static const QString DEFAULT_SCRIPT;

View file

@ -592,17 +592,34 @@ void EntityItemProperties::markAllChanged() {
_glowLevelChanged = true;
}
// TODO: Add support for registration point
glm::vec3 EntityItemProperties::getMinimumPointMeters() const {
// This assumes the registration point is in the center, we need to update this when we really support
// registration point
return _position - (_dimensions / 2.0f);
AACube EntityItemProperties::getMaximumAACubeInTreeUnits() const {
AACube maxCube = getMaximumAACubeInMeters();
maxCube.scale(1 / (float)TREE_SCALE);
return maxCube;
}
// TODO: Add support for registration point
glm::vec3 EntityItemProperties::getMaximumPointMeters() const {
// This assumes the registration point is in the center, we need to update this when we really support
// registration point
return _position + (_dimensions / 2.0f);
/// The maximum bounding cube for the entity, independent of it's rotation.
/// This accounts for the registration point (upon which rotation occurs around).
///
AACube EntityItemProperties::getMaximumAACubeInMeters() const {
// * we know that the position is the center of rotation
glm::vec3 centerOfRotation = _position; // also where _registration point is
// * we know that the registration point is the center of rotation
// * we can calculate the length of the furthest extent from the registration point
// as the dimensions * max (registrationPoint, (1.0,1.0,1.0) - registrationPoint)
glm::vec3 registrationPoint = (_dimensions * _registrationPoint);
glm::vec3 registrationRemainder = (_dimensions * (glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint));
glm::vec3 furthestExtentFromRegistration = glm::max(registrationPoint, registrationRemainder);
// * we know that if you rotate in any direction you would create a sphere
// that has a radius of the length of furthest extent from registration point
float radius = glm::length(furthestExtentFromRegistration);
// * we know that the minimum bounding cube of this maximum possible sphere is
// (center - radius) to (center + radius)
glm::vec3 minimumCorner = centerOfRotation - glm::vec3(radius, radius, radius);
float diameter = radius * 2.0f;
return AACube(minimumCorner, diameter);
}

View file

@ -95,16 +95,8 @@ public:
/// used by EntityScriptingInterface to return EntityItemProperties for unknown models
void setIsUnknownID() { _id = UNKNOWN_ENTITY_ID; _idSet = true; }
glm::vec3 getMinimumPointMeters() const;
glm::vec3 getMaximumPointMeters() const;
AACube getAACubeMeters() const { return AACube(getMinimumPointMeters(), getMaxDimension()); } /// AACube in meter units
glm::vec3 getMinimumPointTreeUnits() const { return getMinimumPointMeters() / (float)TREE_SCALE; }
glm::vec3 getMaximumPointTreeUnits() const { return getMaximumPointMeters() / (float)TREE_SCALE; }
/// AACube in domain scale units (0.0 - 1.0)
AACube getAACubeTreeUnits() const {
return AACube(getMinimumPointMeters() / (float)TREE_SCALE, getMaxDimension() / (float)TREE_SCALE);
}
AACube getMaximumAACubeInTreeUnits() const;
AACube getMaximumAACubeInMeters() const;
void debugDump() const;

View file

@ -652,9 +652,9 @@ void EntityTree::updateMovingEntities(quint64 now, QSet<EntityItemID>& entitiesT
entitiesToDelete << thisEntity->getEntityItemID();
entitiesBecomingStatic << thisEntity;
} else {
AACube oldCube = thisEntity->getAACube();
AACube oldCube = thisEntity->getMaximumAACube();
thisEntity->update(now);
AACube newCube = thisEntity->getAACube();
AACube newCube = thisEntity->getMaximumAACube();
// 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);

View file

@ -296,7 +296,12 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData
}
if (includeThisEntity && params.viewFrustum) {
AACube entityCube = entity->getAACube();
// we want to use the maximum possible box for this, so that we don't have to worry about the nuance of
// simulation changing what's visible. consider the case where the entity contains an angular velocity
// the entity may not be in view and then in view a frame later, let the client side handle it's view
// frustum culling on rendering.
AACube entityCube = entity->getMaximumAACube();
entityCube.scale(TREE_SCALE);
if (params.viewFrustum->cubeInFrustum(entityCube) == ViewFrustum::OUTSIDE) {
includeThisEntity = false; // out of view, don't include it
@ -405,19 +410,31 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData
}
bool EntityTreeElement::containsEntityBounds(const EntityItem* entity) const {
return containsBounds(entity->getMinimumPoint(), entity->getMaximumPoint());
// 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 {
return bestFitBounds(entity->getMinimumPoint(), entity->getMaximumPoint());
// 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 {
return containsBounds(properties.getMinimumPointTreeUnits(), properties.getMaximumPointTreeUnits());
// 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 {
return bestFitBounds(properties.getMinimumPointTreeUnits(), properties.getMaximumPointTreeUnits());
// TODO: this needs to be updated to have the similar behavior support for registration point and rotation
// as EntityItem does
return bestFitBounds(properties.getMaximumAACubeInTreeUnits());
}
bool EntityTreeElement::containsBounds(const AACube& bounds) const {
@ -477,76 +494,36 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con
while(entityItr != entityEnd) {
EntityItem* entity = (*entityItr);
AACube entityCube = entity->getAACube();
AABox entityBox = entity->getAABox();
float localDistance;
BoxFace localFace;
// if the ray doesn't intersect with our cube, we can stop searching!
if (entityCube.findRayIntersection(origin, direction, localDistance, localFace)) {
const FBXGeometry* fbxGeometry = _myTree->getGeometryForEntity(entity);
if (fbxGeometry && fbxGeometry->meshExtents.isValid()) {
Extents extents = fbxGeometry->meshExtents;
if (entityBox.findRayIntersection(origin, direction, localDistance, localFace)) {
// NOTE: If the entity has a bad mesh, then extents will be 0,0,0 & 0,0,0
if (extents.minimum == extents.maximum && extents.minimum == glm::vec3(0,0,0)) {
extents.maximum = glm::vec3(1.0f,1.0f,1.0f); // in this case we will simulate the unit cube
// extents is the entity relative, scaled, centered extents of the entity
glm::mat4 rotation = glm::mat4_cast(entity->getRotation());
glm::mat4 translation = glm::translate(entity->getPosition());
glm::mat4 entityToWorldMatrix = translation * rotation;
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
glm::vec3 dimensions = entity->getDimensions();
AABox entityFrameBox(glm::vec3(0.0f,0.0f,0.0f), dimensions);
glm::vec3 entityFrameOrigin = glm::vec3(worldToEntityMatrix * glm::vec4(origin, 1.0f));
glm::vec3 entityFrameDirection = glm::vec3(worldToEntityMatrix * glm::vec4(direction, 0.0f));
// we can use the AABox's ray intersection by mapping our origin and direction into the entity frame
// and testing intersection there.
if (entityFrameBox.findRayIntersection(entityFrameOrigin, entityFrameDirection, localDistance, localFace)) {
if (localDistance < distance) {
distance = localDistance;
face = localFace;
*intersectedObject = (void*)entity;
somethingIntersected = true;
}
// NOTE: these extents are entity space, so we need to scale and center them accordingly
// size is our "target size in world space"
// we need to set our entity scale so that the extents of the mesh, fit in a cube that size...
float maxDimension = glm::distance(extents.maximum, extents.minimum);
float scale = entity->getSize() / maxDimension;
glm::vec3 halfDimensions = (extents.maximum - extents.minimum) * 0.5f;
glm::vec3 offset = -extents.minimum - halfDimensions;
extents.minimum += offset;
extents.maximum += offset;
extents.minimum *= scale;
extents.maximum *= scale;
Extents rotatedExtents = extents;
rotatedExtents.rotate(entity->getRotation());
rotatedExtents.minimum += entity->getPosition();
rotatedExtents.maximum += entity->getPosition();
AABox rotatedExtentsBox(rotatedExtents.minimum, (rotatedExtents.maximum - rotatedExtents.minimum));
// if it's in our AABOX for our rotated extents, then check to see if it's in our non-AABox
if (rotatedExtentsBox.findRayIntersection(origin, direction, localDistance, localFace)) {
// extents is the entity relative, scaled, centered extents of the entity
glm::mat4 rotation = glm::mat4_cast(entity->getRotation());
glm::mat4 translation = glm::translate(entity->getPosition());
glm::mat4 entityToWorldMatrix = translation * rotation;
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
AABox entityFrameBox(extents.minimum, (extents.maximum - extents.minimum));
glm::vec3 entityFrameOrigin = glm::vec3(worldToEntityMatrix * glm::vec4(origin, 1.0f));
glm::vec3 entityFrameDirection = glm::vec3(worldToEntityMatrix * glm::vec4(direction, 0.0f));
// we can use the AABox's ray intersection by mapping our origin and direction into the entity frame
// and testing intersection there.
if (entityFrameBox.findRayIntersection(entityFrameOrigin, entityFrameDirection, localDistance, localFace)) {
if (localDistance < distance) {
distance = localDistance;
face = localFace;
*intersectedObject = (void*)entity;
somethingIntersected = true;
}
}
}
} else if (localDistance < distance) {
distance = localDistance;
face = localFace;
*intersectedObject = (void*)entity;
somethingIntersected = true;
}
}

View file

@ -36,7 +36,11 @@ UpdateEntityOperator::UpdateEntityOperator(EntityTree* tree,
// caller must have verified existence of containingElement and oldEntity
assert(_containingElement && _existingEntity);
_oldEntityCube = _existingEntity->getAACube();
// 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.
_oldEntityCube = _existingEntity->getMaximumAACube();
_oldEntityBox = _oldEntityCube.clamp(0.0f, 1.0f); // clamp to domain bounds
// If the new properties has position OR dimension changes, but not both, we need to
@ -71,7 +75,7 @@ UpdateEntityOperator::UpdateEntityOperator(EntityTree* tree,
_newEntityCube = _oldEntityCube;
_dontMove = true;
} else {
_newEntityCube = _properties.getAACubeTreeUnits();
_newEntityCube = _properties.getMaximumAACubeInTreeUnits();
_removeOld = true; // our properties are going to move us, so remember this for later processing
}