mirror of
https://github.com/overte-org/overte.git
synced 2025-08-15 16:36:22 +02:00
reconcile use of getAACube() and handle rotations properly
This commit is contained in:
parent
2148baae21
commit
695569b64b
9 changed files with 100 additions and 107 deletions
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue