Panda3D
bulletCharacterControllerNode.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file bulletCharacterControllerNode.cxx
10  * @author enn0x
11  * @date 2010-11-21
12  */
13 
15 
16 #include "config_bullet.h"
17 
18 #include "bulletWorld.h"
19 
20 #if BT_BULLET_VERSION >= 285
21 static const btVector3 up_vectors[3] = {btVector3(1.0f, 0.0f, 0.0f), btVector3(0.0f, 1.0f, 0.0f), btVector3(0.0f, 0.0f, 1.0f)};
22 #endif
23 
24 TypeHandle BulletCharacterControllerNode::_type_handle;
25 
26 /**
27  *
28  */
29 BulletCharacterControllerNode::
30 BulletCharacterControllerNode(BulletShape *shape, PN_stdfloat step_height, const char *name) : BulletBaseCharacterControllerNode(name) {
31 
32  // Synchronised transform
33  _sync = TransformState::make_identity();
34  _sync_disable = false;
35 
36  // Initial transform
37  btTransform trans = btTransform::getIdentity();
38 
39  // Get convex shape (for ghost object)
40  if (!shape->is_convex()) {
41  bullet_cat.error() << "a convex shape is required!" << std::endl;
42  return;
43  }
44 
45  btConvexShape *convex = (btConvexShape *)(shape->ptr());
46 
47  // Ghost object
48  _ghost = new btPairCachingGhostObject();
49  _ghost->setUserPointer(this);
50 
51  _ghost->setWorldTransform(trans);
52  _ghost->setInterpolationWorldTransform(trans);
53  _ghost->setCollisionShape(convex);
54  _ghost->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT);
55 
56  // Up axis
57  _up = get_default_up_axis();
58 
59  // Initialise movement
60  _linear_movement_is_local = false;
61  _linear_movement.set(0.0f, 0.0f, 0.0f);
62  _angular_movement = 0.0f;
63 
64  // Character controller
65 #if BT_BULLET_VERSION >= 285
66  _character = new btKinematicCharacterController(_ghost, convex, step_height, up_vectors[_up]);
67  _character->setGravity(up_vectors[_up] * -(btScalar)9.81f);
68 #else
69  _character = new btKinematicCharacterController(_ghost, convex, step_height, _up);
70  _character->setGravity((btScalar)9.81f);
71 #endif
72 
73  // Retain a pointer to the shape
74  _shape = shape;
75 
76  // Default collide mask TODO set_into_collide_mask(CollideMask::all_on());
77 }
78 
79 /**
80  *
81  */
82 void BulletCharacterControllerNode::
83 set_linear_movement(const LVector3 &movement, bool is_local) {
84  LightMutexHolder holder(BulletWorld::get_global_lock());
85 
86  nassertv(!movement.is_nan());
87 
88  _linear_movement = movement;
89  _linear_movement_is_local = is_local;
90 }
91 
92 /**
93  *
94  */
95 void BulletCharacterControllerNode::
96 set_angular_movement(PN_stdfloat omega) {
97  LightMutexHolder holder(BulletWorld::get_global_lock());
98 
99  _angular_movement = omega;
100 }
101 
102 /**
103  * Assumes the lock(bullet global lock) is held by the caller
104  */
106 do_sync_p2b(PN_stdfloat dt, int num_substeps) {
107 
108  // Synchronise global transform
109  do_transform_changed();
110 
111  // Angular rotation
112  btScalar angle = dt * deg_2_rad(_angular_movement);
113 
114  btMatrix3x3 m = _ghost->getWorldTransform().getBasis();
115  btVector3 up = m[_up];
116 
117  m *= btMatrix3x3(btQuaternion(up, angle));
118 
119  _ghost->getWorldTransform().setBasis(m);
120 
121  // Linear movement
122  LVector3 vp = _linear_movement / (btScalar)num_substeps;
123 
124  btVector3 v;
125  if (_linear_movement_is_local) {
126  btTransform xform = _ghost->getWorldTransform();
127  xform.setOrigin(btVector3(0.0f, 0.0f, 0.0f));
128  v = xform(LVecBase3_to_btVector3(vp));
129  }
130  else {
131  v = LVecBase3_to_btVector3(vp);
132  }
133 
134  // _character->setVelocityForTimeInterval(v, dt);
135  _character->setWalkDirection(v * dt);
136  _angular_movement = 0.0f;
137 }
138 
139 /**
140  * Assumes the lock(bullet global lock) is held by the caller
141  */
144 
145  NodePath np = NodePath::any_path((PandaNode *)this);
146  LVecBase3 scale = np.get_net_transform()->get_scale();
147 
148  btTransform trans = _ghost->getWorldTransform();
149  CPT(TransformState) ts = btTrans_to_TransformState(trans, scale);
150 
151  LMatrix4 m_sync = _sync->get_mat();
152  LMatrix4 m_ts = ts->get_mat();
153 
154  if (!m_sync.almost_equal(m_ts)) {
155  _sync = ts;
156  _sync_disable = true;
157  np.set_transform(NodePath(), ts);
158  _sync_disable = false;
159  }
160 }
161 
162 /**
163  * Assumes the lock(bullet global lock) is held by the caller
164  */
165 void BulletCharacterControllerNode::
166 do_transform_changed() {
167 
168  if (_sync_disable) return;
169 
170  NodePath np = NodePath::any_path((PandaNode *)this);
171  CPT(TransformState) ts = np.get_net_transform();
172 
173  LMatrix4 m_sync = _sync->get_mat();
174  LMatrix4 m_ts = ts->get_mat();
175 
176  if (!m_sync.almost_equal(m_ts)) {
177  _sync = ts;
178 
179  // Get translation, heading and scale
180  LPoint3 pos = ts->get_pos();
181  PN_stdfloat heading = ts->get_hpr().get_x();
182  LVecBase3 scale = ts->get_scale();
183 
184  // Set translation
185  _character->warp(LVecBase3_to_btVector3(pos));
186 
187  // Set Heading
188  btMatrix3x3 m = _ghost->getWorldTransform().getBasis();
189  btVector3 up = m[_up];
190 
191  m = btMatrix3x3(btQuaternion(up, deg_2_rad(heading)));
192 
193  _ghost->getWorldTransform().setBasis(m);
194 
195  // Set scale
196  _shape->do_set_local_scale(scale);
197  }
198 }
199 
200 /**
201  *
202  */
203 void BulletCharacterControllerNode::
204 transform_changed() {
205 
206  if (_sync_disable) return;
207 
208  LightMutexHolder holder(BulletWorld::get_global_lock());
209 
210  do_transform_changed();
211 }
212 
213 /**
214  *
215  */
216 BulletShape *BulletCharacterControllerNode::
217 get_shape() const {
218 
219  return _shape;
220 }
221 
222 /**
223  *
224  */
225 bool BulletCharacterControllerNode::
226 is_on_ground() const {
227  LightMutexHolder holder(BulletWorld::get_global_lock());
228 
229  return _character->onGround();
230 }
231 
232 /**
233  *
234  */
235 bool BulletCharacterControllerNode::
236 can_jump() const {
237  LightMutexHolder holder(BulletWorld::get_global_lock());
238 
239  return _character->canJump();
240 }
241 
242 /**
243  *
244  */
245 void BulletCharacterControllerNode::
246 do_jump() {
247  LightMutexHolder holder(BulletWorld::get_global_lock());
248 
249  _character->jump();
250 }
251 
252 /**
253  *
254  */
255 void BulletCharacterControllerNode::
256 set_fall_speed(PN_stdfloat fall_speed) {
257  LightMutexHolder holder(BulletWorld::get_global_lock());
258 
259  _character->setFallSpeed((btScalar)fall_speed);
260 }
261 
262 /**
263  *
264  */
265 void BulletCharacterControllerNode::
266 set_jump_speed(PN_stdfloat jump_speed) {
267  LightMutexHolder holder(BulletWorld::get_global_lock());
268 
269  _character->setJumpSpeed((btScalar)jump_speed);
270 }
271 
272 /**
273  *
274  */
275 void BulletCharacterControllerNode::
276 set_max_jump_height(PN_stdfloat max_jump_height) {
277  LightMutexHolder holder(BulletWorld::get_global_lock());
278 
279  _character->setMaxJumpHeight((btScalar)max_jump_height);
280 }
281 
282 /**
283  *
284  */
285 void BulletCharacterControllerNode::
286 set_max_slope(PN_stdfloat max_slope) {
287  LightMutexHolder holder(BulletWorld::get_global_lock());
288 
289  _character->setMaxSlope((btScalar)max_slope);
290 }
291 
292 /**
293  *
294  */
295 PN_stdfloat BulletCharacterControllerNode::
296 get_max_slope() const {
297  LightMutexHolder holder(BulletWorld::get_global_lock());
298 
299  return (PN_stdfloat)_character->getMaxSlope();
300 }
301 
302 /**
303  *
304  */
305 PN_stdfloat BulletCharacterControllerNode::
306 get_gravity() const {
307  LightMutexHolder holder(BulletWorld::get_global_lock());
308 
309 #if BT_BULLET_VERSION >= 285
310  return -(PN_stdfloat)_character->getGravity()[_up];
311 #else
312  return (PN_stdfloat)_character->getGravity();
313 #endif
314 }
315 
316 /**
317  *
318  */
319 void BulletCharacterControllerNode::
320 set_gravity(PN_stdfloat gravity) {
321  LightMutexHolder holder(BulletWorld::get_global_lock());
322 
323 #if BT_BULLET_VERSION >= 285
324  _character->setGravity(up_vectors[_up] * -(btScalar)gravity);
325 #else
326  _character->setGravity((btScalar)gravity);
327 #endif
328 }
329 
330 /**
331  *
332  */
333 void BulletCharacterControllerNode::
334 set_use_ghost_sweep_test(bool value) {
335  LightMutexHolder holder(BulletWorld::get_global_lock());
336 
337  return _character->setUseGhostSweepTest(value);
338 }
A basic node of the scene graph or data graph.
Definition: pandaNode.h:64
Indicates a coordinate-system transform on vertices.
virtual void do_sync_b2p()
Assumes the lock(bullet global lock) is held by the caller.
virtual void do_sync_p2b(PN_stdfloat dt, int num_substeps)
Assumes the lock(bullet global lock) is held by the caller.
void set_transform(const TransformState *transform, Thread *current_thread=Thread::get_current_thread())
Changes the complete transform object on this node.
Definition: nodePath.I:565
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:62
virtual void xform(const LMatrix4 &mat)
Transforms the contents of this PandaNode by the indicated matrix, if it means anything to do so.
Definition: pandaNode.cxx:310
Similar to MutexHolder, but for a light mutex.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
LVecBase3 get_scale() const
Retrieves the scale component of the transform.
Definition: nodePath.cxx:1128
const LMatrix4 & get_mat() const
Returns the transform matrix that has been applied to the referenced node, or the identity matrix if ...
Definition: nodePath.I:776
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:161
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.