Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Ignore:
Timestamp:
Dec 13, 2008, 4:14:36 PM (16 years ago)
Author:
rgrieder
Message:
  • Added detach functions to CollisionShapes
  • Added update functions across the CollisionShape hierarchy so that when you change the radius of a sphere, everything up to the WE gets updated.
  • Setting the btCollisionShape at run time doesn't work after all, fixed that (you can still do it, just a question of internals)
  • Improved network synchronisation
  • new WE function: addedToPhysicalWorld() to check whether we can still perform operations that are disallowed at run time (esp. StaticEntity)

Conclusively, I can say that right now, all operations considering physics should be handled automatically, bugs not withstanding.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • code/branches/physics/src/orxonox/objects/worldentities/WorldEntity.cc

    r2408 r2423  
    3333#include <cassert>
    3434#include <OgreSceneManager.h>
    35 
    36 #include "BulletCollision/CollisionShapes/btCollisionShape.h"
    37 #include "BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h"
    3835#include "BulletDynamics/Dynamics/btRigidBody.h"
    3936
     
    4441
    4542#include "objects/Scene.h"
    46 #include "objects/collisionshapes/CollisionShape.h"
    4743#include "objects/collisionshapes/CompoundCollisionShape.h"
    4844
     
    7369        // Default behaviour does not include physics
    7470        this->physicalBody_ = 0;
     71        this->bPhysicsActive_ = false;
    7572        this->collisionShape_ = new CompoundCollisionShape(this);
    7673        this->mass_ = 0;
    77         this->childMass_ = 0;
     74        this->childrenMass_ = 0;
    7875        this->collisionType_ = None;
    7976        this->collisionTypeSynchronised_ = None;
     
    9087                this->getScene()->getSceneManager()->destroySceneNode(this->node_->getName());
    9188
     89            // TODO: Detach from parent and detach all children.
     90
    9291            if (this->physicalBody_)
    9392            {
    94                 if (this->physicalBody_->isInWorld())
    95                     this->getScene()->getPhysicalWorld()->removeRigidBody(this->physicalBody_);
     93                this->deactivatePhysics();
    9694                delete this->physicalBody_;
    9795            }
    98             // TODO: Delete collisionShapes
     96            delete this->collisionShape_;
    9997        }
    10098    }
     
    129127        REGISTERDATA(this->bVisible_,    network::direction::toclient, new network::NetworkCallback<WorldEntity>(this, &WorldEntity::changedVisibility));
    130128
    131         // HACK: Removed the call because it gets called the first time as well
    132         REGISTERDATA(this->getScale3D(), network::direction::toclient);//, new network::NetworkCallback<WorldEntity>(this, &WorldEntity::scaleChanged));
    133 
    134         int* collisionType = (int*)&this->collisionTypeSynchronised_;
    135         REGISTERDATA(*collisionType, network::direction::toclient, new network::NetworkCallback<WorldEntity>(this, &WorldEntity::collisionTypeChanged));
    136         REGISTERDATA(this->mass_,    network::direction::toclient, new network::NetworkCallback<WorldEntity>(this, &WorldEntity::massChanged));
    137 
    138         REGISTERDATA(this->parentID_, network::direction::toclient, new network::NetworkCallback<WorldEntity>(this, &WorldEntity::updateParent));
     129        REGISTERDATA(this->getScale3D(), network::direction::toclient, new network::NetworkCallback<WorldEntity>(this, &WorldEntity::scaleChanged));
     130
     131        REGISTERDATA((int&)this->collisionTypeSynchronised_,
     132                                         network::direction::toclient, new network::NetworkCallback<WorldEntity>(this, &WorldEntity::collisionTypeChanged));
     133        REGISTERDATA(this->mass_,        network::direction::toclient, new network::NetworkCallback<WorldEntity>(this, &WorldEntity::massChanged));
     134        REGISTERDATA(this->bPhysicsActiveSynchronised_,
     135                                         network::direction::toclient, new network::NetworkCallback<WorldEntity>(this, &WorldEntity::physicsActivityChanged));
     136
     137        REGISTERDATA(this->parentID_,    network::direction::toclient, new network::NetworkCallback<WorldEntity>(this, &WorldEntity::updateParent));
    139138    }
    140139
     
    167166    {
    168167        this->setMass(this->mass_);
     168    }
     169
     170    void WorldEntity::physicsActivityChanged()
     171    {
     172        if (this->bPhysicsActiveSynchronised_)
     173            this->activatePhysics();
     174        else
     175            this->deactivatePhysics();
    169176    }
    170177
     
    184191            else
    185192            {
    186                 if (this->physicalBody_->isInWorld())
    187                     removeFromPhysicalWorld();
    188                 if (object->physicalBody_->isInWorld())
    189                     this->getScene()->removeRigidBody(object->physicalBody_);
    190 
    191                 // static to static/kinematic/dynamic --> merge shapes
    192                 this->childMass_ += object->getMass();
    193                 this->attachCollisionShape(object->getCollisionShape(), true);
    194                 // Remove the btRigidBody from the child object.
    195                 // That also implies that cannot add a physics WE to the child afterwards.
    196                 object->setCollisionType(None);
    197 
    198                 addToPhysicalWorld();
     193                object->deactivatePhysics();
    199194            }
    200195        }
     
    213208        object->parent_ = this;
    214209        object->parentID_ = this->getObjectID();
     210
     211        // collision shapes
     212        this->attachCollisionShape(object->getCollisionShape());
     213        // mass
     214        this->childrenMass_ += object->getMass();
     215        recalculatePhysicsProps();
    215216    }
    216217
    217218    void WorldEntity::detach(WorldEntity* object)
    218219    {
     220        // collision shapes
     221        this->detachCollisionShape(object->getCollisionShape());
     222        // mass
     223        if (object->getMass() > 0.0f)
     224        {
     225            this->childrenMass_ -= object->getMass();
     226            recalculatePhysicsProps();
     227        }
     228
    219229        this->node_->removeChild(object->node_);
    220230        this->children_.erase(object);
    221231        object->parent_ = 0;
    222232        object->parentID_ = (unsigned int)-1;
    223 
    224233//        this->getScene()->getRootSceneNode()->addChild(object->node_);
     234
     235        // Note: It is possible that the object has physics but was disabled when attaching
     236        object->activatePhysics();
    225237    }
    226238
     
    237249    }
    238250
    239     void WorldEntity::attachCollisionShape(CollisionShape* shape, bool bWorldEntityRoot)
    240     {
    241         this->collisionShape_->addChildShape(shape, bWorldEntityRoot);
    242 
    243         if (this->physicalBody_)
    244         {
    245             if (this->physicalBody_->isInWorld())
    246             {
    247                 COUT(2) << "Warning: Attaching collision shapes at run time causes its physical body to be removed and added again.";
    248                 removeFromPhysicalWorld();
    249             }
    250             if (this->collisionShape_->getCollisionShape())
    251                 this->physicalBody_->setCollisionShape(this->collisionShape_->getCollisionShape());
    252             // recalculate inertia tensor
    253             internalSetMassProps();
    254             addToPhysicalWorld();
    255         }
     251    void WorldEntity::attachCollisionShape(CollisionShape* shape)
     252    {
     253        this->collisionShape_->addChildShape(shape);
     254        // Note: this->collisionShape_ already notifies us of any changes.
     255    }
     256
     257    void WorldEntity::detachCollisionShape(CollisionShape* shape)
     258    {
     259        this->collisionShape_->removeChildShape(shape);
     260        // Note: this->collisionShape_ already notifies us of any changes.
    256261    }
    257262
     
    261266    }
    262267
    263     void WorldEntity::addToPhysicalWorld() const
    264     {
    265         if (this->isActive() && this->hasPhysics() && !this->physicalBody_->isInWorld())
     268    void WorldEntity::activatePhysics()
     269    {
     270        if (this->isActive() && this->hasPhysics() && !this->isPhysicsActive() && !this->parent_)
     271        {
    266272            this->getScene()->addRigidBody(this->physicalBody_);
    267     }
    268 
    269     void WorldEntity::removeFromPhysicalWorld() const
    270     {
    271         if (this->hasPhysics())
     273            this->bPhysicsActive_ = true;
     274        }
     275    }
     276
     277    void WorldEntity::deactivatePhysics()
     278    {
     279        if (this->isPhysicsActive())
     280        {
    272281            this->getScene()->removeRigidBody(this->physicalBody_);
     282            this->bPhysicsActive_ = false;
     283        }
     284    }
     285
     286    bool WorldEntity::addedToPhysicalWorld() const
     287    {
     288        return this->physicalBody_ && this->physicalBody_->isInWorld();
    273289    }
    274290
     
    292308    {
    293309        this->mass_ = mass;
    294         if (!this->hasPhysics())
    295             return;
    296         // TODO: Add this again when new network callbacks work properly
    297             //COUT(3) << "Warning: Setting the mass of a WorldEntity with no physics has no effect." << std::endl;
    298         else
    299         {
    300             if (this->physicalBody_->isInWorld())
    301             {
    302                 COUT(2) << "Warning: Setting the mass of a WorldEntity at run time causes its physical body to be removed and added again." << std::endl;
    303                 removeFromPhysicalWorld();
    304             }
    305             internalSetMassProps();
    306         }
    307 
    308         addToPhysicalWorld();
    309     }
    310 
    311     void WorldEntity::internalSetMassProps()
    312     {
    313         assert(hasPhysics());
    314 
    315         if (this->isStatic())
    316         {
    317             // Just set everything to zero
    318             this->physicalBody_->setMassProps(0.0f, btVector3(0, 0, 0));
    319         }
    320         else if ((this->mass_ + this->childMass_) == 0.0f)
    321         {
    322             // Use default values to avoid very large or very small values
    323             CCOUT(2) << "Warning: Setting the internal physical mass to 1.0 because mass_ is 0.0." << std::endl;
    324             this->physicalBody_->setMassProps(1.0f, this->getLocalInertia(1.0f));
    325         }
    326         else
    327             this->physicalBody_->setMassProps(this->mass_, this->getLocalInertia(this->mass_ + this->childMass_));
    328     }
    329 
    330     btVector3 WorldEntity::getLocalInertia(btScalar mass) const
    331     {
    332         btVector3 inertia(0, 0, 0);
    333         if (this->collisionShape_->getCollisionShape())
    334             this->collisionShape_->getCollisionShape()->calculateLocalInertia(mass, inertia);
    335         return inertia;
     310        recalculatePhysicsProps();
    336311    }
    337312
     
    341316        if (this->parent_)
    342317            ThrowException(PhysicsViolation, "Cannot set the collision type of a WorldEntity with a parent");
    343         else if (this->physicalBody_ && this->physicalBody_->isInWorld())
     318        else if (this->addedToPhysicalWorld())
    344319            ThrowException(PhysicsViolation, "Warning: Cannot set the collision type at run time.");
    345320
     
    357332            // Create new rigid body
    358333            btCollisionShape* temp = 0;
    359             if (this->collisionShape_)
    360                 temp = this->collisionShape_->getCollisionShape();
    361             btRigidBody::btRigidBodyConstructionInfo bodyConstructionInfo(0, this, temp, btVector3(0,0,0));
     334            btRigidBody::btRigidBodyConstructionInfo bodyConstructionInfo(0, this, this->collisionShape_->getCollisionShape());
     335            bodyConstructionInfo.m_restitution = 1;
    362336            this->physicalBody_ = new btRigidBody(bodyConstructionInfo);
    363337            this->physicalBody_->setUserPointer(this);
     
    368342            // Destroy rigid body
    369343            assert(this->physicalBody_);
    370             removeFromPhysicalWorld();
     344            deactivatePhysics();
    371345            delete this->physicalBody_;
    372346            this->physicalBody_ = 0;
     
    392366        }
    393367
    394         // update our variable for faster checks
     368        // Only sets this->collisionShape_
     369        // However the assertion is to ensure that the internal bullet setting is right
    395370        updateCollisionType();
    396371        assert(this->collisionType_ == type);
    397372
    398373        // update mass and inertia tensor
    399         internalSetMassProps(); // type is not None! See case None in switch
    400 
    401         addToPhysicalWorld();
     374        recalculatePhysicsProps();
     375        activatePhysics();
    402376    }
    403377
     
    450424    }
    451425
    452     bool WorldEntity::isPhysicsRunning() const
    453     {
    454         return this->physicalBody_ && this->physicalBody_->isInWorld();
    455     }
    456 
    457     bool WorldEntity::checkPhysics() const
    458     {
    459         if (!this->physicalBody_)
    460         {
    461             assert(this->getCollisionType() == None);
    462             COUT(2) << "WorldEntity was not fitted with physics, cannot set phyiscal property." << std::endl;
    463             return false;
    464         }
    465         else
    466             return true;
     426    void WorldEntity::notifyChildMassChanged() // Called by a child WE
     427    {
     428        // Note: CollisionShape changes of a child get handled over the internal CompoundCollisionShape already
     429        // Recalculate mass
     430        this->childrenMass_ = 0.0f;
     431        for (std::set<WorldEntity*>::const_iterator it = this->children_.begin(); it != this->children_.end(); ++it)
     432            this->childrenMass_ += (*it)->getMass();
     433        recalculatePhysicsProps();
     434        // Notify parent WE
     435        if (this->parent_)
     436            parent_->notifyChildMassChanged();
     437    }
     438
     439    void WorldEntity::notifyCollisionShapeChanged() // called by this->collisionShape_
     440    {
     441        if (hasPhysics())
     442        {
     443            // Bullet doesn't like sudden changes of the collision shape, so we remove and add it again
     444            if (this->addedToPhysicalWorld())
     445            {
     446                this->deactivatePhysics();
     447                this->physicalBody_->setCollisionShape(this->collisionShape_->getCollisionShape());
     448                this->activatePhysics();
     449            }
     450            else
     451                this->physicalBody_->setCollisionShape(this->collisionShape_->getCollisionShape());
     452        }
     453        recalculatePhysicsProps();
     454    }
     455
     456    void WorldEntity::recalculatePhysicsProps()
     457    {
     458        if (this->hasPhysics())
     459        {
     460            if (this->isStatic())
     461            {
     462                // Just set everything to zero
     463                this->physicalBody_->setMassProps(0.0f, btVector3(0, 0, 0));
     464            }
     465            else if ((this->mass_ + this->childrenMass_) == 0.0f)
     466            {
     467                // Use default values to avoid very large or very small values
     468                CCOUT(4) << "Warning: Setting the internal physical mass to 1.0 because mass_ is 0.0." << std::endl;
     469                this->physicalBody_->setMassProps(1.0f, this->collisionShape_->getLocalInertia(1.0f));
     470            }
     471            else
     472            {
     473                float mass = this->mass_ + this->childrenMass_;
     474                this->physicalBody_->setMassProps(mass, this->collisionShape_->getLocalInertia(mass));
     475            }
     476        }
    467477    }
    468478}
Note: See TracChangeset for help on using the changeset viewer.