physicsDebris.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726
  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/physicsDebris.h"
  24. #include "core/stream/bitStream.h"
  25. #include "math/mathUtils.h"
  26. #include "console/consoleTypes.h"
  27. #include "console/consoleObject.h"
  28. #include "console/engineAPI.h"
  29. #include "sim/netConnection.h"
  30. #include "scene/sceneRenderState.h"
  31. #include "scene/sceneManager.h"
  32. #include "ts/tsShapeInstance.h"
  33. #include "T3D/gameBase/gameProcess.h"
  34. #include "core/resourceManager.h"
  35. #include "gfx/gfxTransformSaver.h"
  36. #include "lighting/lightQuery.h"
  37. #include "T3D/physics/physicsBody.h"
  38. #include "T3D/physics/physicsCollision.h"
  39. #include "T3D/physics/physicsWorld.h"
  40. #include "collision/concretePolyList.h"
  41. #include "T3D/physics/physicsPlugin.h"
  42. #include "math/mathUtils.h"
  43. #include "gui/worldEditor/worldEditor.h"
  44. #include "T3D/containerQuery.h"
  45. F32 PhysicsDebris::smLifetimeScale = 1.0f;
  46. IMPLEMENT_CO_DATABLOCK_V1( PhysicsDebrisData );
  47. ConsoleDocClass( PhysicsDebrisData,
  48. "@brief Defines the properties of a PhysicsDebris object.\n\n"
  49. "@see PhysicsDebris.\n"
  50. "@ingroup Physics"
  51. );
  52. PhysicsDebrisData::PhysicsDebrisData()
  53. : mass( 1.0f ),
  54. dynamicFriction( 0.0f ),
  55. staticFriction( 0.0f ),
  56. restitution( 0.0f ),
  57. linearDamping( 0.0f ),
  58. angularDamping( 0.0f ),
  59. linearSleepThreshold( 1.0f ),
  60. angularSleepThreshold( 1.0f ),
  61. waterDampingScale( 1.0f ),
  62. buoyancyDensity( 0.0f ),
  63. castShadows( true )
  64. {
  65. lifetime = 5.0f;
  66. lifetimeVariance = 0.0f;
  67. INIT_ASSET(Shape);
  68. }
  69. bool PhysicsDebrisData::onAdd()
  70. {
  71. if(!Parent::onAdd())
  72. return false;
  73. return true;
  74. }
  75. bool PhysicsDebrisData::preload( bool server, String &errorStr )
  76. {
  77. if ( Parent::preload( server, errorStr ) == false )
  78. return false;
  79. if ( server ) return true;
  80. if ( mShapeAsset.notNull() )
  81. {
  82. // Create a dummy shape to force the generation of shaders and materials
  83. // during the level load and not during gameplay.
  84. TSShapeInstance *pDummy = new TSShapeInstance( mShape, !server );
  85. delete pDummy;
  86. }
  87. else
  88. {
  89. errorStr = String::ToString("PhysicsDebrisData::load: Couldn't load shape asset \"%s\"", mShapeAssetId);
  90. return false;
  91. }
  92. return true;
  93. }
  94. void PhysicsDebrisData::initPersistFields()
  95. {
  96. addGroup( "Display" );
  97. addProtectedField( "shapeFile", TypeShapeFilename, Offset( mShapeName, PhysicsDebrisData ), &_setShapeData, &defaultProtectedGetFn,
  98. "@brief Path to the .DAE or .DTS file to use for this shape.\n\n"
  99. "Compatable with Live-Asset Reloading.", AbstractClassRep::FIELD_HideInInspectors);
  100. INITPERSISTFIELD_SHAPEASSET(Shape, PhysicsDebrisData, "@brief Shape to use with this debris.\n\n"
  101. "Compatable with Live-Asset Reloading.");
  102. addField( "castShadows", TypeBool, Offset( castShadows, PhysicsDebrisData ),
  103. "@brief Determines if the shape's shadow should be cast onto the environment.\n\n" );
  104. endGroup( "Display" );
  105. addGroup( "Physical Properties" );
  106. addField("lifetime", TypeF32, Offset( lifetime, PhysicsDebrisData ),
  107. "@brief Base time, in seconds, that debris persists after time of creation.\n\n"
  108. "@note A %PhysicsDebris' lifetime multiplied by it's $pref::PhysicsDebris::lifetimeScale "
  109. "must be equal to or greater than 1.0.\n\n");
  110. addField("lifetimeVariance", TypeF32, Offset( lifetimeVariance, PhysicsDebrisData ),
  111. "@brief Range of variation randomly applied to lifetime when debris is created.\n\n"
  112. "Represents the maximum amount of seconds that will be added or subtracted to a shape's base lifetime. "
  113. "A value of 0 will apply the same lifetime to each shape created.\n\n");
  114. addField( "mass", TypeF32, Offset( mass, PhysicsDebrisData ),
  115. "@brief Value representing the mass of the shape.\n\n"
  116. "A shape's mass influences the magnitude of any force applied to it. "
  117. "@note All PhysicsDebris objects are dynamic.");
  118. addField( "friction", TypeF32, Offset( dynamicFriction, PhysicsDebrisData ),
  119. "@brief Coefficient of kinetic %friction to be applied to the shape.\n\n"
  120. "Kinetic %friction reduces the velocity of a moving object while it is in contact with a surface. "
  121. "A larger coefficient will result in a larger reduction in velocity. "
  122. "A shape's friction should be smaller than it's staticFriction, but greater than 0.\n\n"
  123. "@note This value is only applied while an object is in motion. For an object starting at rest, see PhysicsDebrisData::staticFriction");
  124. addField( "staticFriction", TypeF32, Offset( staticFriction, PhysicsDebrisData ),
  125. "@brief Coefficient of static %friction to be applied to the shape.\n\n"
  126. "Static %friction determines the force needed to start moving an at-rest object in contact with a surface. "
  127. "If the force applied onto shape cannot overcome the force of static %friction, the shape will remain at rest. "
  128. "A higher coefficient will require a larger force to start motion. "
  129. "This value should be both greater than 0 and the PhysicsDebrisData::friction.\n\n"
  130. "@note This value is only applied while an object is at rest. For an object in motion, see PhysicsDebrisData::friction");
  131. addField( "restitution", TypeF32, Offset( restitution, PhysicsDebrisData ),
  132. "@brief Bounce coeffecient applied to the shape in response to a collision.\n\n"
  133. "Restitution is a ratio of a shape's velocity before and after a collision. "
  134. "A value of 0 will zero out a shape's post-collision velocity, making it stop on contact. "
  135. "Larger values will remove less velocity after a collision, making it \'bounce\' with greater force. "
  136. "Normal %restitution values range between 0 and 1.0."
  137. "@note Values near or equaling 1.0 are likely to cause undesirable results in the physics simulation."
  138. " Because of this, it is reccomended to avoid values close to 1.0");
  139. addField( "linearDamping", TypeF32, Offset( linearDamping, PhysicsDebrisData ),
  140. "@brief Value that reduces an object's linear velocity over time.\n\n"
  141. "Larger values will cause velocity to decay quicker.\n\n" );
  142. addField( "angularDamping", TypeF32, Offset( angularDamping, PhysicsDebrisData ),
  143. "@brief Value that reduces an object's rotational velocity over time.\n\n"
  144. "Larger values will cause velocity to decay quicker.\n\n" );
  145. addField( "linearSleepThreshold", TypeF32, Offset( linearSleepThreshold, PhysicsDebrisData ),
  146. "@brief Minimum linear velocity before the shape can be put to sleep.\n\n"
  147. "This should be a positive value. Shapes put to sleep will not be simulated in order to save system resources.\n\n"
  148. "@note The shape must be dynamic.");
  149. addField( "angularSleepThreshold", TypeF32, Offset( angularSleepThreshold, PhysicsDebrisData ),
  150. "@brief Minimum rotational velocity before the shape can be put to sleep.\n\n"
  151. "This should be a positive value. Shapes put to sleep will not be simulated in order to save system resources.\n\n"
  152. "@note The shape must be dynamic.");
  153. addField( "waterDampingScale", TypeF32, Offset( waterDampingScale, PhysicsDebrisData ),
  154. "@brief Scale to apply to linear and angular dampening while underwater.\n\n "
  155. "@see angularDamping linearDamping" );
  156. addField( "buoyancyDensity", TypeF32, Offset( buoyancyDensity, PhysicsDebrisData ),
  157. "@brief The density of this shape for purposes of calculating buoyant forces.\n\n"
  158. "The result of the calculated buoyancy is relative to the density of the WaterObject the PhysicsDebris is within."
  159. "@see WaterObject::density");
  160. endGroup( "Physical Properties" );
  161. Parent::initPersistFields();
  162. }
  163. void PhysicsDebrisData::packData(BitStream* stream)
  164. {
  165. Parent::packData(stream);
  166. stream->writeFlag( castShadows );
  167. stream->write( lifetime );
  168. stream->write( lifetimeVariance );
  169. stream->write( mass );
  170. stream->write( dynamicFriction );
  171. stream->write( staticFriction );
  172. stream->write( restitution );
  173. stream->write( linearDamping );
  174. stream->write( angularDamping );
  175. stream->write( linearSleepThreshold );
  176. stream->write( angularSleepThreshold );
  177. stream->write( waterDampingScale );
  178. stream->write( buoyancyDensity );
  179. PACKDATA_ASSET(Shape);
  180. }
  181. void PhysicsDebrisData::unpackData(BitStream* stream)
  182. {
  183. Parent::unpackData(stream);
  184. castShadows = stream->readFlag();
  185. stream->read( &lifetime );
  186. stream->read( &lifetimeVariance );
  187. stream->read( &mass );
  188. stream->read( &dynamicFriction );
  189. stream->read( &staticFriction );
  190. stream->read( &restitution );
  191. stream->read( &linearDamping );
  192. stream->read( &angularDamping );
  193. stream->read( &linearSleepThreshold );
  194. stream->read( &angularSleepThreshold );
  195. stream->read( &waterDampingScale );
  196. stream->read( &buoyancyDensity );
  197. UNPACKDATA_ASSET(Shape);
  198. }
  199. DefineEngineMethod( PhysicsDebrisData, preload, void, (), ,
  200. "@brief Loads some information to have readily available at simulation time.\n\n"
  201. "Forces generation of shaders, materials, and other data used by the %PhysicsDebris object. "
  202. "This function should be used while a level is loading in order to shorten "
  203. "the amount of time to create a PhysicsDebris in game.\n\n")
  204. {
  205. String errorStr;
  206. object->_setShape(object->getShape());
  207. if( !object->preload( false, errorStr ) )
  208. Con::errorf( "PhsysicsDebrisData::preload - error: %s", errorStr.c_str() );
  209. }
  210. IMPLEMENT_CO_NETOBJECT_V1( PhysicsDebris );
  211. ConsoleDocClass( PhysicsDebris,
  212. "@brief Represents one or more rigid bodies defined in a single mesh file with "
  213. "a limited lifetime.\n\n"
  214. "A PhysicsDebris object can be viewed as a single system capable of generating multiple "
  215. "@link PhysicsBody PhysicsBodies@endlink as debris when triggered. Vaguely similar to how "
  216. "a ParticleEmitter is capable of creating Particles, but isn't a particle in itself. "
  217. "After it's lifetime has elapsed, the object will be deleted.\n\n"
  218. "%PhysicsDebris loads a standard .DAE or .DTS file and creates a rigid body for "
  219. "each defined collision node.\n\n"
  220. "For collision nodes to work correctly, they must be setup as follows:\n"
  221. " - Visible mesh nodes are siblings of the collision node under a common parent dummy node.\n"
  222. " - Collision node is a child of its visible mesh node.\n\n"
  223. "Colmesh type nodes are NOT supported; physx and most standard rigid "
  224. "body simulations do not support arbitrary triangle meshs for dynamics "
  225. "do to the computational expense.\n\n"
  226. "Therefore, collision nodes must be one of the following:\n"
  227. " - Colbox\n"
  228. " - Colsphere\n"
  229. " - Colcapsule\n"
  230. " - Col (convex).\n\n"
  231. "%PhysicsDebris should NOT be created on the server.\n\n"
  232. "@ingroup Physics"
  233. );
  234. PhysicsDebris* PhysicsDebris::create( PhysicsDebrisData *datablock,
  235. const MatrixF &transform,
  236. const VectorF &linVel )
  237. {
  238. // Skip out if we don't have a datablock or the
  239. // global lifetime scale has it living less than
  240. // a second.
  241. if ( !datablock ||
  242. ( datablock->lifetime > 0.0f &&
  243. datablock->lifetime * smLifetimeScale < 1.0f ) )
  244. return NULL;
  245. PhysicsDebris *debris = new PhysicsDebris();
  246. debris->setDataBlock( datablock );
  247. debris->setTransform( transform );
  248. debris->mInitialLinVel = linVel;
  249. if ( !debris->registerObject() )
  250. {
  251. delete debris;
  252. return NULL;
  253. }
  254. return debris;
  255. }
  256. PhysicsDebris::PhysicsDebris()
  257. : mLifetime( 0.0f ),
  258. mInitialLinVel( Point3F::Zero ),
  259. mDataBlock( NULL ),
  260. mShapeInstance( NULL ),
  261. mWorld( NULL )
  262. {
  263. mTypeMask |= DebrisObjectType | DynamicShapeObjectType;
  264. // Only allocated client side.
  265. mNetFlags.set( IsGhost );
  266. }
  267. PhysicsDebris::~PhysicsDebris()
  268. {
  269. }
  270. void PhysicsDebris::initPersistFields()
  271. {
  272. Con::addVariable( "$pref::PhysicsDebris::lifetimeScale", TypeF32, &smLifetimeScale,
  273. "@brief Scales how long %PhysicsDebris will live before being removed.\n"
  274. "@note A value of 0 will disable PhysicsDebris entirely.");
  275. Parent::initPersistFields();
  276. }
  277. bool PhysicsDebris::onAdd()
  278. {
  279. AssertFatal( isClientObject(), "PhysicsDebris::onAdd - This shouldn't be added on the server!" );
  280. if ( !Parent::onAdd() )
  281. return false;
  282. if( !mDataBlock )
  283. {
  284. Con::errorf("PhysicsDebris::onAdd - Fail - No datablock");
  285. return false;
  286. }
  287. // If it has a fixed lifetime then calculate it.
  288. if ( mDataBlock->lifetime > 0.0f )
  289. {
  290. F32 lifeVar = (mDataBlock->lifetimeVariance * 2.0f * gRandGen.randF(-1.0,1.0)) - mDataBlock->lifetimeVariance;
  291. mLifetime = mDataBlock->lifetime + lifeVar;
  292. }
  293. // Setup our bounding box
  294. mObjBox = mDataBlock->mShape->mBounds;
  295. resetWorldBox();
  296. // Add it to the client scene.
  297. addToScene();
  298. // We add the debris to the net connection so that
  299. // it is cleaned up when the client disconnects.
  300. NetConnection *conn = NetConnection::getConnectionToServer();
  301. AssertFatal( conn != NULL, "PhysicsDebris::onAdd - Got null net connection!");
  302. conn->addObject(this);
  303. PhysicsPlugin::getPhysicsResetSignal().notify( this, &PhysicsDebris::_onPhysicsReset );
  304. _createFragments();
  305. return true;
  306. }
  307. bool PhysicsDebris::onNewDataBlock( GameBaseData *dptr, bool reload )
  308. {
  309. if ( !dptr )
  310. return false;
  311. mDataBlock = dynamic_cast< PhysicsDebrisData* >( dptr );
  312. if ( !mDataBlock )
  313. {
  314. Con::errorf( ConsoleLogEntry::General, "PhysicsDebris::onNewDataBlock - datablock ( %i ) is not of type PhysicsDebrisData.", dptr->getId() );
  315. return false;
  316. }
  317. return true;
  318. }
  319. void PhysicsDebris::onRemove()
  320. {
  321. PhysicsPlugin::getPhysicsResetSignal().remove( this, &PhysicsDebris::_onPhysicsReset );
  322. _deleteFragments();
  323. removeFromScene();
  324. Parent::onRemove();
  325. }
  326. void PhysicsDebris::processTick( const Move* )
  327. {
  328. PROFILE_SCOPE( PhysicsDebris_processTick );
  329. // Delete the debris if our lifetime has expired.
  330. if ( mDataBlock->lifetime > 0.0f &&
  331. mIsZero( mLifetime ) )
  332. {
  333. deleteObject();
  334. return;
  335. }
  336. MatrixF mat;
  337. mWorldBox = Box3F::Invalid;
  338. Box3F bounds;
  339. FragmentVector::iterator fragment = mFragments.begin();
  340. for ( ; fragment != mFragments.end(); fragment++ )
  341. {
  342. // Store the last position.
  343. fragment->lastPos = fragment->pos;
  344. fragment->lastRot = fragment->rot;
  345. // Get the new position.
  346. fragment->body->getTransform( &mat );
  347. // Calculate the delta between the current
  348. // global pose and the last global pose.
  349. fragment->pos = mat.getPosition();
  350. fragment->rot.set( mat );
  351. // Update the bounds.
  352. bounds = fragment->body->getWorldBounds();
  353. mWorldBox.intersect( bounds );
  354. // Apply forces for the next tick.
  355. _updateForces( fragment->body, bounds );
  356. }
  357. // Finish up the bounds update.
  358. mWorldSphere.radius = (mWorldBox.maxExtents - mWorldSphere.center).len();
  359. mObjBox = mWorldBox;
  360. mWorldToObj.mul(mObjBox);
  361. mRenderWorldBox = mWorldBox;
  362. mRenderWorldSphere = mWorldSphere;
  363. }
  364. void PhysicsDebris::_updateForces( PhysicsBody *body, const Box3F &bounds )
  365. {
  366. PROFILE_SCOPE( PhysicsDebris_updateForces );
  367. // If we're not simulating don't update forces.
  368. if ( !mWorld->isEnabled() )
  369. return;
  370. ContainerQueryInfo info;
  371. info.box = bounds;
  372. info.mass = mDataBlock->mass;
  373. // Find and retreive physics info from intersecting WaterObject(s)
  374. getContainer()->findObjects( bounds, WaterObjectType|PhysicalZoneObjectType, findRouter, &info );
  375. // Calculate buoyancy and drag
  376. F32 angDrag = mDataBlock->angularDamping;
  377. F32 linDrag = mDataBlock->linearDamping;
  378. F32 buoyancy = 0.0f;
  379. Point3F cmass = body->getCMassPosition();
  380. F32 density = mDataBlock->buoyancyDensity;
  381. if ( density > 0.0f )
  382. {
  383. if ( info.waterCoverage > 0.0f )
  384. {
  385. F32 waterDragScale = info.waterViscosity * mDataBlock->waterDampingScale;
  386. F32 powCoverage = mPow( info.waterCoverage, 0.25f );
  387. angDrag = mLerp( angDrag, angDrag * waterDragScale, powCoverage );
  388. linDrag = mLerp( linDrag, linDrag * waterDragScale, powCoverage );
  389. }
  390. // A little hackery to prevent oscillation
  391. // Based on this blog post:
  392. // (http://reinot.blogspot.com/2005/11/oh-yes-they-float-georgie-they-all.html)
  393. buoyancy = ( info.waterDensity / density ) * mPow( info.waterCoverage, 2.0f );
  394. Point3F buoyancyForce = buoyancy * -mWorld->getGravity() * TickSec * mDataBlock->mass;
  395. body->applyImpulse( cmass, buoyancyForce );
  396. }
  397. // Update the dampening as the container might have changed.
  398. body->setDamping( linDrag, angDrag );
  399. // Apply physical zone forces.
  400. if ( !info.appliedForce.isZero() )
  401. body->applyImpulse( cmass, info.appliedForce );
  402. }
  403. void PhysicsDebris::advanceTime( F32 dt )
  404. {
  405. // Decrement the lifetime.
  406. if ( smLifetimeScale > 0.0f )
  407. mLifetime = getMax( 0.0f, mLifetime - ( dt / smLifetimeScale ) );
  408. else
  409. mLifetime = 0.0f;
  410. }
  411. void PhysicsDebris::interpolateTick( F32 dt )
  412. {
  413. PROFILE_SCOPE( PhysicsDebris_interpolateTick );
  414. mShapeInstance->animate();
  415. if ( mShapeInstance->getCurrentDetail() < 0 )
  416. return;
  417. const MatrixF &objectXfm = getRenderWorldTransform();
  418. Vector<MatrixF> &nodeXfms = mShapeInstance->mNodeTransforms;
  419. MatrixF globalXfm;
  420. MatrixF tempXfm;
  421. QuatF newRot;
  422. Point3F newPos;
  423. FragmentVector::iterator fragment = mFragments.begin();
  424. for ( ; fragment != mFragments.end(); fragment++ )
  425. {
  426. // Do the interpolation.
  427. newRot.interpolate( fragment->rot, fragment->lastRot, dt );
  428. newRot.setMatrix( &globalXfm );
  429. newPos.interpolate( fragment->pos, fragment->lastPos, dt );
  430. globalXfm.setPosition( newPos );
  431. tempXfm = objectXfm * globalXfm;
  432. for ( S32 i = 0; i < fragment->nodeIds.size(); i++ )
  433. {
  434. S32 n = fragment->nodeIds[i];
  435. nodeXfms[n] = tempXfm;
  436. }
  437. }
  438. }
  439. void PhysicsDebris::prepRenderImage( SceneRenderState *state )
  440. {
  441. if( !mShapeInstance )
  442. return;
  443. // Skip shadow rendering if this debris doesn't support it.
  444. if ( state->isShadowPass() &&
  445. !mDataBlock->castShadows )
  446. return;
  447. // If the debris is completed LOD'd out then skip it.
  448. if ( mShapeInstance->setDetailFromPosAndScale( state, getRenderPosition(), getScale() ) < 0 )
  449. return;
  450. // Fade out the debris over the last second of its lifetime.
  451. F32 alpha = 1.0;
  452. if ( mDataBlock->lifetime > 0.0f )
  453. alpha = getMin( mLifetime * smLifetimeScale, 1.0f );
  454. // Set up our TS render state.
  455. TSRenderState rdata;
  456. rdata.setSceneState( state );
  457. rdata.setFadeOverride( alpha );
  458. // We might have some forward lit materials
  459. // so pass down a query to gather lights.
  460. LightQuery query;
  461. query.init( getWorldSphere() );
  462. rdata.setLightQuery( &query );
  463. GFXTransformSaver saver;
  464. MatrixF mat = getRenderTransform();
  465. mat.scale( getScale() );
  466. GFX->setWorldMatrix( mat );
  467. mShapeInstance->animate();
  468. mShapeInstance->render( rdata );
  469. }
  470. void PhysicsDebris::applyImpulse( const Point3F &pos, const VectorF &vec )
  471. {
  472. FragmentVector::iterator fragment = mFragments.begin();
  473. for ( ; fragment != mFragments.end(); fragment++ )
  474. fragment->body->applyImpulse( pos, vec );
  475. }
  476. void PhysicsDebris::applyRadialImpulse( const Point3F &origin, F32 radius, F32 magnitude )
  477. {
  478. FragmentVector::iterator fragment = mFragments.begin();
  479. for ( ; fragment != mFragments.end(); fragment++ )
  480. {
  481. PhysicsBody &body = *fragment->body;
  482. Box3F bounds = body.getWorldBounds();
  483. VectorF force = bounds.getCenter() - origin;
  484. F32 dist = force.magnitudeSafe();
  485. force.normalize();
  486. if ( dist == 0.0f )
  487. force *= magnitude;
  488. else
  489. force *= mClampF( radius / dist, 0.0f, 1.0f ) * magnitude;
  490. body.applyImpulse( origin, force );
  491. }
  492. }
  493. void PhysicsDebris::_createFragments()
  494. {
  495. _deleteFragments();
  496. mWorld = PHYSICSMGR->getWorld( "client" );
  497. if ( !mWorld )
  498. return;
  499. TSShape *shape = mDataBlock->mShape;
  500. mShapeInstance = new TSShapeInstance( shape, true );
  501. mShapeInstance->animate();
  502. Vector< CollisionShapeInfo > infoList;
  503. shape->buildColShapes( false, Point3F::One, &infoList );
  504. mFragments.setSize( infoList.size() );
  505. dMemset( mFragments.address(), 0, mFragments.memSize() );
  506. const Point3F damageDir( 0, 0, 1 );
  507. MatrixF bodyMat( true );
  508. bodyMat = getTransform();
  509. const U32 bodyFlags = PhysicsBody::BF_DEBRIS;
  510. mWorldBox = Box3F::Invalid;
  511. for ( S32 i = 0; i < infoList.size(); i++ )
  512. {
  513. const CollisionShapeInfo &info = infoList[i];
  514. Fragment &fragment = mFragments[i];
  515. if ( info.colNode == -1 )
  516. Con::errorf( "PhysicsDebris::_createFragments, Missing or couldnt find a colNode." );
  517. else
  518. _findNodes( info.colNode, fragment.nodeIds );
  519. PhysicsBody *body = PHYSICSMGR->createBody();
  520. body->init( info.colShape, mDataBlock->mass, bodyFlags, this, mWorld );
  521. body->setMaterial( mDataBlock->restitution, mDataBlock->dynamicFriction, mDataBlock->staticFriction );
  522. body->setDamping( mDataBlock->linearDamping, mDataBlock->angularDamping );
  523. body->setSleepThreshold( mDataBlock->linearSleepThreshold, mDataBlock->angularSleepThreshold );
  524. body->setTransform( bodyMat );
  525. body->setLinVelocity( mInitialLinVel );
  526. fragment.body = body;
  527. // Set the initial delta state.
  528. fragment.pos = bodyMat.getPosition();
  529. fragment.rot.set( bodyMat );
  530. fragment.lastPos = fragment.pos;
  531. fragment.lastRot = fragment.rot;
  532. // Update the bounds.
  533. mWorldBox.intersect( body->getWorldBounds() );
  534. }
  535. // Finish up updating the bounds.
  536. mWorldSphere.radius = (mWorldBox.maxExtents - mWorldSphere.center).len();
  537. mObjBox = mWorldBox;
  538. mWorldToObj.mul(mObjBox);
  539. mRenderWorldBox = mWorldBox;
  540. mRenderWorldSphere = mWorldSphere;
  541. }
  542. void PhysicsDebris::_deleteFragments()
  543. {
  544. FragmentVector::iterator fragment = mFragments.begin();
  545. for ( ; fragment != mFragments.end(); fragment++ )
  546. delete fragment->body;
  547. mFragments.clear();
  548. SAFE_DELETE( mShapeInstance );
  549. }
  550. void PhysicsDebris::_findNodes( U32 colNode, Vector<U32> &nodeIds )
  551. {
  552. // Two possible cases:
  553. // 1. Visible mesh nodes are siblings of the collision node under a common parent dummy node
  554. // 2. Collision node is a child of its visible mesh node
  555. TSShape *shape = mDataBlock->mShape;
  556. S32 itr = shape->nodes[colNode].parentIndex;
  557. itr = shape->nodes[itr].firstChild;
  558. while ( itr != -1 )
  559. {
  560. if ( itr != colNode )
  561. nodeIds.push_back(itr);
  562. itr = shape->nodes[itr].nextSibling;
  563. }
  564. // If we didn't find any siblings of the collision node we assume
  565. // it is case #2 and the collision nodes direct parent is the visible mesh.
  566. if ( nodeIds.size() == 0 && shape->nodes[colNode].parentIndex != -1 )
  567. nodeIds.push_back( shape->nodes[colNode].parentIndex );
  568. }
  569. extern bool gEditingMission;
  570. void PhysicsDebris::_onPhysicsReset( PhysicsResetEvent reset )
  571. {
  572. if ( gEditingMission )
  573. {
  574. // Editing stuff, clean up the trash!
  575. safeDeleteObject();
  576. }
  577. }