- Timestamp:
- Dec 14, 2008, 4:16:52 PM (16 years ago)
- Location:
- code/branches/physics_merge
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
code/branches/physics_merge
- Property svn:mergeinfo changed
-
code/branches/physics_merge/src/orxonox/objects/worldentities/WorldEntity.cc
r2371 r2442 22 22 * Author: 23 23 * Fabian 'x3n' Landau 24 * Reto Grieder (physics) 24 25 * Co-authors: 25 26 * ... … … 31 32 32 33 #include <cassert> 34 #include <OgreSceneNode.h> 33 35 #include <OgreSceneManager.h> 34 36 #include "BulletDynamics/Dynamics/btRigidBody.h" 37 38 #include "util/Exception.h" 39 #include "util/Convert.h" 35 40 #include "core/CoreIncludes.h" 36 41 #include "core/XMLPort.h" 37 #include "util/Convert.h"38 #include "util/Exception.h"39 42 40 43 #include "objects/Scene.h" 44 #include "objects/collisionshapes/CompoundCollisionShape.h" 41 45 42 46 namespace orxonox … … 64 68 this->node_->setOrientation(Quaternion::IDENTITY); 65 69 70 // Default behaviour does not include physics 71 this->physicalBody_ = 0; 72 this->bPhysicsActive_ = false; 73 this->collisionShape_ = new CompoundCollisionShape(this); 74 this->collisionType_ = None; 75 this->collisionTypeSynchronised_ = None; 76 this->mass_ = 0; 77 this->childrenMass_ = 0; 78 // Use bullet default values 79 this->restitution_ = 0; 80 this->angularFactor_ = 1; 81 this->linearDamping_ = 0; 82 this->angularDamping_ = 0; 83 this->friction_ = 0.5; 84 66 85 this->registerVariables(); 67 86 } … … 74 93 if (this->getScene()->getSceneManager()) 75 94 this->getScene()->getSceneManager()->destroySceneNode(this->node_->getName()); 95 96 // TODO: Detach from parent and detach all children. 97 98 if (this->physicalBody_) 99 { 100 this->deactivatePhysics(); 101 delete this->physicalBody_; 102 } 103 delete this->collisionShape_; 76 104 } 77 105 } … … 81 109 SUPER(WorldEntity, XMLPort, xmlelement, mode); 82 110 83 XMLPortParamTemplate(WorldEntity, "position", setPosition, getPosition,xmlelement, mode, const Vector3&);111 XMLPortParamTemplate(WorldEntity, "position", setPosition, getPosition, xmlelement, mode, const Vector3&); 84 112 XMLPortParamTemplate(WorldEntity, "orientation", setOrientation, getOrientation, xmlelement, mode, const Quaternion&); 85 XMLPortParamLoadOnly(WorldEntity, "lookat", lookAt_xmlport, xmlelement, mode); 86 XMLPortParamLoadOnly(WorldEntity, "direction", setDirection_xmlport, xmlelement, mode); 87 XMLPortParamLoadOnly(WorldEntity, "yaw", yaw_xmlport, xmlelement, mode); 88 XMLPortParamLoadOnly(WorldEntity, "pitch", pitch_xmlport, xmlelement, mode); 89 XMLPortParamLoadOnly(WorldEntity, "roll", roll_xmlport, xmlelement, mode); 90 XMLPortParamTemplate(WorldEntity, "scale3D", setScale3D, getScale3D, xmlelement, mode, const Vector3&); 91 XMLPortParam(WorldEntity, "scale", setScale, getScale, xmlelement, mode); 92 113 XMLPortParamTemplate(WorldEntity, "scale3D", setScale3D, getScale3D, xmlelement, mode, const Vector3&); 114 XMLPortParam (WorldEntity, "scale", setScale, getScale, xmlelement, mode); 115 XMLPortParamLoadOnly(WorldEntity, "lookat", lookAt_xmlport, xmlelement, mode); 116 XMLPortParamLoadOnly(WorldEntity, "direction", setDirection_xmlport, xmlelement, mode); 117 XMLPortParamLoadOnly(WorldEntity, "yaw", yaw_xmlport, xmlelement, mode); 118 XMLPortParamLoadOnly(WorldEntity, "pitch", pitch_xmlport, xmlelement, mode); 119 XMLPortParamLoadOnly(WorldEntity, "roll", roll_xmlport, xmlelement, mode); 120 121 // Physics 122 XMLPortParam(WorldEntity, "collisionType", setCollisionTypeStr, getCollisionTypeStr, xmlelement, mode); 123 XMLPortParam(WorldEntity, "mass", setMass, getMass, xmlelement, mode); 124 XMLPortParam(WorldEntity, "restitution", setRestitution, getRestitution, xmlelement, mode); 125 XMLPortParam(WorldEntity, "angularFactor", setAngularFactor, getAngularFactor, xmlelement, mode); 126 XMLPortParam(WorldEntity, "linearDamping", setLinearDamping, getLinearDamping, xmlelement, mode); 127 XMLPortParam(WorldEntity, "angularDamping", setAngularDamping, getAngularDamping, xmlelement, mode); 128 XMLPortParam(WorldEntity, "friction", setFriction, getFriction, xmlelement, mode); 129 130 // Other attached WorldEntities 93 131 XMLPortObject(WorldEntity, WorldEntity, "attached", attach, getAttachedObject, xmlelement, mode); 132 // Attached collision shapes 133 XMLPortObject(WorldEntity, CollisionShape, "collisionShapes", attachCollisionShape, getAttachedCollisionShape, xmlelement, mode); 94 134 } 95 135 96 136 void WorldEntity::registerVariables() 97 137 { 98 registerVariable(this->bActive_, variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::changedActivity)); 99 registerVariable(this->bVisible_, variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::changedVisibility)); 100 101 registerVariable(this->getScale3D().x, variableDirection::toclient); 102 registerVariable(this->getScale3D().y, variableDirection::toclient); 103 registerVariable(this->getScale3D().z, variableDirection::toclient); 104 105 registerVariable(this->parentID_, variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::updateParent)); 106 } 107 108 void WorldEntity::updateParent() 138 registerVariable(this->bActive_, variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::changedActivity)); 139 registerVariable(this->bVisible_, variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::changedVisibility)); 140 141 registerVariable(this->getScale3D(), variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::scaleChanged)); 142 143 registerVariable((int&)this->collisionTypeSynchronised_, 144 variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::collisionTypeChanged)); 145 registerVariable(this->mass_, variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::massChanged)); 146 registerVariable(this->restitution_, variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::restitutionChanged)); 147 registerVariable(this->angularFactor_, variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::angularFactorChanged)); 148 registerVariable(this->linearDamping_, variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::linearDampingChanged)); 149 registerVariable(this->angularDamping_, variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::angularDampingChanged)); 150 registerVariable(this->friction_, variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::frictionChanged)); 151 registerVariable(this->bPhysicsActiveSynchronised_, 152 variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::physicsActivityChanged)); 153 154 registerVariable(this->parentID_, variableDirection::toclient, new NetworkCallback<WorldEntity>(this, &WorldEntity::parentChanged)); 155 } 156 157 void WorldEntity::parentChanged() 109 158 { 110 159 if (this->parentID_ != OBJECTID_UNKNOWN) … … 116 165 } 117 166 167 void WorldEntity::collisionTypeChanged() 168 { 169 if (this->collisionTypeSynchronised_ != Dynamic && 170 this->collisionTypeSynchronised_ != Kinematic && 171 this->collisionTypeSynchronised_ != Static && 172 this->collisionTypeSynchronised_ != None) 173 { 174 CCOUT(1) << "Error when collsion Type was received over network. Unknown enum value:" << this->collisionTypeSynchronised_ << std::endl; 175 } 176 else if (this->collisionTypeSynchronised_ != collisionType_) 177 { 178 if (this->parent_) 179 CCOUT(2) << "Warning: Network connection tried to set the collision type of an attached WE. Ignoring." << std::endl; 180 else 181 this->setCollisionType(this->collisionTypeSynchronised_); 182 } 183 } 184 185 void WorldEntity::physicsActivityChanged() 186 { 187 if (this->bPhysicsActiveSynchronised_) 188 this->activatePhysics(); 189 else 190 this->deactivatePhysics(); 191 } 192 118 193 void WorldEntity::attach(WorldEntity* object) 119 194 { 195 // check first whether attaching is even allowed 196 if (object->hasPhysics()) 197 { 198 if (!this->hasPhysics()) 199 { 200 COUT(2) << "Warning: Cannot attach a physical object to a non physical one." << std::endl; 201 return; 202 } 203 else if (object->isDynamic()) 204 { 205 COUT(2) << "Warning: Cannot attach a dynamic object to a WorldEntity." << std::endl; 206 return; 207 } 208 else if (object->isKinematic() && this->isDynamic()) 209 { 210 COUT(2) << "Warning: Cannot attach a kinematic object to a dynamic one." << std::endl; 211 return; 212 } 213 else if (object->isKinematic()) 214 { 215 COUT(2) << "Warning: Cannot attach a kinematic object to a static or kinematic one: Not yet implemented." << std::endl; 216 return; 217 } 218 else 219 { 220 object->deactivatePhysics(); 221 } 222 } 223 120 224 if (object->getParent()) 121 225 object->detachFromParent(); … … 131 235 object->parent_ = this; 132 236 object->parentID_ = this->getObjectID(); 237 238 // collision shapes 239 this->attachCollisionShape(object->getCollisionShape()); 240 // mass 241 this->childrenMass_ += object->getMass(); 242 recalculateMassProps(); 133 243 } 134 244 135 245 void WorldEntity::detach(WorldEntity* object) 136 246 { 247 // collision shapes 248 this->detachCollisionShape(object->getCollisionShape()); 249 // mass 250 if (object->getMass() > 0.0f) 251 { 252 this->childrenMass_ -= object->getMass(); 253 recalculateMassProps(); 254 } 255 137 256 this->node_->removeChild(object->node_); 138 257 this->children_.erase(object); 139 258 object->parent_ = 0; 140 259 object->parentID_ = OBJECTID_UNKNOWN; 141 142 260 // this->getScene()->getRootSceneNode()->addChild(object->node_); 261 262 // Note: It is possible that the object has physics but was disabled when attaching 263 object->activatePhysics(); 143 264 } 144 265 … … 154 275 return 0; 155 276 } 277 278 void WorldEntity::attachOgreObject(Ogre::MovableObject* object) 279 { 280 this->node_->attachObject(object); 281 } 282 283 void WorldEntity::detachOgreObject(Ogre::MovableObject* object) 284 { 285 this->node_->detachObject(object); 286 } 287 288 Ogre::MovableObject* WorldEntity::detachOgreObject(const Ogre::String& name) 289 { 290 return this->node_->detachObject(name); 291 } 292 293 void WorldEntity::attachCollisionShape(CollisionShape* shape) 294 { 295 this->collisionShape_->addChildShape(shape); 296 // Note: this->collisionShape_ already notifies us of any changes. 297 } 298 299 void WorldEntity::detachCollisionShape(CollisionShape* shape) 300 { 301 this->collisionShape_->removeChildShape(shape); 302 // Note: this->collisionShape_ already notifies us of any changes. 303 } 304 305 CollisionShape* WorldEntity::getAttachedCollisionShape(unsigned int index) const 306 { 307 return this->collisionShape_->getChildShape(index); 308 } 309 310 void WorldEntity::activatePhysics() 311 { 312 if (this->isActive() && this->hasPhysics() && !this->isPhysicsActive() && !this->parent_) 313 { 314 this->getScene()->addRigidBody(this->physicalBody_); 315 this->bPhysicsActive_ = true; 316 } 317 } 318 319 void WorldEntity::deactivatePhysics() 320 { 321 if (this->isPhysicsActive()) 322 { 323 this->getScene()->removeRigidBody(this->physicalBody_); 324 this->bPhysicsActive_ = false; 325 } 326 } 327 328 bool WorldEntity::addedToPhysicalWorld() const 329 { 330 return this->physicalBody_ && this->physicalBody_->isInWorld(); 331 } 332 333 #ifndef _NDEBUG 334 const Vector3& WorldEntity::getPosition() const 335 { 336 return this->node_->getPosition(); 337 } 338 339 const Quaternion& WorldEntity::getOrientation() const 340 { 341 return this->node_->getOrientation(); 342 } 343 344 const Vector3& WorldEntity::getScale3D() const 345 { 346 return this->node_->getScale(); 347 } 348 #endif 349 350 const Vector3& WorldEntity::getWorldPosition() const 351 { 352 return this->node_->_getDerivedPosition(); 353 } 354 355 const Quaternion& WorldEntity::getWorldOrientation() const 356 { 357 return this->node_->_getDerivedOrientation(); 358 } 359 360 void WorldEntity::translate(const Vector3& distance, TransformSpace::Space relativeTo) 361 { 362 switch (relativeTo) 363 { 364 case TransformSpace::Local: 365 // position is relative to parent so transform downwards 366 this->setPosition(this->getPosition() + this->getOrientation() * distance); 367 break; 368 case TransformSpace::Parent: 369 this->setPosition(this->getPosition() + distance); 370 break; 371 case TransformSpace::World: 372 // position is relative to parent so transform upwards 373 if (this->node_->getParent()) 374 setPosition(getPosition() + (node_->getParent()->_getDerivedOrientation().Inverse() * distance) 375 / node_->getParent()->_getDerivedScale()); 376 else 377 this->setPosition(this->getPosition() + distance); 378 break; 379 } 380 } 381 382 void WorldEntity::rotate(const Quaternion& rotation, TransformSpace::Space relativeTo) 383 { 384 switch(relativeTo) 385 { 386 case TransformSpace::Local: 387 this->setOrientation(this->getOrientation() * rotation); 388 break; 389 case TransformSpace::Parent: 390 // Rotations are normally relative to local axes, transform up 391 this->setOrientation(rotation * this->getOrientation()); 392 break; 393 case TransformSpace::World: 394 // Rotations are normally relative to local axes, transform up 395 this->setOrientation(this->getOrientation() * this->getWorldOrientation().Inverse() 396 * rotation * this->getWorldOrientation()); 397 break; 398 } 399 } 400 401 void WorldEntity::lookAt(const Vector3& target, TransformSpace::Space relativeTo, const Vector3& localDirectionVector) 402 { 403 Vector3 origin; 404 switch (relativeTo) 405 { 406 case TransformSpace::Local: 407 origin = Vector3::ZERO; 408 break; 409 case TransformSpace::Parent: 410 origin = this->getPosition(); 411 break; 412 case TransformSpace::World: 413 origin = this->getWorldPosition(); 414 break; 415 } 416 this->setDirection(target - origin, relativeTo, localDirectionVector); 417 } 418 419 void WorldEntity::setDirection(const Vector3& direction, TransformSpace::Space relativeTo, const Vector3& localDirectionVector) 420 { 421 Quaternion savedOrientation(this->getOrientation()); 422 Ogre::Node::TransformSpace ogreRelativeTo; 423 switch (relativeTo) 424 { 425 case TransformSpace::Local: 426 ogreRelativeTo = Ogre::Node::TS_LOCAL; break; 427 case TransformSpace::Parent: 428 ogreRelativeTo = Ogre::Node::TS_PARENT; break; 429 case TransformSpace::World: 430 ogreRelativeTo = Ogre::Node::TS_WORLD; break; 431 } 432 this->node_->setDirection(direction, ogreRelativeTo, localDirectionVector); 433 Quaternion newOrientation(this->node_->getOrientation()); 434 this->node_->setOrientation(savedOrientation); 435 this->setOrientation(newOrientation); 436 } 437 438 void WorldEntity::setScale3D(const Vector3& scale) 439 { 440 if (this->hasPhysics()) 441 { 442 CCOUT(2) << "Warning: Cannot set the scale of a physical object: Not yet implemented." << std::endl; 443 return; 444 } 445 446 this->node_->setScale(scale); 447 } 448 449 void WorldEntity::setCollisionType(CollisionType type) 450 { 451 // If we are already attached to a parent, this would be a bad idea.. 452 if (this->parent_) 453 { 454 CCOUT(2) << "Warning: Cannot set the collision type of a WorldEntity with a parent." << std::endl; 455 return; 456 } 457 else if (this->addedToPhysicalWorld()) 458 { 459 CCOUT(2) << "Warning: Cannot set the collision type at run time." << std::endl; 460 return; 461 } 462 463 // Check for type legality. Could be StaticEntity or MobileEntity 464 if (!this->isCollisionTypeLegal(type)) 465 return; // exception gets issued anyway 466 if (type != None && !this->getScene()->hasPhysics()) 467 { 468 CCOUT(2) << "Warning: Cannot have physical bodies in a non physical scene." << std::endl; 469 return; 470 } 471 472 // Check whether we have to create or destroy. 473 if (type != None && this->collisionType_ == None) 474 { 475 // Check whether there was some scaling applied. 476 if (!this->node_->getScale().positionEquals(Vector3(1, 1, 1), 0.001)) 477 { 478 CCOUT(2) << "Warning: Cannot create a physical body if there is scaling applied to the node: Not yet implemented." << std::endl; 479 return; 480 } 481 482 // Create new rigid body 483 btRigidBody::btRigidBodyConstructionInfo bodyConstructionInfo(0, this, this->collisionShape_->getCollisionShape()); 484 this->physicalBody_ = new btRigidBody(bodyConstructionInfo); 485 this->physicalBody_->setUserPointer(this); 486 this->physicalBody_->setActivationState(DISABLE_DEACTIVATION); 487 } 488 else if (type == None && this->collisionType_ != None) 489 { 490 // Destroy rigid body 491 assert(this->physicalBody_); 492 deactivatePhysics(); 493 delete this->physicalBody_; 494 this->physicalBody_ = 0; 495 this->collisionType_ = None; 496 this->collisionTypeSynchronised_ = None; 497 return; 498 } 499 500 // Change type 501 switch (type) 502 { 503 case Dynamic: 504 this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !(btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_KINEMATIC_OBJECT)); 505 break; 506 case Kinematic: 507 this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_KINEMATIC_OBJECT); 508 break; 509 case Static: 510 this->physicalBody_->setCollisionFlags(this->physicalBody_->getCollisionFlags() & !btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_STATIC_OBJECT); 511 break; 512 case None: 513 return; // this->collisionType_ was None too 514 } 515 516 // Only sets this->collisionShape_ 517 // However the assertion is to ensure that the internal bullet setting is right 518 updateCollisionType(); 519 assert(this->collisionType_ == type); 520 521 // update mass and inertia tensor 522 recalculateMassProps(); 523 resetPhysicsProps(); 524 activatePhysics(); 525 } 526 527 void WorldEntity::setCollisionTypeStr(const std::string& typeStr) 528 { 529 std::string typeStrLower = getLowercase(typeStr); 530 CollisionType type; 531 if (typeStrLower == "dynamic") 532 type = Dynamic; 533 else if (typeStrLower == "static") 534 type = Static; 535 else if (typeStrLower == "kinematic") 536 type = Kinematic; 537 else if (typeStrLower == "none") 538 type = None; 539 else 540 ThrowException(ParseError, std::string("Attempting to set an unknown collision type: '") + typeStr + "'."); 541 this->setCollisionType(type); 542 } 543 544 std::string WorldEntity::getCollisionTypeStr() const 545 { 546 switch (this->getCollisionType()) 547 { 548 case Dynamic: 549 return "dynamic"; 550 case Kinematic: 551 return "kinematic"; 552 case Static: 553 return "static"; 554 case None: 555 return "none"; 556 default: 557 assert(false); 558 return ""; 559 } 560 } 561 562 void WorldEntity::updateCollisionType() 563 { 564 if (!this->physicalBody_) 565 this->collisionType_ = None; 566 else if (this->physicalBody_->isKinematicObject()) 567 this->collisionType_ = Kinematic; 568 else if (this->physicalBody_->isStaticObject()) 569 this->collisionType_ = Static; 570 else 571 this->collisionType_ = Dynamic; 572 this->collisionTypeSynchronised_ = this->collisionType_; 573 } 574 575 void WorldEntity::notifyChildMassChanged() // Called by a child WE 576 { 577 // Note: CollisionShape changes of a child get handled over the internal CompoundCollisionShape already 578 // Recalculate mass 579 this->childrenMass_ = 0.0f; 580 for (std::set<WorldEntity*>::const_iterator it = this->children_.begin(); it != this->children_.end(); ++it) 581 this->childrenMass_ += (*it)->getMass(); 582 recalculateMassProps(); 583 // Notify parent WE 584 if (this->parent_) 585 parent_->notifyChildMassChanged(); 586 } 587 588 void WorldEntity::notifyCollisionShapeChanged() // called by this->collisionShape_ 589 { 590 if (hasPhysics()) 591 { 592 // Bullet doesn't like sudden changes of the collision shape, so we remove and add it again 593 if (this->addedToPhysicalWorld()) 594 { 595 this->deactivatePhysics(); 596 this->physicalBody_->setCollisionShape(this->collisionShape_->getCollisionShape()); 597 this->activatePhysics(); 598 } 599 else 600 this->physicalBody_->setCollisionShape(this->collisionShape_->getCollisionShape()); 601 } 602 recalculateMassProps(); 603 } 604 605 void WorldEntity::recalculateMassProps() 606 { 607 if (this->hasPhysics()) 608 { 609 if (this->isStatic()) 610 { 611 // Just set everything to zero 612 this->physicalBody_->setMassProps(0.0f, btVector3(0, 0, 0)); 613 } 614 else if ((this->mass_ + this->childrenMass_) == 0.0f) 615 { 616 // Use default values to avoid very large or very small values 617 CCOUT(4) << "Warning: Setting the internal physical mass to 1.0 because mass_ is 0.0." << std::endl; 618 this->physicalBody_->setMassProps(1.0f, this->collisionShape_->getLocalInertia(1.0f)); 619 } 620 else 621 { 622 float mass = this->mass_ + this->childrenMass_; 623 this->physicalBody_->setMassProps(mass, this->collisionShape_->getLocalInertia(mass)); 624 } 625 } 626 } 627 628 void WorldEntity::resetPhysicsProps() 629 { 630 if (this->hasPhysics()) 631 { 632 this->physicalBody_->setRestitution(this->restitution_); 633 this->physicalBody_->setAngularFactor(this->angularFactor_); 634 this->physicalBody_->setDamping(this->linearDamping_, this->angularDamping_); 635 this->physicalBody_->setFriction(this->friction_); 636 } 637 } 156 638 }
Note: See TracChangeset
for help on using the changeset viewer.