API Docs for: GoblinPhysics
Show:

File: src\classes\RigidBody.js

  1. /**
  2. * Represents a rigid body
  3. *
  4. * @class RigidBody
  5. * @constructor
  6. * @param shape
  7. * @param mass {Number}
  8. */
  9. Goblin.RigidBody = (function() {
  10. var body_count = 0;
  11.  
  12. return function( shape, mass ) {
  13. /**
  14. * goblin ID of the body
  15. *
  16. * @property id
  17. * @type {Number}
  18. */
  19. this.id = body_count++;
  20.  
  21. /**
  22. * shape definition for this rigid body
  23. *
  24. * @property shape
  25. */
  26. this.shape = shape;
  27.  
  28. /**
  29. * axis-aligned bounding box enclosing this body
  30. *
  31. * @property aabb
  32. * @type {AABB}
  33. */
  34. this.aabb = new Goblin.AABB();
  35.  
  36. /**
  37. * the rigid body's mass
  38. *
  39. * @property mass
  40. * @type {Number}
  41. * @default Infinity
  42. */
  43. this.mass = mass || Infinity;
  44.  
  45. /**
  46. * the rigid body's current position
  47. *
  48. * @property position
  49. * @type {vec3}
  50. * @default [ 0, 0, 0 ]
  51. */
  52. this.position = new Goblin.Vector3();
  53.  
  54. /**
  55. * rotation of the rigid body
  56. *
  57. * @type {quat4}
  58. */
  59. this.rotation = new Goblin.Quaternion( 0, 0, 0, 1 );
  60.  
  61. /**
  62. * the rigid body's current linear velocity
  63. *
  64. * @property linear_velocity
  65. * @type {vec3}
  66. * @default [ 0, 0, 0 ]
  67. */
  68. this.linear_velocity = new Goblin.Vector3();
  69.  
  70. /**
  71. * the rigid body's current angular velocity
  72. *
  73. * @property angular_velocity
  74. * @type {vec3}
  75. * @default [ 0, 0, 0 ]
  76. */
  77. this.angular_velocity = new Goblin.Vector3();
  78.  
  79. /**
  80. * transformation matrix transforming points from object space to world space
  81. *
  82. * @property transform
  83. * @type {mat4}
  84. */
  85. this.transform = new Goblin.Matrix4();
  86. this.transform.identity();
  87.  
  88. /**
  89. * transformation matrix transforming points from world space to object space
  90. *
  91. * @property transform_inverse
  92. * @type {mat4}
  93. */
  94. this.transform_inverse = new Goblin.Matrix4();
  95. this.transform_inverse.identity();
  96.  
  97. this.inertiaTensor = shape.getInertiaTensor( mass );
  98.  
  99. this.inverseInertiaTensor = new Goblin.Matrix3();
  100. this.inertiaTensor.invertInto( this.inverseInertiaTensor );
  101.  
  102. this.inertiaTensorWorldFrame = new Goblin.Matrix3();
  103.  
  104. this.inverseInertiaTensorWorldFrame = new Goblin.Matrix3();
  105.  
  106. /**
  107. * the rigid body's current acceleration
  108. *
  109. * @property acceleration
  110. * @type {vec3}
  111. * @default [ 0, 0, 0 ]
  112. */
  113. this.acceleration = new Goblin.Vector3();
  114.  
  115. /**
  116. * amount of restitution this object has
  117. *
  118. * @property restitution
  119. * @type {Number}
  120. * @default 0.1
  121. */
  122. this.restitution = 0.1;
  123.  
  124. /**
  125. * amount of friction this object has
  126. *
  127. * @property friction
  128. * @type {Number}
  129. * @default 0.5
  130. */
  131. this.friction = 0.5;
  132.  
  133. /**
  134. * the rigid body's custom gravity
  135. *
  136. * @property gravity
  137. * @type {vec3}
  138. * @default null
  139. * @private
  140. */
  141. this.gravity = null;
  142.  
  143. /**
  144. * proportion of linear velocity lost per second ( 0.0 - 1.0 )
  145. *
  146. * @property linear_damping
  147. * @type {Number}
  148. */
  149. this.linear_damping = 0;
  150.  
  151. /**
  152. * proportion of angular velocity lost per second ( 0.0 - 1.0 )
  153. *
  154. * @property angular_damping
  155. * @type {Number}
  156. */
  157. this.angular_damping = 0;
  158.  
  159. /**
  160. * the world to which the rigid body has been added,
  161. * this is set when the rigid body is added to a world
  162. *
  163. * @property world
  164. * @type {Goblin.World}
  165. * @default null
  166. */
  167. this.world = null;
  168.  
  169. /**
  170. * all resultant force accumulated by the rigid body
  171. * this force is applied in the next occurring integration
  172. *
  173. * @property accumulated_force
  174. * @type {vec3}
  175. * @default [ 0, 0, 0 ]
  176. * @private
  177. */
  178. this.accumulated_force = new Goblin.Vector3();
  179.  
  180. /**
  181. * All resultant torque accumulated by the rigid body
  182. * this torque is applied in the next occurring integration
  183. *
  184. * @property accumulated_force
  185. * @type {vec3}
  186. * @default [ 0, 0, 0 ]
  187. * @private
  188. */
  189. this.accumulated_torque = new Goblin.Vector3();
  190.  
  191. // Used by the constraint solver to determine what impulse needs to be added to the body
  192. this.push_velocity = new Goblin.Vector3();
  193. this.turn_velocity = new Goblin.Vector3();
  194. this.solver_impulse = new Float64Array( 6 );
  195.  
  196. // Set default derived values
  197. this.updateDerived();
  198.  
  199. this.listeners = {};
  200. };
  201. })();
  202. Goblin.EventEmitter.apply( Goblin.RigidBody );
  203.  
  204. /**
  205. * Given `direction`, find the point in this body which is the most extreme in that direction.
  206. * This support point is calculated in world coordinates and stored in the second parameter `support_point`
  207. *
  208. * @method findSupportPoint
  209. * @param direction {vec3} direction to use in finding the support point
  210. * @param support_point {vec3} vec3 variable which will contain the supporting point after calling this method
  211. */
  212. Goblin.RigidBody.prototype.findSupportPoint = (function(){
  213. var local_direction = new Goblin.Vector3();
  214.  
  215. return function( direction, support_point ) {
  216. // Convert direction into local frame for the shape
  217. this.transform_inverse.rotateVector3Into( direction, local_direction );
  218.  
  219. this.shape.findSupportPoint( local_direction, support_point );
  220.  
  221. // Convert from the shape's local coordinates to world coordinates
  222. this.transform.transformVector3( support_point );
  223. };
  224. })();
  225.  
  226. /**
  227. * Checks if a ray segment intersects with the object
  228. *
  229. * @method rayIntersect
  230. * @property ray_start {vec3} start point of the segment
  231. * @property ray_end {vec3{ end point of the segment
  232. * @property intersection_list {Array} array to append intersection to
  233. */
  234. Goblin.RigidBody.prototype.rayIntersect = (function(){
  235. var local_start = new Goblin.Vector3(),
  236. local_end = new Goblin.Vector3();
  237.  
  238. return function( ray_start, ray_end, intersection_list ) {
  239. // transform start & end into local coordinates
  240. this.transform_inverse.transformVector3Into( ray_start, local_start );
  241. this.transform_inverse.transformVector3Into( ray_end, local_end );
  242.  
  243. // Intersect with shape
  244. var intersection = this.shape.rayIntersect( local_start, local_end );
  245.  
  246. if ( intersection != null ) {
  247. intersection.object = this; // change from the shape to the body
  248. this.transform.transformVector3( intersection.point ); // transform shape's local coordinates to the body's world coordinates
  249.  
  250. // Rotate intersection normal
  251. this.transform.rotateVector3( intersection.normal );
  252.  
  253. intersection_list.push( intersection );
  254. }
  255. };
  256. })();
  257.  
  258. /**
  259. * Updates the rigid body's position, velocity, and acceleration
  260. *
  261. * @method integrate
  262. * @param timestep {Number} time, in seconds, to use in integration
  263. */
  264. Goblin.RigidBody.prototype.integrate = function( timestep ) {
  265. if ( this.mass === Infinity ) {
  266. return;
  267. }
  268.  
  269. var invmass = 1 / this.mass;
  270.  
  271. // Add accumulated linear force
  272. _tmp_vec3_1.scaleVector( this.accumulated_force, invmass );
  273. this.linear_velocity.add( _tmp_vec3_1 );
  274.  
  275. // Add accumulated angular force
  276. this.inverseInertiaTensorWorldFrame.transformVector3Into( this.accumulated_torque, _tmp_vec3_1 );
  277. this.angular_velocity.add( _tmp_vec3_1 );
  278.  
  279. // Apply damping
  280. this.linear_velocity.scale( Math.pow( 1 - this.linear_damping, timestep ) );
  281. this.angular_velocity.scale( Math.pow( 1 - this.angular_damping, timestep ) );
  282.  
  283. // Update position
  284. _tmp_vec3_1.scaleVector( this.linear_velocity, timestep );
  285. this.position.add( _tmp_vec3_1 );
  286.  
  287. // Update rotation
  288. _tmp_quat4_1.x = this.angular_velocity.x * timestep;
  289. _tmp_quat4_1.y = this.angular_velocity.y * timestep;
  290. _tmp_quat4_1.z = this.angular_velocity.z * timestep;
  291. _tmp_quat4_1.w = 0;
  292.  
  293. _tmp_quat4_1.multiply( this.rotation );
  294.  
  295. var half_dt = 0.5;
  296. this.rotation.x += half_dt * _tmp_quat4_1.x;
  297. this.rotation.y += half_dt * _tmp_quat4_1.y;
  298. this.rotation.z += half_dt * _tmp_quat4_1.z;
  299. this.rotation.w += half_dt * _tmp_quat4_1.w;
  300. this.rotation.normalize();
  301.  
  302. // Clear accumulated forces
  303. this.accumulated_force.x = this.accumulated_force.y = this.accumulated_force.z = 0;
  304. this.accumulated_torque.x = this.accumulated_torque.y = this.accumulated_torque.z = 0;
  305. this.solver_impulse[0] = this.solver_impulse[1] = this.solver_impulse[2] = this.solver_impulse[3] = this.solver_impulse[4] = this.solver_impulse[5] = 0;
  306. this.push_velocity.x = this.push_velocity.y = this.push_velocity.z = 0;
  307. this.turn_velocity.x = this.turn_velocity.y = this.turn_velocity.z = 0;
  308. };
  309.  
  310. /**
  311. * Sets a custom gravity value for this rigid_body
  312. *
  313. * @method setGravity
  314. * @param x {Number} gravity to apply on x axis
  315. * @param y {Number} gravity to apply on y axis
  316. * @param z {Number} gravity to apply on z axis
  317. */
  318. Goblin.RigidBody.prototype.setGravity = function( x, y, z ) {
  319. if ( this.gravity ) {
  320. this.gravity.x = x;
  321. this.gravity.y = y;
  322. this.gravity.z = z;
  323. } else {
  324. this.gravity = new Goblin.Vector3( x, y, z );
  325. }
  326. };
  327.  
  328. /**
  329. * Directly adds linear velocity to the body
  330. *
  331. * @method applyImpulse
  332. * @param impulse {vec3} linear velocity to add to the body
  333. */
  334. Goblin.RigidBody.prototype.applyImpulse = function( impulse ) {
  335. this.linear_velocity.add( impulse );
  336. };
  337.  
  338. /**
  339. * Adds a force to the rigid_body which will be used only for the next integration
  340. *
  341. * @method applyForce
  342. * @param force {vec3} force to apply to the rigid_body
  343. */
  344. Goblin.RigidBody.prototype.applyForce = function( force ) {
  345. this.accumulated_force.add( force );
  346. };
  347.  
  348. /**
  349. * Applies the vector `force` at world coordinate `point`
  350. *
  351. * @method applyForceAtWorldPoint
  352. * @param force {vec3} Force to apply
  353. * @param point {vec3} world coordinates where force originates
  354. */
  355. Goblin.RigidBody.prototype.applyForceAtWorldPoint = function( force, point ) {
  356. _tmp_vec3_1.copy( point );
  357. _tmp_vec3_1.subtract( this.position );
  358. _tmp_vec3_1.cross( force );
  359.  
  360. this.accumulated_force.add( force );
  361. this.accumulated_torque.add( _tmp_vec3_1 );
  362. };
  363.  
  364. /**
  365. * Applies vector `force` to body at position `point` in body's frame
  366. *
  367. * @method applyForceAtLocalPoint
  368. * @param force {vec3} Force to apply
  369. * @param point {vec3} local frame coordinates where force originates
  370. */
  371. Goblin.RigidBody.prototype.applyForceAtLocalPoint = function( force, point ) {
  372. this.transform.transformVector3Into( point, _tmp_vec3_1 );
  373. this.applyForceAtWorldPoint( force, _vec3 );
  374. };
  375.  
  376. Goblin.RigidBody.prototype.getVelocityInLocalPoint = function( point, out ) {
  377. if ( this.mass === Infinity ) {
  378. out.set( 0, 0, 0 );
  379. } else {
  380. out.copy( this.angular_velocity );
  381. out.cross( point );
  382. out.add( this.linear_velocity );
  383. }
  384. };
  385.  
  386. /**
  387. * Sets the rigid body's transformation matrix to the current position and rotation
  388. *
  389. * @method updateDerived
  390. */
  391. Goblin.RigidBody.prototype.updateDerived = function() {
  392. // normalize rotation
  393. this.rotation.normalize();
  394.  
  395. // update this.transform and this.transform_inverse
  396. this.transform.makeTransform( this.rotation, this.position );
  397. this.transform.invertInto( this.transform_inverse );
  398.  
  399. // Update the world frame inertia tensor and inverse
  400. if ( this.mass !== Infinity ) {
  401. _tmp_mat3_1.fromMatrix4( this.transform_inverse );
  402. _tmp_mat3_1.transposeInto( _tmp_mat3_2 );
  403. _tmp_mat3_2.multiply( this.inertiaTensor );
  404. this.inertiaTensorWorldFrame.multiplyFrom( _tmp_mat3_2, _tmp_mat3_1 );
  405.  
  406. this.inertiaTensorWorldFrame.invertInto( this.inverseInertiaTensorWorldFrame );
  407. }
  408.  
  409. // Update AABB
  410. this.aabb.transform( this.shape.aabb, this.transform );
  411. };