btWorld.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "T3D/physics/bullet/btWorld.h"
  24. #include "T3D/physics/bullet/btPlugin.h"
  25. #include "T3D/physics/bullet/btCasts.h"
  26. #include "T3D/physics/physicsUserData.h"
  27. #include "core/stream/bitStream.h"
  28. #include "platform/profiler.h"
  29. #include "sim/netConnection.h"
  30. #include "console/console.h"
  31. #include "console/consoleTypes.h"
  32. #include "scene/sceneRenderState.h"
  33. #include "T3D/gameBase/gameProcess.h"
  34. BtWorld::BtWorld() :
  35. mProcessList( NULL ),
  36. mIsSimulating( false ),
  37. mErrorReport( false ),
  38. mTickCount( 0 ),
  39. mIsEnabled( false ),
  40. mEditorTimeScale( 1.0f ),
  41. mDynamicsWorld( NULL )
  42. {
  43. }
  44. BtWorld::~BtWorld()
  45. {
  46. }
  47. bool BtWorld::initWorld( bool isServer, ProcessList *processList )
  48. {
  49. // Collision configuration contains default setup for memory, collision setup.
  50. mCollisionConfiguration = new btDefaultCollisionConfiguration();
  51. mDispatcher = new btCollisionDispatcher( mCollisionConfiguration );
  52. btVector3 worldMin( -2000, -2000, -1000 );
  53. btVector3 worldMax( 2000, 2000, 1000 );
  54. btAxisSweep3 *sweepBP = new btAxisSweep3( worldMin, worldMax );
  55. mBroadphase = sweepBP;
  56. sweepBP->getOverlappingPairCache()->setInternalGhostPairCallback( new btGhostPairCallback() );
  57. // The default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded).
  58. mSolver = new btSequentialImpulseConstraintSolver;
  59. mDynamicsWorld = new btDiscreteDynamicsWorld( mDispatcher, mBroadphase, mSolver, mCollisionConfiguration );
  60. if ( !mDynamicsWorld )
  61. {
  62. Con::errorf( "BtWorld - %s failed to create dynamics world!", isServer ? "Server" : "Client" );
  63. return false;
  64. }
  65. // Removing the randomization in the solver is required
  66. // to make the simulation deterministic.
  67. mDynamicsWorld->getSolverInfo().m_solverMode &= ~SOLVER_RANDMIZE_ORDER;
  68. mDynamicsWorld->setGravity( btCast<btVector3>( mGravity ) );
  69. AssertFatal( processList, "BtWorld::init() - We need a process list to create the world!" );
  70. mProcessList = processList;
  71. mProcessList->preTickSignal().notify( this, &BtWorld::getPhysicsResults );
  72. mProcessList->postTickSignal().notify( this, &BtWorld::tickPhysics, 1000.0f );
  73. return true;
  74. }
  75. void BtWorld::_destroy()
  76. {
  77. // Release the tick processing signals.
  78. if ( mProcessList )
  79. {
  80. mProcessList->preTickSignal().remove( this, &BtWorld::getPhysicsResults );
  81. mProcessList->postTickSignal().remove( this, &BtWorld::tickPhysics );
  82. mProcessList = NULL;
  83. }
  84. // TODO: Release any remaining
  85. // orphaned rigid bodies here.
  86. SAFE_DELETE( mDynamicsWorld );
  87. SAFE_DELETE( mSolver );
  88. SAFE_DELETE( mBroadphase );
  89. SAFE_DELETE( mDispatcher );
  90. SAFE_DELETE( mCollisionConfiguration );
  91. }
  92. void BtWorld::tickPhysics( U32 elapsedMs )
  93. {
  94. if ( !mDynamicsWorld || !mIsEnabled )
  95. return;
  96. // Did we forget to call getPhysicsResults somewhere?
  97. AssertFatal( !mIsSimulating, "BtWorld::tickPhysics() - Already simulating!" );
  98. // The elapsed time should be non-zero and
  99. // a multiple of TickMs!
  100. AssertFatal( elapsedMs != 0 &&
  101. ( elapsedMs % TickMs ) == 0 , "BtWorld::tickPhysics() - Got bad elapsed time!" );
  102. PROFILE_SCOPE(BtWorld_TickPhysics);
  103. // Convert it to seconds.
  104. const F32 elapsedSec = (F32)elapsedMs * 0.001f;
  105. // Simulate
  106. mDynamicsWorld->stepSimulation( elapsedSec * mEditorTimeScale, smPhysicsMaxSubSteps, smPhysicsStepTime);
  107. mIsSimulating = true;
  108. //Con::printf( "%s BtWorld::tickPhysics!", this == smClientWorld ? "Client" : "Server" );
  109. }
  110. void BtWorld::getPhysicsResults()
  111. {
  112. if ( !mDynamicsWorld || !mIsSimulating )
  113. return;
  114. PROFILE_SCOPE(BtWorld_GetPhysicsResults);
  115. // Get results from scene.
  116. // mScene->fetchResults( NX_RIGID_BODY_FINISHED, true );
  117. mIsSimulating = false;
  118. mTickCount++;
  119. }
  120. void BtWorld::setEnabled( bool enabled )
  121. {
  122. mIsEnabled = enabled;
  123. if ( !mIsEnabled )
  124. getPhysicsResults();
  125. }
  126. void BtWorld::destroyWorld()
  127. {
  128. _destroy();
  129. }
  130. bool BtWorld::castRay( const Point3F &startPnt, const Point3F &endPnt, RayInfo *ri, const Point3F &impulse )
  131. {
  132. btCollisionWorld::ClosestRayResultCallback result( btCast<btVector3>( startPnt ), btCast<btVector3>( endPnt ) );
  133. mDynamicsWorld->rayTest( btCast<btVector3>( startPnt ), btCast<btVector3>( endPnt ), result );
  134. if ( !result.hasHit() || !result.m_collisionObject )
  135. return false;
  136. if ( ri )
  137. {
  138. ri->object = PhysicsUserData::getObject( result.m_collisionObject->getUserPointer() );
  139. // If we were passed a RayInfo, we can only return true signifying a collision
  140. // if we hit an object that actually has a torque object associated with it.
  141. //
  142. // In some ways this could be considered an error, either a physx object
  143. // has raycast-collision enabled that shouldn't or someone did not set
  144. // an object in this actor's userData.
  145. //
  146. if ( ri->object == NULL )
  147. return false;
  148. ri->distance = ( endPnt - startPnt ).len() * result.m_closestHitFraction;
  149. ri->normal = btCast<Point3F>( result.m_hitNormalWorld );
  150. ri->point = btCast<Point3F>( result.m_hitPointWorld );
  151. ri->t = result.m_closestHitFraction;
  152. }
  153. /*
  154. if ( impulse.isZero() ||
  155. !actor.isDynamic() ||
  156. actor.readBodyFlag( NX_BF_KINEMATIC ) )
  157. return true;
  158. NxVec3 force = pxCast<NxVec3>( impulse );//worldRay.dir * forceAmt;
  159. actor.addForceAtPos( force, hitInfo.worldImpact, NX_IMPULSE );
  160. */
  161. return true;
  162. }
  163. PhysicsBody* BtWorld::castRay( const Point3F &start, const Point3F &end, U32 bodyTypes )
  164. {
  165. btVector3 startPt = btCast<btVector3>( start );
  166. btVector3 endPt = btCast<btVector3>( end );
  167. btCollisionWorld::ClosestRayResultCallback result( startPt, endPt );
  168. mDynamicsWorld->rayTest( startPt, endPt, result );
  169. if ( !result.hasHit() || !result.m_collisionObject )
  170. return NULL;
  171. PhysicsUserData *userData = PhysicsUserData::cast( result.m_collisionObject->getUserPointer() );
  172. if ( !userData )
  173. return NULL;
  174. return userData->getBody();
  175. }
  176. void BtWorld::explosion( const Point3F &pos, F32 radius, F32 forceMagnitude )
  177. {
  178. /*
  179. // Find Actors at the position within the radius
  180. // and apply force to them.
  181. NxVec3 nxPos = pxCast<NxVec3>( pos );
  182. NxShape **shapes = (NxShape**)NxAlloca(10*sizeof(NxShape*));
  183. NxSphere worldSphere( nxPos, radius );
  184. NxU32 numHits = mScene->overlapSphereShapes( worldSphere, NX_ALL_SHAPES, 10, shapes, NULL );
  185. for ( NxU32 i = 0; i < numHits; i++ )
  186. {
  187. NxActor &actor = shapes[i]->getActor();
  188. bool dynamic = actor.isDynamic();
  189. if ( !dynamic )
  190. continue;
  191. bool kinematic = actor.readBodyFlag( NX_BF_KINEMATIC );
  192. if ( kinematic )
  193. continue;
  194. NxVec3 force = actor.getGlobalPosition() - nxPos;
  195. force.normalize();
  196. force *= forceMagnitude;
  197. actor.addForceAtPos( force, nxPos, NX_IMPULSE, true );
  198. }
  199. */
  200. }
  201. void BtWorld::onDebugDraw( const SceneRenderState *state )
  202. {
  203. mDebugDraw.setCuller( &state->getCullingFrustum() );
  204. mDynamicsWorld->setDebugDrawer( &mDebugDraw );
  205. mDynamicsWorld->debugDrawWorld();
  206. mDynamicsWorld->setDebugDrawer( NULL );
  207. mDebugDraw.flush();
  208. }
  209. void BtWorld::reset()
  210. {
  211. if ( !mDynamicsWorld )
  212. return;
  213. ///create a copy of the array, not a reference!
  214. btCollisionObjectArray copyArray = mDynamicsWorld->getCollisionObjectArray();
  215. S32 numObjects = mDynamicsWorld->getNumCollisionObjects();
  216. for ( S32 i=0; i < numObjects; i++ )
  217. {
  218. btCollisionObject* colObj = copyArray[i];
  219. btRigidBody* body = btRigidBody::upcast(colObj);
  220. if (body)
  221. {
  222. if (body->getMotionState())
  223. {
  224. //btDefaultMotionState* myMotionState = (btDefaultMotionState*)body->getMotionState();
  225. //myMotionState->m_graphicsWorldTrans = myMotionState->m_startWorldTrans;
  226. //body->setCenterOfMassTransform( myMotionState->m_graphicsWorldTrans );
  227. //colObj->setInterpolationWorldTransform( myMotionState->m_startWorldTrans );
  228. colObj->forceActivationState(ACTIVE_TAG);
  229. colObj->activate();
  230. colObj->setDeactivationTime(0);
  231. //colObj->setActivationState(WANTS_DEACTIVATION);
  232. }
  233. //removed cached contact points (this is not necessary if all objects have been removed from the dynamics world)
  234. //m_dynamicsWorld->getBroadphase()->getOverlappingPairCache()->cleanProxyFromPairs(colObj->getBroadphaseHandle(),getDynamicsWorld()->getDispatcher());
  235. btRigidBody* body = btRigidBody::upcast(colObj);
  236. if (body && !body->isStaticObject())
  237. {
  238. btRigidBody::upcast(colObj)->setLinearVelocity(btVector3(0,0,0));
  239. btRigidBody::upcast(colObj)->setAngularVelocity(btVector3(0,0,0));
  240. }
  241. }
  242. }
  243. // reset some internal cached data in the broadphase
  244. mDynamicsWorld->getBroadphase()->resetPool( mDynamicsWorld->getDispatcher() );
  245. mDynamicsWorld->getConstraintSolver()->reset();
  246. }
  247. /*
  248. ConsoleFunction( castForceRay, const char*, 4, 4, "( Point3F startPnt, Point3F endPnt, VectorF impulseVec )" )
  249. {
  250. PhysicsWorld *world = PHYSICSPLUGIN->getWorld( "server" );
  251. if ( !world )
  252. return NULL;
  253. char *returnBuffer = Con::getReturnBuffer(256);
  254. Point3F impulse;
  255. Point3F startPnt, endPnt;
  256. dSscanf( argv[1], "%f %f %f", &startPnt.x, &startPnt.y, &startPnt.z );
  257. dSscanf( argv[2], "%f %f %f", &endPnt.x, &endPnt.y, &endPnt.z );
  258. dSscanf( argv[3], "%f %f %f", &impulse.x, &impulse.y, &impulse.z );
  259. Point3F hitPoint;
  260. RayInfo rinfo;
  261. bool hit = world->castRay( startPnt, endPnt, &rinfo, impulse );
  262. DebugDrawer *ddraw = DebugDrawer::get();
  263. if ( ddraw )
  264. {
  265. ddraw->drawLine( startPnt, endPnt, hit ? ColorF::RED : ColorF::GREEN );
  266. ddraw->setLastTTL( 3000 );
  267. }
  268. if ( hit )
  269. {
  270. dSprintf(returnBuffer, 256, "%g %g %g",
  271. rinfo.point.x, rinfo.point.y, rinfo.point.z );
  272. return returnBuffer;
  273. }
  274. else
  275. return NULL;
  276. }
  277. */