mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 15:09:24 +02:00
initial support for STATIC and KINEMATIC motion
This commit is contained in:
parent
bd34ac4357
commit
2f9a35412f
7 changed files with 147 additions and 24 deletions
|
@ -37,6 +37,13 @@ EntityMotionState::EntityMotionState(EntityItem* entity) : _entity(entity) {
|
||||||
EntityMotionState::~EntityMotionState() {
|
EntityMotionState::~EntityMotionState() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MotionType EntityMotionState::getMotionType() const {
|
||||||
|
// HACK: According to EntityTree the meaning of "static" is "not moving" whereas
|
||||||
|
// to Bullet it means "can't move". For demo purposes we temporarily interpret
|
||||||
|
// Entity::weightless to mean Bullet::static.
|
||||||
|
return _entity->hasGravity() ? MOTION_TYPE_DYNAMIC : MOTION_TYPE_STATIC;
|
||||||
|
}
|
||||||
|
|
||||||
// This callback is invoked by the physics simulation in two cases:
|
// This callback is invoked by the physics simulation in two cases:
|
||||||
// (1) when the RigidBody is first added to the world
|
// (1) when the RigidBody is first added to the world
|
||||||
// (irregardless of MotionType: STATIC, DYNAMIC, or KINEMATIC)
|
// (irregardless of MotionType: STATIC, DYNAMIC, or KINEMATIC)
|
||||||
|
|
|
@ -27,6 +27,8 @@ public:
|
||||||
EntityMotionState(EntityItem* item);
|
EntityMotionState(EntityItem* item);
|
||||||
virtual ~EntityMotionState();
|
virtual ~EntityMotionState();
|
||||||
|
|
||||||
|
MotionType getMotionType() const;
|
||||||
|
|
||||||
void getWorldTransform (btTransform &worldTrans) const;
|
void getWorldTransform (btTransform &worldTrans) const;
|
||||||
void setWorldTransform (const btTransform &worldTrans);
|
void setWorldTransform (const btTransform &worldTrans);
|
||||||
void applyVelocities() const;
|
void applyVelocities() const;
|
||||||
|
|
|
@ -77,9 +77,9 @@ EntityItem* EntityTree::getOrCreateEntityItem(const EntityItemID& entityID, cons
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a new entity item to the tree
|
/// Adds a new entity item to the tree
|
||||||
void EntityTree::addEntityItem(EntityItem* entityItem) {
|
void EntityTree::addEntityItem(EntityItem* entity) {
|
||||||
// You should not call this on existing entities that are already part of the tree! Call updateEntity()
|
// You should not call this on existing entities that are already part of the tree! Call updateEntity()
|
||||||
EntityItemID entityID = entityItem->getEntityItemID();
|
EntityItemID entityID = entity->getEntityItemID();
|
||||||
EntityTreeElement* containingElement = getContainingElement(entityID);
|
EntityTreeElement* containingElement = getContainingElement(entityID);
|
||||||
if (containingElement) {
|
if (containingElement) {
|
||||||
qDebug() << "UNEXPECTED!!!! don't call addEntityItem() on existing entity items. entityID=" << entityID;
|
qDebug() << "UNEXPECTED!!!! don't call addEntityItem() on existing entity items. entityID=" << entityID;
|
||||||
|
@ -87,12 +87,15 @@ void EntityTree::addEntityItem(EntityItem* entityItem) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recurse the tree and store the entity in the correct tree element
|
// Recurse the tree and store the entity in the correct tree element
|
||||||
AddEntityOperator theOperator(this, entityItem);
|
AddEntityOperator theOperator(this, entity);
|
||||||
recurseTreeWithOperator(&theOperator);
|
recurseTreeWithOperator(&theOperator);
|
||||||
|
|
||||||
// check to see if we need to simulate this entity..
|
// check to see if we need to simulate this entity..
|
||||||
// BOOKMARK -- add entity to physics engine here
|
changeEntityState(entity, EntityItem::Static, entity->getSimulationState());
|
||||||
changeEntityState(entityItem, EntityItem::Static, entityItem->getSimulationState());
|
|
||||||
|
if (_physicsWorld && !entity->getMotionState()) {
|
||||||
|
addEntityToPhysicsWorld(entity);
|
||||||
|
}
|
||||||
|
|
||||||
_isDirty = true;
|
_isDirty = true;
|
||||||
}
|
}
|
||||||
|
@ -530,7 +533,7 @@ int EntityTree::processEditPacketData(PacketType packetType, const unsigned char
|
||||||
// search for the entity by EntityItemID
|
// search for the entity by EntityItemID
|
||||||
EntityItem* existingEntity = findEntityByEntityItemID(entityItemID);
|
EntityItem* existingEntity = findEntityByEntityItemID(entityItemID);
|
||||||
|
|
||||||
// if the entityItem exists, then update it
|
// if the EntityItem exists, then update it
|
||||||
if (existingEntity) {
|
if (existingEntity) {
|
||||||
updateEntity(entityItemID, properties);
|
updateEntity(entityItemID, properties);
|
||||||
existingEntity->markAsChangedOnServer();
|
existingEntity->markAsChangedOnServer();
|
||||||
|
@ -621,9 +624,6 @@ void EntityTree::changeEntityState(EntityItem* const entity,
|
||||||
|
|
||||||
case EntityItem::Moving:
|
case EntityItem::Moving:
|
||||||
_movingEntities.push_back(entity);
|
_movingEntities.push_back(entity);
|
||||||
if (_physicsWorld && !entity->getMotionState()) {
|
|
||||||
addEntityToPhysicsWorld(entity);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EntityItem::Mortal:
|
case EntityItem::Mortal:
|
||||||
|
@ -683,7 +683,11 @@ void EntityTree::updateChangingEntities(quint64 now, QSet<EntityItemID>& entitie
|
||||||
// TODO: switch these to iterators so we can remove items that get deleted
|
// TODO: switch these to iterators so we can remove items that get deleted
|
||||||
for (int i = 0; i < _changingEntities.size(); i++) {
|
for (int i = 0; i < _changingEntities.size(); i++) {
|
||||||
EntityItem* thisEntity = _changingEntities[i];
|
EntityItem* thisEntity = _changingEntities[i];
|
||||||
thisEntity->update(now);
|
EntityMotionState* motionState = thisEntity->getMotionState();
|
||||||
|
if (!motionState) {
|
||||||
|
thisEntity->update(now);
|
||||||
|
}
|
||||||
|
|
||||||
// always check to see if the lifetime has expired, for immortal entities this is always false
|
// always check to see if the lifetime has expired, for immortal entities this is always false
|
||||||
if (thisEntity->lifetimeHasExpired()) {
|
if (thisEntity->lifetimeHasExpired()) {
|
||||||
qDebug() << "Lifetime has expired for entity:" << thisEntity->getEntityItemID();
|
qDebug() << "Lifetime has expired for entity:" << thisEntity->getEntityItemID();
|
||||||
|
|
|
@ -34,7 +34,8 @@ CustomMotionState::CustomMotionState() :
|
||||||
_volume(DEFAULT_VOLUME),
|
_volume(DEFAULT_VOLUME),
|
||||||
_friction(DEFAULT_FRICTION),
|
_friction(DEFAULT_FRICTION),
|
||||||
_restitution(DEFAULT_RESTITUTION),
|
_restitution(DEFAULT_RESTITUTION),
|
||||||
_motionType(MOTION_TYPE_STATIC),
|
_wasInWorld(false),
|
||||||
|
_motionType(MOTION_TYPE_STATIC),
|
||||||
_body(NULL) {
|
_body(NULL) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ public:
|
||||||
|
|
||||||
virtual void computeShapeInfo(ShapeInfo& info) = 0;
|
virtual void computeShapeInfo(ShapeInfo& info) = 0;
|
||||||
|
|
||||||
MotionType getMotionType() const { return _motionType; }
|
virtual MotionType getMotionType() const { return _motionType; }
|
||||||
|
|
||||||
void setDensity(float density);
|
void setDensity(float density);
|
||||||
void setFriction(float friction);
|
void setFriction(float friction);
|
||||||
|
@ -54,15 +54,16 @@ public:
|
||||||
void getAngularVelocity(glm::vec3& angularVelocityOut) const;
|
void getAngularVelocity(glm::vec3& angularVelocityOut) const;
|
||||||
|
|
||||||
friend class PhysicsWorld;
|
friend class PhysicsWorld;
|
||||||
protected:
|
|
||||||
|
|
||||||
|
protected:
|
||||||
float _density;
|
float _density;
|
||||||
float _volume;
|
float _volume;
|
||||||
float _friction;
|
float _friction;
|
||||||
float _restitution;
|
float _restitution;
|
||||||
|
bool _wasInWorld;
|
||||||
// The data members below have NO setters. They are only changed by a PhysicsWorld instance.
|
|
||||||
MotionType _motionType;
|
MotionType _motionType;
|
||||||
|
|
||||||
|
// _body has NO setters -- it is only changed by PhysicsWorld
|
||||||
btRigidBody* _body;
|
btRigidBody* _body;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,26 @@ void PhysicsWorld::init() {
|
||||||
_broadphaseFilter = new btDbvtBroadphase();
|
_broadphaseFilter = new btDbvtBroadphase();
|
||||||
_constraintSolver = new btSequentialImpulseConstraintSolver;
|
_constraintSolver = new btSequentialImpulseConstraintSolver;
|
||||||
_dynamicsWorld = new btDiscreteDynamicsWorld(_collisionDispatcher, _broadphaseFilter, _constraintSolver, _collisionConfig);
|
_dynamicsWorld = new btDiscreteDynamicsWorld(_collisionDispatcher, _broadphaseFilter, _constraintSolver, _collisionConfig);
|
||||||
|
|
||||||
|
// TODO: once the initial physics system is working we will set gravity of the world to be zero
|
||||||
|
// and each object will have to specify its own local gravity, or we'll set up gravity zones.
|
||||||
|
//_dynamicsWorld->setGravity(btVector3(0.0f, 0.0f, 0.0f));
|
||||||
|
//
|
||||||
|
// GROUND HACK: In the meantime we add a big planar floor to catch falling objects
|
||||||
|
// NOTE: we don't care about memory leaking groundShape and groundObject -->
|
||||||
|
// they'll exist until the executable exits.
|
||||||
|
const float halfSide = 200.0f;
|
||||||
|
const float halfHeight = 10.0f;
|
||||||
|
|
||||||
|
btCollisionShape* groundShape = new btBoxShape(btVector3(halfSide, halfHeight, halfSide));
|
||||||
|
btTransform groundTransform;
|
||||||
|
groundTransform.setIdentity();
|
||||||
|
groundTransform.setOrigin(btVector3(halfSide, -halfHeight, halfSide));
|
||||||
|
|
||||||
|
btCollisionObject* groundObject = new btCollisionObject();
|
||||||
|
groundObject->setCollisionShape(groundShape);
|
||||||
|
groundObject->setWorldTransform(groundTransform);
|
||||||
|
_dynamicsWorld->addCollisionObject(groundObject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,19 +113,103 @@ bool PhysicsWorld::removeVoxel(const glm::vec3& position, float scale) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bullet collision flags are as follows:
|
||||||
|
// CF_STATIC_OBJECT= 1,
|
||||||
|
// CF_KINEMATIC_OBJECT= 2,
|
||||||
|
// CF_NO_CONTACT_RESPONSE = 4,
|
||||||
|
// CF_CUSTOM_MATERIAL_CALLBACK = 8,//this allows per-triangle material (friction/restitution)
|
||||||
|
// CF_CHARACTER_OBJECT = 16,
|
||||||
|
// CF_DISABLE_VISUALIZE_OBJECT = 32, //disable debug drawing
|
||||||
|
// CF_DISABLE_SPU_COLLISION_PROCESSING = 64//disable parallel/SPU processing
|
||||||
|
|
||||||
bool PhysicsWorld::addEntity(CustomMotionState* motionState) {
|
bool PhysicsWorld::addEntity(CustomMotionState* motionState) {
|
||||||
assert(motionState);
|
assert(motionState);
|
||||||
ShapeInfo info;
|
ShapeInfo info;
|
||||||
motionState->computeShapeInfo(info);
|
motionState->computeShapeInfo(info);
|
||||||
btCollisionShape* shape = _shapeManager.getShape(info);
|
btCollisionShape* shape = _shapeManager.getShape(info);
|
||||||
if (shape) {
|
if (shape) {
|
||||||
btVector3 inertia;
|
btVector3 inertia(0.0f, 0.0f, 0.0f);
|
||||||
float mass = motionState->getMass();
|
float mass = 0.0f;
|
||||||
shape->calculateLocalInertia(mass, inertia);
|
btRigidBody* body = NULL;
|
||||||
btRigidBody* body = new btRigidBody(mass, motionState, shape, inertia);
|
switch(motionState->_motionType) {
|
||||||
motionState->_body = body;
|
case MOTION_TYPE_KINEMATIC: {
|
||||||
motionState->applyVelocities();
|
body = new btRigidBody(mass, motionState, shape, inertia);
|
||||||
// TODO: set dynamic/kinematic/static property from data stored in motionState
|
body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT);
|
||||||
|
body->setActivationState(DISABLE_DEACTIVATION);
|
||||||
|
body->updateInertiaTensor();
|
||||||
|
motionState->_body = body;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MOTION_TYPE_DYNAMIC: {
|
||||||
|
mass = motionState->getMass();
|
||||||
|
shape->calculateLocalInertia(mass, inertia);
|
||||||
|
body = new btRigidBody(mass, motionState, shape, inertia);
|
||||||
|
body->updateInertiaTensor();
|
||||||
|
motionState->_body = body;
|
||||||
|
motionState->applyVelocities();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
// MOTION_TYPE_STATIC
|
||||||
|
body = new btRigidBody(mass, motionState, shape, inertia);
|
||||||
|
body->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT);
|
||||||
|
body->updateInertiaTensor();
|
||||||
|
motionState->_body = body;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
body->setRestitution(motionState->_restitution);
|
||||||
|
body->setFriction(motionState->_friction);
|
||||||
|
_dynamicsWorld->addRigidBody(body);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PhysicsWorld::updateEntityMotionType(CustomMotionState* motionState) {
|
||||||
|
btRigidBody* body = motionState->_body;
|
||||||
|
if (!body) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MotionType oldType = MOTION_TYPE_DYNAMIC;
|
||||||
|
if (body->isStaticObject()) {
|
||||||
|
oldType = MOTION_TYPE_STATIC;
|
||||||
|
} else if (body->isKinematicObject()) {
|
||||||
|
oldType = MOTION_TYPE_KINEMATIC;
|
||||||
|
}
|
||||||
|
MotionType newType = motionState->getMotionType();
|
||||||
|
if (oldType != newType) {
|
||||||
|
// pull body out of physics engine
|
||||||
|
_dynamicsWorld->removeRigidBody(body);
|
||||||
|
|
||||||
|
// update various properties and flags
|
||||||
|
switch (newType) {
|
||||||
|
case MOTION_TYPE_KINEMATIC: {
|
||||||
|
body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT);
|
||||||
|
body->setActivationState(DISABLE_DEACTIVATION);
|
||||||
|
body->updateInertiaTensor();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MOTION_TYPE_DYNAMIC: {
|
||||||
|
btVector3 inertia(0.0f, 0.0f, 0.0f);
|
||||||
|
float mass = motionState->getMass();
|
||||||
|
body->getCollisionShape()->calculateLocalInertia(mass, inertia);
|
||||||
|
body->updateInertiaTensor();
|
||||||
|
motionState->applyVelocities();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
// MOTION_TYPE_STATIC
|
||||||
|
body->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT);
|
||||||
|
body->updateInertiaTensor();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// reinsert body into physics engine
|
||||||
|
body->setRestitution(motionState->_restitution);
|
||||||
|
body->setFriction(motionState->_friction);
|
||||||
_dynamicsWorld->addRigidBody(body);
|
_dynamicsWorld->addRigidBody(body);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,11 +59,15 @@ public:
|
||||||
/// \return true if Voxel removed
|
/// \return true if Voxel removed
|
||||||
bool removeVoxel(const glm::vec3& position, float scale);
|
bool removeVoxel(const glm::vec3& position, float scale);
|
||||||
|
|
||||||
/// \param info information about collision shapes to create
|
/// \param motionState pointer to Entity's MotionState
|
||||||
/// \return true if Entity added
|
/// \return true if Entity added
|
||||||
bool addEntity(CustomMotionState* motionState);
|
bool addEntity(CustomMotionState* motionState);
|
||||||
|
|
||||||
/// \param id UUID of the entity
|
/// \param motionState pointer to Entity's MotionState
|
||||||
|
/// \return true if entity updated
|
||||||
|
bool updateEntityMotionType(CustomMotionState* motionState);
|
||||||
|
|
||||||
|
/// \param motionState pointer to Entity's MotionState
|
||||||
/// \return true if Entity removed
|
/// \return true if Entity removed
|
||||||
bool removeEntity(CustomMotionState* motionState);
|
bool removeEntity(CustomMotionState* motionState);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue