Panda3D
bulletRigidBodyNode.cxx
1 // Filename: bulletRigidBodyNode.cxx
2 // Created by: enn0x (19Nov10)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "bulletRigidBodyNode.h"
16 #include "bulletShape.h"
17 
18 TypeHandle BulletRigidBodyNode::_type_handle;
19 
20 ////////////////////////////////////////////////////////////////////
21 // Function: BulletRigidBodyNode::Constructor
22 // Access: Published
23 // Description:
24 ////////////////////////////////////////////////////////////////////
25 BulletRigidBodyNode::
26 BulletRigidBodyNode(const char *name) : BulletBodyNode(name) {
27 
28  // Motion state
29  _motion = new MotionState();
30 
31  // Mass properties
32  btScalar mass(0.0);
33  btVector3 inertia(0, 0, 0);
34 
35  // construction info
36  btRigidBody::btRigidBodyConstructionInfo ci(mass, _motion, _shape, inertia);
37 
38  // Additional damping
39  if (bullet_additional_damping) {
40  ci.m_additionalDamping = true;
41  ci.m_additionalDampingFactor = bullet_additional_damping_linear_factor;
42  ci.m_additionalLinearDampingThresholdSqr = bullet_additional_damping_linear_threshold;
43  ci.m_additionalAngularDampingFactor = bullet_additional_damping_angular_factor;
44  ci.m_additionalAngularDampingThresholdSqr = bullet_additional_damping_angular_threshold;
45  }
46 
47  // Rigid body
48  _rigid = new btRigidBody(ci);
49  _rigid->setUserPointer(this);
50 }
51 
52 ////////////////////////////////////////////////////////////////////
53 // Function: BulletRigidBodyNode::output
54 // Access: Public, Virtual
55 // Description:
56 ////////////////////////////////////////////////////////////////////
57 void BulletRigidBodyNode::
58 output(ostream &out) const {
59 
60  BulletBodyNode::output(out);
61 
62  out << " mass=" << get_mass();
63 }
64 
65 ////////////////////////////////////////////////////////////////////
66 // Function: BulletRigidBodyNode::get_object
67 // Access: Public
68 // Description:
69 ////////////////////////////////////////////////////////////////////
70 btCollisionObject *BulletRigidBodyNode::
71 get_object() const {
72 
73  return _rigid;
74 }
75 
76 ////////////////////////////////////////////////////////////////////
77 // Function: BulletRigidBodyNode::shape_changed
78 // Access: Published
79 // Description: Hook which should be called whenever the total
80 // shape of a body changed. Used for example to update
81 // the mass properties (inertia) of a rigid body.
82 // The default implementation does nothing.
83 ////////////////////////////////////////////////////////////////////
84 void BulletRigidBodyNode::
85 shape_changed() {
86 
87  set_mass(get_mass());
88  transform_changed();
89 }
90 
91 ////////////////////////////////////////////////////////////////////
92 // Function: BulletRigidBodyNode::set_mass
93 // Access: Published
94 // Description: Sets the mass of a rigid body. This also modifies
95 // the inertia, which is automatically computed from
96 // the shape of the body. Setting a value of zero
97 // for mass will make the body static. A value of
98 // zero can be considered an infinite mass.
99 ////////////////////////////////////////////////////////////////////
101 set_mass(PN_stdfloat mass) {
102 
103  btScalar bt_mass = mass;
104  btVector3 bt_inertia(0.0, 0.0, 0.0);
105 
106  if (bt_mass > 0.0) {
107  _rigid->getCollisionShape()->calculateLocalInertia(bt_mass, bt_inertia);
108  }
109 
110  _rigid->setMassProps(bt_mass, bt_inertia);
111  _rigid->updateInertiaTensor();
112 }
113 
114 ////////////////////////////////////////////////////////////////////
115 // Function: BulletRigidBodyNode::get_mass
116 // Access: Published
117 // Description: Returns the total mass of a rigid body.
118 // A value of zero means that the body is staic, i.e.
119 // has an infinite mass.
120 ////////////////////////////////////////////////////////////////////
121 PN_stdfloat BulletRigidBodyNode::
122 get_mass() const {
123 
124  btScalar inv_mass = _rigid->getInvMass();
125  btScalar mass = (inv_mass == btScalar(0.0)) ? btScalar(0.0) : btScalar(1.0) / inv_mass;
126 
127  return mass;
128 }
129 
130 ////////////////////////////////////////////////////////////////////
131 // Function: BulletRigidBodyNode::get_inv_mass
132 // Access: Published
133 // Description: Returns the inverse mass of a rigid body.
134 ////////////////////////////////////////////////////////////////////
135 PN_stdfloat BulletRigidBodyNode::
136 get_inv_mass() const {
137 
138  return (PN_stdfloat)_rigid->getInvMass();
139 }
140 
141 ////////////////////////////////////////////////////////////////////
142 // Function: BulletRigidBodyNode::set_inertia
143 // Access: Published
144 // Description: Sets the inertia of a rigid body. Inertia is given
145 // as a three-component vector. A component value of
146 // zero means infinite inertia along this direction.
147 // Setting the intertia will override the value which
148 // is automatically calculated from the rigid bodies
149 // shape. However, it is possible that automatic
150 // calculation of intertia is trigger after calling
151 // this method, and thus overwriting the explicitly
152 // set value again. This happens when:
153 // (a) the mass is set after the inertia.
154 // (b) a shape is added or removed from the body.
155 // (c) the scale of the body changed.
156 ////////////////////////////////////////////////////////////////////
158 set_inertia(const LVecBase3 &inertia) {
159 
160  btVector3 inv_inertia(
161  inertia.get_x() == 0.0 ? btScalar(0.0) : btScalar(1.0 / inertia.get_x()),
162  inertia.get_y() == 0.0 ? btScalar(0.0) : btScalar(1.0 / inertia.get_y()),
163  inertia.get_z() == 0.0 ? btScalar(0.0) : btScalar(1.0 / inertia.get_z())
164  );
165 
166  _rigid->setInvInertiaDiagLocal(inv_inertia);
167  _rigid->updateInertiaTensor();
168 }
169 
170 ////////////////////////////////////////////////////////////////////
171 // Function: BulletRigidBodyNode::get_inertia
172 // Access: Published
173 // Description: Returns the inertia of the rigid body. Inertia is
174 // given as a three component vector. A component
175 // value of zero means infinite inertia along this
176 // direction.
177 ////////////////////////////////////////////////////////////////////
179 get_inertia() const {
180 
181  btVector3 inv_inertia = _rigid->getInvInertiaDiagLocal();
182  LVector3 inertia(
183  inv_inertia.x() == btScalar(0.0) ? 0.0 : 1.0 / inv_inertia.x(),
184  inv_inertia.y() == btScalar(0.0) ? 0.0 : 1.0 / inv_inertia.y(),
185  inv_inertia.z() == btScalar(0.0) ? 0.0 : 1.0 / inv_inertia.z()
186  );
187 
188  return inertia;
189 }
190 
191 ////////////////////////////////////////////////////////////////////
192 // Function: BulletRigidBodyNode::get_inv_inertia_diag_local
193 // Access: Published
194 // Description:
195 ////////////////////////////////////////////////////////////////////
196 LVector3 BulletRigidBodyNode::
197 get_inv_inertia_diag_local() const {
198 
199  return btVector3_to_LVector3(_rigid->getInvInertiaDiagLocal());
200 }
201 
202 ////////////////////////////////////////////////////////////////////
203 // Function: BulletRigidBodyNode::get_inv_inertia_tensor_world
204 // Access: Published
205 // Description:
206 ////////////////////////////////////////////////////////////////////
207 LMatrix3 BulletRigidBodyNode::
208 get_inv_inertia_tensor_world() const {
209 
210  return btMatrix3x3_to_LMatrix3(_rigid->getInvInertiaTensorWorld());
211 }
212 
213 ////////////////////////////////////////////////////////////////////
214 // Function: BulletRigidBodyNode::apply_force
215 // Access: Published
216 // Description:
217 ////////////////////////////////////////////////////////////////////
218 void BulletRigidBodyNode::
219 apply_force(const LVector3 &force, const LPoint3 &pos) {
220 
221  nassertv_always(!force.is_nan());
222  nassertv_always(!pos.is_nan());
223 
224  _rigid->applyForce(LVecBase3_to_btVector3(force),
225  LVecBase3_to_btVector3(pos));
226 }
227 
228 ////////////////////////////////////////////////////////////////////
229 // Function: BulletRigidBodyNode::apply_central_force
230 // Access: Published
231 // Description:
232 ////////////////////////////////////////////////////////////////////
233 void BulletRigidBodyNode::
234 apply_central_force(const LVector3 &force) {
235 
236  nassertv_always(!force.is_nan());
237 
238  _rigid->applyCentralForce(LVecBase3_to_btVector3(force));
239 }
240 
241 ////////////////////////////////////////////////////////////////////
242 // Function: BulletRigidBodyNode::apply_torque
243 // Access: Published
244 // Description:
245 ////////////////////////////////////////////////////////////////////
246 void BulletRigidBodyNode::
247 apply_torque(const LVector3 &torque) {
248 
249  nassertv_always(!torque.is_nan());
250 
251  _rigid->applyTorque(LVecBase3_to_btVector3(torque));
252 }
253 
254 ////////////////////////////////////////////////////////////////////
255 // Function: BulletRigidBodyNode::apply_torque_impulse
256 // Access: Published
257 // Description:
258 ////////////////////////////////////////////////////////////////////
259 void BulletRigidBodyNode::
260 apply_torque_impulse(const LVector3 &torque) {
261 
262  nassertv_always(!torque.is_nan());
263 
264  _rigid->applyTorqueImpulse(LVecBase3_to_btVector3(torque));
265 }
266 
267 ////////////////////////////////////////////////////////////////////
268 // Function: BulletRigidBodyNode::apply_impulse
269 // Access: Published
270 // Description:
271 ////////////////////////////////////////////////////////////////////
272 void BulletRigidBodyNode::
273 apply_impulse(const LVector3 &impulse, const LPoint3 &pos) {
274 
275  nassertv_always(!impulse.is_nan());
276  nassertv_always(!pos.is_nan());
277 
278  _rigid->applyImpulse(LVecBase3_to_btVector3(impulse),
279  LVecBase3_to_btVector3(pos));
280 }
281 
282 ////////////////////////////////////////////////////////////////////
283 // Function: BulletRigidBodyNode::apply_central_impulse
284 // Access: Published
285 // Description:
286 ////////////////////////////////////////////////////////////////////
287 void BulletRigidBodyNode::
288 apply_central_impulse(const LVector3 &impulse) {
289 
290  nassertv_always(!impulse.is_nan());
291 
292  _rigid->applyCentralImpulse(LVecBase3_to_btVector3(impulse));
293 }
294 
295 ////////////////////////////////////////////////////////////////////
296 // Function: BulletRigidBodyNode::transform_changed
297 // Access: Protected
298 // Description:
299 ////////////////////////////////////////////////////////////////////
300 void BulletRigidBodyNode::
301 transform_changed() {
302 
303  if (_motion->sync_disabled()) return;
304 
305  NodePath np = NodePath::any_path((PandaNode *)this);
306  CPT(TransformState) ts = np.get_net_transform();
307 
308  // For kinematic bodies Bullet will query the transform
309  // via Motionstate::getWorldTransform. Therefor we need to
310  // store the new transform within the motion state.
311  // For dynamic bodies we need to store the net scale within
312  // the motion state, since Bullet might update the transform
313  // via MotionState::setWorldTransform.
314  _motion->set_net_transform(ts);
315 
316  // For dynamic or static bodies we directly apply the
317  // new transform.
318  if (!is_kinematic()) {
319  btTransform trans = TransformState_to_btTrans(ts);
320  _rigid->setCenterOfMassTransform(trans);
321  }
322 
323  // Rescale all shapes, but only if the new transform state
324  // has a scale, and this scale differes from the current scale.
325  if (ts->has_scale()) {
326  btVector3 new_scale = LVecBase3_to_btVector3(ts->get_scale());
327  btVector3 current_scale = _shape->getLocalScaling();
328  btVector3 current_scale_inv(1.0/current_scale.x(), 1.0/current_scale.y(), 1.0/current_scale.z());
329 
330  if (new_scale != current_scale) {
331  _shape->setLocalScaling(current_scale_inv);
332  _shape->setLocalScaling(new_scale);
333  }
334  }
335 
336  // Activate the body if it has been sleeping
337  if (!_rigid->isActive()) {
338  _rigid->activate(true);
339  }
340 }
341 
342 ////////////////////////////////////////////////////////////////////
343 // Function: BulletRigidBodyNode::sync_p2b
344 // Access: Public
345 // Description:
346 ////////////////////////////////////////////////////////////////////
347 void BulletRigidBodyNode::
348 sync_p2b() {
349 
350  if (is_kinematic()) {
351  transform_changed();
352  }
353 }
354 
355 ////////////////////////////////////////////////////////////////////
356 // Function: BulletRigidBodyNode::sync_b2p
357 // Access: Public
358 // Description:
359 ////////////////////////////////////////////////////////////////////
360 void BulletRigidBodyNode::
361 sync_b2p() {
362 
363  _motion->sync_b2p((PandaNode *)this);
364 }
365 
366 ////////////////////////////////////////////////////////////////////
367 // Function: BulletRigidBodyNode::get_linear_velocity
368 // Access: Published
369 // Description:
370 ////////////////////////////////////////////////////////////////////
371 LVector3 BulletRigidBodyNode::
372 get_linear_velocity() const {
373 
374  return btVector3_to_LVector3(_rigid->getLinearVelocity());
375 }
376 
377 ////////////////////////////////////////////////////////////////////
378 // Function: BulletRigidBodyNode::get_angular_velocity
379 // Access: Published
380 // Description:
381 ////////////////////////////////////////////////////////////////////
382 LVector3 BulletRigidBodyNode::
383 get_angular_velocity() const {
384 
385  return btVector3_to_LVector3(_rigid->getAngularVelocity());
386 }
387 
388 ////////////////////////////////////////////////////////////////////
389 // Function: BulletRigidBodyNode::set_linear_velocity
390 // Access: Published
391 // Description:
392 ////////////////////////////////////////////////////////////////////
393 void BulletRigidBodyNode::
394 set_linear_velocity(const LVector3 &velocity) {
395 
396  nassertv_always(!velocity.is_nan());
397 
398  _rigid->setLinearVelocity(LVecBase3_to_btVector3(velocity));
399 }
400 
401 ////////////////////////////////////////////////////////////////////
402 // Function: BulletRigidBodyNode::set_angular_velocity
403 // Access: Published
404 // Description:
405 ////////////////////////////////////////////////////////////////////
406 void BulletRigidBodyNode::
407 set_angular_velocity(const LVector3 &velocity) {
408 
409  nassertv_always(!velocity.is_nan());
410 
411  _rigid->setAngularVelocity(LVecBase3_to_btVector3(velocity));
412 }
413 
414 ////////////////////////////////////////////////////////////////////
415 // Function: BulletRigidBodyNode::clear_forces
416 // Access: Published
417 // Description:
418 ////////////////////////////////////////////////////////////////////
419 void BulletRigidBodyNode::
420 clear_forces() {
421 
422  _rigid->clearForces();
423 }
424 
425 ////////////////////////////////////////////////////////////////////
426 // Function: BulletRigidBodyNode::get_linear_sleep_threshold
427 // Access: Published
428 // Description:
429 ////////////////////////////////////////////////////////////////////
430 PN_stdfloat BulletRigidBodyNode::
431 get_linear_sleep_threshold() const {
432 
433  return _rigid->getLinearSleepingThreshold();
434 }
435 
436 ////////////////////////////////////////////////////////////////////
437 // Function: BulletRigidBodyNode::get_angular_sleep_threshold
438 // Access: Published
439 // Description:
440 ////////////////////////////////////////////////////////////////////
441 PN_stdfloat BulletRigidBodyNode::
442 get_angular_sleep_threshold() const {
443 
444  return _rigid->getAngularSleepingThreshold();
445 }
446 
447 ////////////////////////////////////////////////////////////////////
448 // Function: BulletRigidBodyNode::set_linear_sleep_threshold
449 // Access: Published
450 // Description:
451 ////////////////////////////////////////////////////////////////////
452 void BulletRigidBodyNode::
453 set_linear_sleep_threshold(PN_stdfloat threshold) {
454 
455  _rigid->setSleepingThresholds(threshold, _rigid->getAngularSleepingThreshold());
456 }
457 
458 ////////////////////////////////////////////////////////////////////
459 // Function: BulletRigidBodyNode::set_angular_sleep_threshold
460 // Access: Published
461 // Description:
462 ////////////////////////////////////////////////////////////////////
463 void BulletRigidBodyNode::
464 set_angular_sleep_threshold(PN_stdfloat threshold) {
465 
466  _rigid->setSleepingThresholds(_rigid->getLinearSleepingThreshold(), threshold);
467 }
468 
469 ////////////////////////////////////////////////////////////////////
470 // Function: BulletRigidBodyNode::set_gravity
471 // Access: Published
472 // Description:
473 ////////////////////////////////////////////////////////////////////
474 void BulletRigidBodyNode::
475 set_gravity(const LVector3 &gravity) {
476 
477  nassertv_always(!gravity.is_nan());
478 
479  _rigid->setGravity(LVecBase3_to_btVector3(gravity));
480 }
481 
482 ////////////////////////////////////////////////////////////////////
483 // Function: BulletRigidBodyNode::get_gravity
484 // Access: Published
485 // Description:
486 ////////////////////////////////////////////////////////////////////
487 LVector3 BulletRigidBodyNode::
488 get_gravity() const {
489 
490  return btVector3_to_LVector3(_rigid->getGravity());
491 }
492 
493 ////////////////////////////////////////////////////////////////////
494 // Function: BulletRigidBodyNode::set_linear_factor
495 // Access: Published
496 // Description:
497 ////////////////////////////////////////////////////////////////////
498 void BulletRigidBodyNode::
499 set_linear_factor(const LVector3 &factor) {
500 
501  _rigid->setLinearFactor(LVecBase3_to_btVector3(factor));
502 }
503 
504 ////////////////////////////////////////////////////////////////////
505 // Function: BulletRigidBodyNode::set_angular_factor
506 // Access: Published
507 // Description:
508 ////////////////////////////////////////////////////////////////////
509 void BulletRigidBodyNode::
510 set_angular_factor(const LVector3 &factor) {
511 
512  _rigid->setAngularFactor(LVecBase3_to_btVector3(factor));
513 }
514 
515 ////////////////////////////////////////////////////////////////////
516 // Function: BulletRigidBodyNode::get_total_force
517 // Access: Published
518 // Description:
519 ////////////////////////////////////////////////////////////////////
520 LVector3 BulletRigidBodyNode::
521 get_total_force() const {
522 
523  return btVector3_to_LVector3(_rigid->getTotalForce());
524 }
525 
526 ////////////////////////////////////////////////////////////////////
527 // Function: BulletRigidBodyNode::get_total_torque
528 // Access: Published
529 // Description:
530 ////////////////////////////////////////////////////////////////////
531 LVector3 BulletRigidBodyNode::
532 get_total_torque() const {
533 
534  return btVector3_to_LVector3(_rigid->getTotalTorque());
535 }
536 
537 ////////////////////////////////////////////////////////////////////
538 // Function: BulletRigidBodyNode::MotionState::Constructor
539 // Access: Public
540 // Description:
541 ////////////////////////////////////////////////////////////////////
542 BulletRigidBodyNode::MotionState::
543 MotionState() {
544 
545  _trans.setIdentity();
546  _disabled = false;
547  _dirty = false;
548  _was_dirty = false;
549 }
550 
551 ////////////////////////////////////////////////////////////////////
552 // Function: BulletRigidBodyNode::MotionState::getWorldTransform
553 // Access: Public
554 // Description:
555 ////////////////////////////////////////////////////////////////////
556 void BulletRigidBodyNode::MotionState::
557 getWorldTransform(btTransform &trans) const {
558 
559  trans = _trans;
560 }
561 
562 ////////////////////////////////////////////////////////////////////
563 // Function: BulletRigidBodyNode::MotionState::setWorldTransform
564 // Access: Public
565 // Description:
566 ////////////////////////////////////////////////////////////////////
567 void BulletRigidBodyNode::MotionState::
568 setWorldTransform(const btTransform &trans) {
569 
570  _trans = trans;
571  _dirty = true;
572  _was_dirty = true;
573 }
574 
575 ////////////////////////////////////////////////////////////////////
576 // Function: BulletRigidBodyNode::MotionState::sync_b2p
577 // Access: Public
578 // Description:
579 ////////////////////////////////////////////////////////////////////
580 void BulletRigidBodyNode::MotionState::
581 sync_b2p(PandaNode *node) {
582 
583  if (!_dirty) return;
584 
585  NodePath np = NodePath::any_path(node);
586  LPoint3 p = btVector3_to_LPoint3(_trans.getOrigin());
587  LQuaternion q = btQuat_to_LQuaternion(_trans.getRotation());
588 
589  _disabled = true;
590  np.set_pos_quat(NodePath(), p, q);
591  _disabled = false;
592  _dirty = false;
593 }
594 
595 ////////////////////////////////////////////////////////////////////
596 // Function: BulletRigidBodyNode::MotionState::set_net_transform
597 // Access: Public
598 // Description: This method stores the global transform within the
599 // Motionstate. It is called from
600 // BulletRigidBodyNode::transform_changed().
601 // For kinematic bodies the global transform is
602 // required since Bullet queries the body transform
603 // via MotionState::getGlobalStranform().
604 // For dynamic bodies the global scale is required,
605 // since Bullet will overwrite the member _trans
606 // by calling MotionState::setGlobalTransform.
607 ////////////////////////////////////////////////////////////////////
608 void BulletRigidBodyNode::MotionState::
609 set_net_transform(const TransformState *ts) {
610 
611  nassertv(ts);
612 
613  _trans = TransformState_to_btTrans(ts);
614 }
615 
616 ////////////////////////////////////////////////////////////////////
617 // Function: BulletRigidBodyNode::MotionState::sync_disabled
618 // Access: Public
619 // Description:
620 ////////////////////////////////////////////////////////////////////
621 bool BulletRigidBodyNode::MotionState::
622 sync_disabled() const {
623 
624  return _disabled;
625 }
626 
627 ////////////////////////////////////////////////////////////////////
628 // Function: BulletRigidBodyNode::MotionState::pick_dirty_flag
629 // Access: Public
630 // Description:
631 ////////////////////////////////////////////////////////////////////
632 bool BulletRigidBodyNode::MotionState::
633 pick_dirty_flag() {
634 
635  bool rc = _was_dirty;
636  _was_dirty = false;
637  return rc;
638 }
639 
640 ////////////////////////////////////////////////////////////////////
641 // Function: BulletRigidBodyNode::pick_dirty_flag
642 // Access: Published
643 // Description: Returns TRUE if the transform of the rigid body
644 // has changed at least once since the last call to
645 // this method.
646 ////////////////////////////////////////////////////////////////////
649 
650  return _motion->pick_dirty_flag();
651 }
652 
void set_inertia(const LVecBase3 &inertia)
Sets the inertia of a rigid body.
A basic node of the scene graph or data graph.
Definition: pandaNode.h:72
This is the base class for all three-component vectors and points.
Definition: lvecBase3.h:105
void set_mass(PN_stdfloat mass)
Sets the mass of a rigid body.
PN_stdfloat get_inv_mass() const
Returns the inverse mass of a rigid body.
PN_stdfloat get_mass() const
Returns the total mass of a rigid body.
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
Definition: lvector3.h:100
void set_pos_quat(const LVecBase3 &pos, const LQuaternion &quat)
Sets the translation and rotation component of the transform, leaving scale untouched.
Definition: nodePath.cxx:1412
This is a three-component point in space (as opposed to a three-component vector, which represents a ...
Definition: lpoint3.h:99
bool is_nan() const
Returns true if any component of the vector is not-a-number, false otherwise.
Definition: lvecBase3.h:464
static NodePath any_path(PandaNode *node, Thread *current_thread=Thread::get_current_thread())
Returns a new NodePath that represents any arbitrary path from the root to the indicated node...
Definition: nodePath.I:77
LVector3 get_inertia() const
Returns the inertia of the rigid body.
This is the base quaternion class.
Definition: lquaternion.h:96
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
This is a 3-by-3 transform matrix.
Definition: lmatrix.h:110
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:165
bool pick_dirty_flag()
Returns TRUE if the transform of the rigid body has changed at least once since the last call to this...