Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/modules/jolt_physics/objects/jolt_body_3d.cpp
20943 views
1
/**************************************************************************/
2
/* jolt_body_3d.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "jolt_body_3d.h"
32
33
#include "../joints/jolt_joint_3d.h"
34
#include "../jolt_project_settings.h"
35
#include "../misc/jolt_math_funcs.h"
36
#include "../misc/jolt_type_conversions.h"
37
#include "../shapes/jolt_shape_3d.h"
38
#include "../spaces/jolt_broad_phase_layer.h"
39
#include "../spaces/jolt_space_3d.h"
40
#include "jolt_area_3d.h"
41
#include "jolt_group_filter.h"
42
#include "jolt_physics_direct_body_state_3d.h"
43
#include "jolt_soft_body_3d.h"
44
45
namespace {
46
47
template <typename TValue, typename TGetter>
48
bool integrate(TValue &p_value, PhysicsServer3D::AreaSpaceOverrideMode p_mode, TGetter &&p_getter) {
49
switch (p_mode) {
50
case PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED: {
51
return false;
52
}
53
case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE: {
54
p_value += p_getter();
55
return false;
56
}
57
case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: {
58
p_value += p_getter();
59
return true;
60
}
61
case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE: {
62
p_value = p_getter();
63
return true;
64
}
65
case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: {
66
p_value = p_getter();
67
return false;
68
}
69
default: {
70
ERR_FAIL_V_MSG(false, vformat("Unhandled override mode: '%d'. This should not happen. Please report this.", p_mode));
71
}
72
}
73
}
74
75
} // namespace
76
77
JPH::BroadPhaseLayer JoltBody3D::_get_broad_phase_layer() const {
78
switch (mode) {
79
case PhysicsServer3D::BODY_MODE_STATIC: {
80
return _is_big() ? JoltBroadPhaseLayer::BODY_STATIC_BIG : JoltBroadPhaseLayer::BODY_STATIC;
81
}
82
case PhysicsServer3D::BODY_MODE_KINEMATIC:
83
case PhysicsServer3D::BODY_MODE_RIGID:
84
case PhysicsServer3D::BODY_MODE_RIGID_LINEAR: {
85
return JoltBroadPhaseLayer::BODY_DYNAMIC;
86
}
87
default: {
88
ERR_FAIL_V_MSG(JoltBroadPhaseLayer::BODY_STATIC, vformat("Unhandled body mode: '%d'. This should not happen. Please report this.", mode));
89
}
90
}
91
}
92
93
JPH::ObjectLayer JoltBody3D::_get_object_layer() const {
94
ERR_FAIL_NULL_V(space, 0);
95
96
if (jolt_shape == nullptr || jolt_shape->GetType() == JPH::EShapeType::Empty) {
97
// No point doing collision checks against a shapeless object.
98
return space->map_to_object_layer(_get_broad_phase_layer(), 0, 0);
99
}
100
101
return space->map_to_object_layer(_get_broad_phase_layer(), collision_layer, collision_mask);
102
}
103
104
JPH::EMotionType JoltBody3D::_get_motion_type() const {
105
switch (mode) {
106
case PhysicsServer3D::BODY_MODE_STATIC: {
107
return JPH::EMotionType::Static;
108
}
109
case PhysicsServer3D::BODY_MODE_KINEMATIC: {
110
return JPH::EMotionType::Kinematic;
111
}
112
case PhysicsServer3D::BODY_MODE_RIGID:
113
case PhysicsServer3D::BODY_MODE_RIGID_LINEAR: {
114
return JPH::EMotionType::Dynamic;
115
}
116
default: {
117
ERR_FAIL_V_MSG(JPH::EMotionType::Static, vformat("Unhandled body mode: '%d'. This should not happen. Please report this.", mode));
118
}
119
}
120
}
121
122
void JoltBody3D::_add_to_space() {
123
jolt_shape = build_shapes(true);
124
125
JPH::CollisionGroup::GroupID group_id = 0;
126
JPH::CollisionGroup::SubGroupID sub_group_id = 0;
127
JoltGroupFilter::encode_object(this, group_id, sub_group_id);
128
129
jolt_settings->mUserData = reinterpret_cast<JPH::uint64>(this);
130
jolt_settings->mObjectLayer = _get_object_layer();
131
jolt_settings->mCollisionGroup = JPH::CollisionGroup(nullptr, group_id, sub_group_id);
132
jolt_settings->mMotionType = _get_motion_type();
133
jolt_settings->mAllowedDOFs = _calculate_allowed_dofs();
134
jolt_settings->mAllowDynamicOrKinematic = true;
135
jolt_settings->mCollideKinematicVsNonDynamic = reports_all_kinematic_contacts();
136
jolt_settings->mUseManifoldReduction = !reports_contacts();
137
jolt_settings->mAllowSleeping = is_sleep_actually_allowed();
138
jolt_settings->mLinearDamping = 0.0f;
139
jolt_settings->mAngularDamping = 0.0f;
140
jolt_settings->mMaxLinearVelocity = JoltProjectSettings::max_linear_velocity;
141
jolt_settings->mMaxAngularVelocity = JoltProjectSettings::max_angular_velocity;
142
143
if (JoltProjectSettings::use_enhanced_internal_edge_removal_for_bodies) {
144
jolt_settings->mEnhancedInternalEdgeRemoval = true;
145
}
146
147
jolt_settings->mOverrideMassProperties = JPH::EOverrideMassProperties::MassAndInertiaProvided;
148
jolt_settings->mMassPropertiesOverride = _calculate_mass_properties();
149
150
jolt_settings->SetShape(jolt_shape);
151
152
JPH::Body *new_jolt_body = space->add_object(*this, *jolt_settings, sleep_initially);
153
if (new_jolt_body == nullptr) {
154
return;
155
}
156
157
jolt_body = new_jolt_body;
158
159
delete jolt_settings;
160
jolt_settings = nullptr;
161
}
162
163
void JoltBody3D::_enqueue_call_queries() {
164
// This method will be called from the body activation listener on multiple threads during the simulation step.
165
166
if (space != nullptr) {
167
space->enqueue_call_queries(&call_queries_element);
168
}
169
}
170
171
void JoltBody3D::_dequeue_call_queries() {
172
if (space != nullptr) {
173
space->dequeue_call_queries(&call_queries_element);
174
}
175
}
176
177
void JoltBody3D::_integrate_forces(float p_step, JPH::Body &p_jolt_body) {
178
_update_gravity(p_jolt_body);
179
180
if (!custom_integrator) {
181
JPH::MotionProperties &motion_properties = *p_jolt_body.GetMotionPropertiesUnchecked();
182
183
// Jolt applies damping differently from Godot Physics, where Godot Physics applies damping before integrating
184
// forces whereas Jolt does it after integrating forces. The way Godot Physics does it seems to yield more
185
// consistent results across different update frequencies when using high (>1) damping values, so we apply the
186
// damping ourselves instead, before any force integration happens.
187
JPH::Vec3 linear_velocity = motion_properties.GetLinearVelocity();
188
linear_velocity *= MAX(1.0f - total_linear_damp * p_step, 0.0f);
189
motion_properties.SetLinearVelocity(linear_velocity);
190
191
JPH::Vec3 angular_velocity = motion_properties.GetAngularVelocity();
192
angular_velocity *= MAX(1.0f - total_angular_damp * p_step, 0.0f);
193
motion_properties.SetAngularVelocity(angular_velocity);
194
195
p_jolt_body.AddForce(to_jolt(gravity / motion_properties.GetInverseMass() + constant_force));
196
p_jolt_body.AddTorque(to_jolt(constant_torque));
197
}
198
}
199
200
void JoltBody3D::_move_kinematic(float p_step, JPH::Body &p_jolt_body) {
201
p_jolt_body.SetLinearVelocity(JPH::Vec3::sZero());
202
p_jolt_body.SetAngularVelocity(JPH::Vec3::sZero());
203
204
const JPH::RVec3 current_position = p_jolt_body.GetPosition();
205
const JPH::Quat current_rotation = p_jolt_body.GetRotation();
206
207
const JPH::RVec3 new_position = to_jolt_r(kinematic_transform.origin);
208
const JPH::Quat new_rotation = to_jolt(kinematic_transform.basis);
209
210
if (new_position == current_position && new_rotation == current_rotation) {
211
return;
212
}
213
214
p_jolt_body.MoveKinematic(new_position, new_rotation, p_step);
215
}
216
217
JPH::EAllowedDOFs JoltBody3D::_calculate_allowed_dofs() const {
218
if (is_static()) {
219
return JPH::EAllowedDOFs::All;
220
}
221
222
JPH::EAllowedDOFs allowed_dofs = JPH::EAllowedDOFs::All;
223
224
if (is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_X)) {
225
allowed_dofs &= ~JPH::EAllowedDOFs::TranslationX;
226
}
227
228
if (is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_Y)) {
229
allowed_dofs &= ~JPH::EAllowedDOFs::TranslationY;
230
}
231
232
if (is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_Z)) {
233
allowed_dofs &= ~JPH::EAllowedDOFs::TranslationZ;
234
}
235
236
if (is_axis_locked(PhysicsServer3D::BODY_AXIS_ANGULAR_X) || is_rigid_linear()) {
237
allowed_dofs &= ~JPH::EAllowedDOFs::RotationX;
238
}
239
240
if (is_axis_locked(PhysicsServer3D::BODY_AXIS_ANGULAR_Y) || is_rigid_linear()) {
241
allowed_dofs &= ~JPH::EAllowedDOFs::RotationY;
242
}
243
244
if (is_axis_locked(PhysicsServer3D::BODY_AXIS_ANGULAR_Z) || is_rigid_linear()) {
245
allowed_dofs &= ~JPH::EAllowedDOFs::RotationZ;
246
}
247
248
ERR_FAIL_COND_V_MSG(allowed_dofs == JPH::EAllowedDOFs::None, JPH::EAllowedDOFs::All, vformat("Invalid axis locks for '%s'. Locking all axes is not supported when using Jolt Physics. All axes will be unlocked. Considering freezing the body instead.", to_string()));
249
250
return allowed_dofs;
251
}
252
253
JPH::MassProperties JoltBody3D::_calculate_mass_properties(const JPH::Shape &p_shape) const {
254
const bool calculate_mass = mass <= 0;
255
const bool calculate_inertia = inertia.x <= 0 || inertia.y <= 0 || inertia.z <= 0;
256
257
JPH::MassProperties mass_properties = p_shape.GetMassProperties();
258
259
if (calculate_mass && calculate_inertia) {
260
// Use the mass properties calculated by the shape
261
} else if (calculate_inertia) {
262
mass_properties.ScaleToMass(mass);
263
} else {
264
mass_properties.mMass = mass;
265
}
266
267
if (inertia.x > 0) {
268
mass_properties.mInertia(0, 0) = (float)inertia.x;
269
mass_properties.mInertia(0, 1) = 0;
270
mass_properties.mInertia(0, 2) = 0;
271
mass_properties.mInertia(1, 0) = 0;
272
mass_properties.mInertia(2, 0) = 0;
273
}
274
275
if (inertia.y > 0) {
276
mass_properties.mInertia(1, 1) = (float)inertia.y;
277
mass_properties.mInertia(1, 0) = 0;
278
mass_properties.mInertia(1, 2) = 0;
279
mass_properties.mInertia(0, 1) = 0;
280
mass_properties.mInertia(2, 1) = 0;
281
}
282
283
if (inertia.z > 0) {
284
mass_properties.mInertia(2, 2) = (float)inertia.z;
285
mass_properties.mInertia(2, 0) = 0;
286
mass_properties.mInertia(2, 1) = 0;
287
mass_properties.mInertia(0, 2) = 0;
288
mass_properties.mInertia(1, 2) = 0;
289
}
290
291
mass_properties.mInertia(3, 3) = 1.0f;
292
293
return mass_properties;
294
}
295
296
JPH::MassProperties JoltBody3D::_calculate_mass_properties() const {
297
return _calculate_mass_properties(*jolt_shape);
298
}
299
300
void JoltBody3D::_on_wake_up() {
301
// This method will be called from the body activation listener on multiple threads during the simulation step.
302
303
if (_should_call_queries()) {
304
_enqueue_call_queries();
305
}
306
}
307
308
void JoltBody3D::_update_mass_properties() {
309
if (in_space()) {
310
jolt_body->GetMotionPropertiesUnchecked()->SetMassProperties(_calculate_allowed_dofs(), _calculate_mass_properties());
311
}
312
}
313
314
void JoltBody3D::_update_gravity(JPH::Body &p_jolt_body) {
315
gravity = Vector3();
316
317
const Vector3 position = to_godot(p_jolt_body.GetPosition());
318
319
bool gravity_done = false;
320
321
for (const JoltArea3D *area : areas) {
322
gravity_done = integrate(gravity, area->get_gravity_mode(), [&]() {
323
return area->compute_gravity(position);
324
});
325
326
if (gravity_done) {
327
break;
328
}
329
}
330
331
if (!gravity_done) {
332
gravity += space->get_default_area()->compute_gravity(position);
333
}
334
335
gravity *= gravity_scale;
336
}
337
338
void JoltBody3D::_update_damp() {
339
if (!in_space()) {
340
return;
341
}
342
343
total_linear_damp = 0.0;
344
total_angular_damp = 0.0;
345
346
bool linear_damp_done = linear_damp_mode == PhysicsServer3D::BODY_DAMP_MODE_REPLACE;
347
bool angular_damp_done = angular_damp_mode == PhysicsServer3D::BODY_DAMP_MODE_REPLACE;
348
349
for (const JoltArea3D *area : areas) {
350
if (!linear_damp_done) {
351
linear_damp_done = integrate(total_linear_damp, area->get_linear_damp_mode(), [&]() {
352
return area->get_linear_damp();
353
});
354
}
355
356
if (!angular_damp_done) {
357
angular_damp_done = integrate(total_angular_damp, area->get_angular_damp_mode(), [&]() {
358
return area->get_angular_damp();
359
});
360
}
361
362
if (linear_damp_done && angular_damp_done) {
363
break;
364
}
365
}
366
367
const JoltArea3D *default_area = space->get_default_area();
368
369
if (!linear_damp_done) {
370
total_linear_damp += default_area->get_linear_damp();
371
}
372
373
if (!angular_damp_done) {
374
total_angular_damp += default_area->get_angular_damp();
375
}
376
377
switch (linear_damp_mode) {
378
case PhysicsServer3D::BODY_DAMP_MODE_COMBINE: {
379
total_linear_damp += linear_damp;
380
} break;
381
case PhysicsServer3D::BODY_DAMP_MODE_REPLACE: {
382
total_linear_damp = linear_damp;
383
} break;
384
}
385
386
switch (angular_damp_mode) {
387
case PhysicsServer3D::BODY_DAMP_MODE_COMBINE: {
388
total_angular_damp += angular_damp;
389
} break;
390
case PhysicsServer3D::BODY_DAMP_MODE_REPLACE: {
391
total_angular_damp = angular_damp;
392
} break;
393
}
394
395
_motion_changed();
396
}
397
398
void JoltBody3D::_update_kinematic_transform() {
399
if (is_kinematic()) {
400
kinematic_transform = get_transform_unscaled();
401
}
402
}
403
404
void JoltBody3D::_update_joint_constraints() {
405
for (JoltJoint3D *joint : joints) {
406
joint->rebuild();
407
}
408
}
409
410
void JoltBody3D::_update_possible_kinematic_contacts() {
411
const bool value = reports_all_kinematic_contacts();
412
413
if (!in_space()) {
414
jolt_settings->mCollideKinematicVsNonDynamic = value;
415
} else {
416
jolt_body->SetCollideKinematicVsNonDynamic(value);
417
}
418
}
419
420
void JoltBody3D::_update_sleep_allowed() {
421
const bool value = is_sleep_actually_allowed();
422
423
if (!in_space()) {
424
jolt_settings->mAllowSleeping = value;
425
} else {
426
jolt_body->SetAllowSleeping(value);
427
}
428
}
429
430
void JoltBody3D::_destroy_joint_constraints() {
431
for (JoltJoint3D *joint : joints) {
432
joint->destroy();
433
}
434
}
435
436
void JoltBody3D::_exit_all_areas() {
437
if (!in_space()) {
438
return;
439
}
440
441
for (JoltArea3D *area : areas) {
442
area->body_exited(jolt_body->GetID(), false);
443
}
444
445
areas.clear();
446
}
447
448
void JoltBody3D::_update_group_filter() {
449
JPH::GroupFilter *group_filter = !exceptions.is_empty() ? JoltGroupFilter::instance : nullptr;
450
451
if (!in_space()) {
452
jolt_settings->mCollisionGroup.SetGroupFilter(group_filter);
453
} else {
454
jolt_body->GetCollisionGroup().SetGroupFilter(group_filter);
455
}
456
}
457
458
void JoltBody3D::_mode_changed() {
459
_update_object_layer();
460
_update_kinematic_transform();
461
_update_mass_properties();
462
_update_sleep_allowed();
463
wake_up();
464
}
465
466
void JoltBody3D::_shapes_committed() {
467
JoltShapedObject3D::_shapes_committed();
468
469
_update_mass_properties();
470
_update_joint_constraints();
471
wake_up();
472
}
473
474
void JoltBody3D::_space_changing() {
475
JoltShapedObject3D::_space_changing();
476
477
sleep_initially = is_sleeping();
478
479
_destroy_joint_constraints();
480
_exit_all_areas();
481
_dequeue_call_queries();
482
}
483
484
void JoltBody3D::_space_changed() {
485
JoltShapedObject3D::_space_changed();
486
487
_update_kinematic_transform();
488
_update_group_filter();
489
_update_joint_constraints();
490
_update_sleep_allowed();
491
_areas_changed();
492
}
493
494
void JoltBody3D::_areas_changed() {
495
_update_damp();
496
wake_up();
497
}
498
499
void JoltBody3D::_joints_changed() {
500
wake_up();
501
}
502
503
void JoltBody3D::_transform_changed() {
504
wake_up();
505
}
506
507
void JoltBody3D::_motion_changed() {
508
wake_up();
509
}
510
511
void JoltBody3D::_exceptions_changed() {
512
_update_group_filter();
513
}
514
515
void JoltBody3D::_axis_lock_changed() {
516
_update_mass_properties();
517
wake_up();
518
}
519
520
void JoltBody3D::_contact_reporting_changed() {
521
_update_possible_kinematic_contacts();
522
_update_sleep_allowed();
523
wake_up();
524
}
525
526
void JoltBody3D::_sleep_allowed_changed() {
527
_update_sleep_allowed();
528
wake_up();
529
}
530
531
JoltBody3D::JoltBody3D() :
532
JoltShapedObject3D(OBJECT_TYPE_BODY),
533
call_queries_element(this) {
534
}
535
536
JoltBody3D::~JoltBody3D() {
537
if (direct_state != nullptr) {
538
memdelete(direct_state);
539
direct_state = nullptr;
540
}
541
}
542
543
void JoltBody3D::set_transform(Transform3D p_transform) {
544
JOLT_ENSURE_SCALE_NOT_ZERO(p_transform, vformat("An invalid transform was passed to physics body '%s'.", to_string()));
545
546
Vector3 new_scale;
547
JoltMath::decompose(p_transform, new_scale);
548
549
// Ideally we would do an exact comparison here, but due to floating-point precision this would be invalidated very often.
550
if (!scale.is_equal_approx(new_scale)) {
551
scale = new_scale;
552
_shapes_changed();
553
}
554
555
if (!in_space()) {
556
jolt_settings->mPosition = to_jolt_r(p_transform.origin);
557
jolt_settings->mRotation = to_jolt(p_transform.basis);
558
} else if (is_kinematic()) {
559
kinematic_transform = p_transform;
560
} else {
561
space->get_body_iface().SetPositionAndRotation(jolt_body->GetID(), to_jolt_r(p_transform.origin), to_jolt(p_transform.basis), JPH::EActivation::DontActivate);
562
}
563
564
_transform_changed();
565
}
566
567
Variant JoltBody3D::get_state(PhysicsServer3D::BodyState p_state) const {
568
switch (p_state) {
569
case PhysicsServer3D::BODY_STATE_TRANSFORM: {
570
return get_transform_scaled();
571
}
572
case PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY: {
573
return get_linear_velocity();
574
}
575
case PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY: {
576
return get_angular_velocity();
577
}
578
case PhysicsServer3D::BODY_STATE_SLEEPING: {
579
return is_sleeping();
580
}
581
case PhysicsServer3D::BODY_STATE_CAN_SLEEP: {
582
return is_sleep_allowed();
583
}
584
default: {
585
ERR_FAIL_V_MSG(Variant(), vformat("Unhandled body state: '%d'. This should not happen. Please report this.", p_state));
586
}
587
}
588
}
589
590
void JoltBody3D::set_state(PhysicsServer3D::BodyState p_state, const Variant &p_value) {
591
switch (p_state) {
592
case PhysicsServer3D::BODY_STATE_TRANSFORM: {
593
set_transform(p_value);
594
} break;
595
case PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY: {
596
set_linear_velocity(p_value);
597
} break;
598
case PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY: {
599
set_angular_velocity(p_value);
600
} break;
601
case PhysicsServer3D::BODY_STATE_SLEEPING: {
602
set_is_sleeping(p_value);
603
} break;
604
case PhysicsServer3D::BODY_STATE_CAN_SLEEP: {
605
set_is_sleep_allowed(p_value);
606
} break;
607
default: {
608
ERR_FAIL_MSG(vformat("Unhandled body state: '%d'. This should not happen. Please report this.", p_state));
609
} break;
610
}
611
}
612
613
Variant JoltBody3D::get_param(PhysicsServer3D::BodyParameter p_param) const {
614
switch (p_param) {
615
case PhysicsServer3D::BODY_PARAM_BOUNCE: {
616
return get_bounce();
617
}
618
case PhysicsServer3D::BODY_PARAM_FRICTION: {
619
return get_friction();
620
}
621
case PhysicsServer3D::BODY_PARAM_MASS: {
622
return get_mass();
623
}
624
case PhysicsServer3D::BODY_PARAM_INERTIA: {
625
return get_inertia();
626
}
627
case PhysicsServer3D::BODY_PARAM_CENTER_OF_MASS: {
628
return get_center_of_mass_custom();
629
}
630
case PhysicsServer3D::BODY_PARAM_GRAVITY_SCALE: {
631
return get_gravity_scale();
632
}
633
case PhysicsServer3D::BODY_PARAM_LINEAR_DAMP_MODE: {
634
return get_linear_damp_mode();
635
}
636
case PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP_MODE: {
637
return get_angular_damp_mode();
638
}
639
case PhysicsServer3D::BODY_PARAM_LINEAR_DAMP: {
640
return get_linear_damp();
641
}
642
case PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP: {
643
return get_angular_damp();
644
}
645
default: {
646
ERR_FAIL_V_MSG(Variant(), vformat("Unhandled body parameter: '%d'. This should not happen. Please report this.", p_param));
647
}
648
}
649
}
650
651
void JoltBody3D::set_param(PhysicsServer3D::BodyParameter p_param, const Variant &p_value) {
652
switch (p_param) {
653
case PhysicsServer3D::BODY_PARAM_BOUNCE: {
654
set_bounce(p_value);
655
} break;
656
case PhysicsServer3D::BODY_PARAM_FRICTION: {
657
set_friction(p_value);
658
} break;
659
case PhysicsServer3D::BODY_PARAM_MASS: {
660
set_mass(p_value);
661
} break;
662
case PhysicsServer3D::BODY_PARAM_INERTIA: {
663
set_inertia(p_value);
664
} break;
665
case PhysicsServer3D::BODY_PARAM_CENTER_OF_MASS: {
666
set_center_of_mass_custom(p_value);
667
} break;
668
case PhysicsServer3D::BODY_PARAM_GRAVITY_SCALE: {
669
set_gravity_scale(p_value);
670
} break;
671
case PhysicsServer3D::BODY_PARAM_LINEAR_DAMP_MODE: {
672
set_linear_damp_mode((DampMode)(int)p_value);
673
} break;
674
case PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP_MODE: {
675
set_angular_damp_mode((DampMode)(int)p_value);
676
} break;
677
case PhysicsServer3D::BODY_PARAM_LINEAR_DAMP: {
678
set_linear_damp(p_value);
679
} break;
680
case PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP: {
681
set_angular_damp(p_value);
682
} break;
683
default: {
684
ERR_FAIL_MSG(vformat("Unhandled body parameter: '%d'. This should not happen. Please report this.", p_param));
685
} break;
686
}
687
}
688
689
void JoltBody3D::set_custom_integrator(bool p_enabled) {
690
if (custom_integrator == p_enabled) {
691
return;
692
}
693
694
custom_integrator = p_enabled;
695
696
if (in_space()) {
697
jolt_body->ResetForce();
698
jolt_body->ResetTorque();
699
}
700
701
_motion_changed();
702
}
703
704
bool JoltBody3D::is_sleeping() const {
705
if (!in_space()) {
706
return sleep_initially;
707
} else {
708
return !jolt_body->IsActive();
709
}
710
}
711
712
bool JoltBody3D::is_sleep_actually_allowed() const {
713
return sleep_allowed && !(is_kinematic() && reports_contacts());
714
}
715
716
void JoltBody3D::set_is_sleeping(bool p_enabled) {
717
if (!in_space()) {
718
sleep_initially = p_enabled;
719
} else {
720
space->set_is_object_sleeping(jolt_body->GetID(), p_enabled);
721
}
722
}
723
724
void JoltBody3D::set_is_sleep_allowed(bool p_enabled) {
725
if (sleep_allowed == p_enabled) {
726
return;
727
}
728
729
sleep_allowed = p_enabled;
730
731
_sleep_allowed_changed();
732
}
733
734
Basis JoltBody3D::get_principal_inertia_axes() const {
735
ERR_FAIL_COND_V_MSG(!in_space(), Basis(), vformat("Failed to retrieve principal inertia axes of '%s'. Doing so without a physics space is not supported when using Jolt Physics. If this relates to a node, try adding the node to a scene tree first.", to_string()));
736
737
if (unlikely(is_static() || is_kinematic())) {
738
return Basis();
739
}
740
741
return to_godot(jolt_body->GetRotation() * jolt_body->GetMotionPropertiesUnchecked()->GetInertiaRotation());
742
}
743
744
Vector3 JoltBody3D::get_inverse_inertia() const {
745
ERR_FAIL_COND_V_MSG(!in_space(), Vector3(), vformat("Failed to retrieve inverse inertia of '%s'. Doing so without a physics space is not supported when using Jolt Physics. If this relates to a node, try adding the node to a scene tree first.", to_string()));
746
747
if (unlikely(is_static() || is_kinematic())) {
748
return Vector3();
749
}
750
751
return to_godot(jolt_body->GetMotionPropertiesUnchecked()->GetLocalSpaceInverseInertia().GetDiagonal3());
752
}
753
754
Basis JoltBody3D::get_inverse_inertia_tensor() const {
755
ERR_FAIL_COND_V_MSG(!in_space(), Basis(), vformat("Failed to retrieve inverse inertia tensor of '%s'. Doing so without a physics space is not supported when using Jolt Physics. If this relates to a node, try adding the node to a scene tree first.", to_string()));
756
757
if (unlikely(is_static() || is_kinematic())) {
758
return Basis();
759
}
760
761
return to_godot(jolt_body->GetInverseInertia()).basis;
762
}
763
764
void JoltBody3D::set_linear_velocity(const Vector3 &p_velocity) {
765
if (is_static() || is_kinematic()) {
766
linear_surface_velocity = p_velocity;
767
} else {
768
if (!in_space()) {
769
jolt_settings->mLinearVelocity = to_jolt(p_velocity);
770
} else {
771
jolt_body->GetMotionPropertiesUnchecked()->SetLinearVelocityClamped(to_jolt(p_velocity));
772
}
773
}
774
775
_motion_changed();
776
}
777
778
void JoltBody3D::set_angular_velocity(const Vector3 &p_velocity) {
779
if (is_static() || is_kinematic()) {
780
angular_surface_velocity = p_velocity;
781
} else {
782
if (!in_space()) {
783
jolt_settings->mAngularVelocity = to_jolt(p_velocity);
784
} else {
785
jolt_body->GetMotionPropertiesUnchecked()->SetAngularVelocityClamped(to_jolt(p_velocity));
786
}
787
}
788
789
_motion_changed();
790
}
791
792
void JoltBody3D::set_axis_velocity(const Vector3 &p_axis_velocity) {
793
const Vector3 axis = p_axis_velocity.normalized();
794
795
if (!in_space()) {
796
Vector3 linear_velocity = to_godot(jolt_settings->mLinearVelocity);
797
linear_velocity -= axis * axis.dot(linear_velocity);
798
linear_velocity += p_axis_velocity;
799
jolt_settings->mLinearVelocity = to_jolt(linear_velocity);
800
} else {
801
Vector3 linear_velocity = get_linear_velocity();
802
linear_velocity -= axis * axis.dot(linear_velocity);
803
linear_velocity += p_axis_velocity;
804
set_linear_velocity(linear_velocity);
805
}
806
807
_motion_changed();
808
}
809
810
Vector3 JoltBody3D::get_velocity_at_position(const Vector3 &p_position) const {
811
if (unlikely(!in_space())) {
812
return Vector3();
813
}
814
815
const JPH::MotionProperties &motion_properties = *jolt_body->GetMotionPropertiesUnchecked();
816
const Vector3 total_linear_velocity = to_godot(motion_properties.GetLinearVelocity()) + linear_surface_velocity;
817
const Vector3 total_angular_velocity = to_godot(motion_properties.GetAngularVelocity()) + angular_surface_velocity;
818
const Vector3 com_to_pos = p_position - to_godot(jolt_body->GetCenterOfMassPosition());
819
820
return total_linear_velocity + total_angular_velocity.cross(com_to_pos);
821
}
822
823
void JoltBody3D::set_center_of_mass_custom(const Vector3 &p_center_of_mass) {
824
if (custom_center_of_mass && p_center_of_mass == center_of_mass_custom) {
825
return;
826
}
827
828
custom_center_of_mass = true;
829
center_of_mass_custom = p_center_of_mass;
830
831
_shapes_changed();
832
}
833
834
void JoltBody3D::set_max_contacts_reported(int p_count) {
835
ERR_FAIL_INDEX(p_count, MAX_CONTACTS_REPORTED_3D_MAX);
836
837
if (unlikely((int)contacts.size() == p_count)) {
838
return;
839
}
840
841
contacts.resize(p_count);
842
contact_count = MIN(contact_count, p_count);
843
844
const bool use_manifold_reduction = !reports_contacts();
845
846
if (!in_space()) {
847
jolt_settings->mUseManifoldReduction = use_manifold_reduction;
848
} else {
849
space->get_body_iface().SetUseManifoldReduction(jolt_body->GetID(), use_manifold_reduction);
850
}
851
852
_contact_reporting_changed();
853
}
854
855
bool JoltBody3D::reports_all_kinematic_contacts() const {
856
return reports_contacts() && JoltProjectSettings::generate_all_kinematic_contacts;
857
}
858
859
void JoltBody3D::add_contact(const JoltBody3D *p_collider, float p_depth, int p_shape_index, int p_collider_shape_index, const Vector3 &p_normal, const Vector3 &p_position, const Vector3 &p_collider_position, const Vector3 &p_velocity, const Vector3 &p_collider_velocity, const Vector3 &p_impulse) {
860
const int max_contacts = get_max_contacts_reported();
861
862
if (max_contacts == 0) {
863
return;
864
}
865
866
Contact *contact = nullptr;
867
868
if (contact_count < max_contacts) {
869
contact = &contacts[contact_count++];
870
} else {
871
Contact *shallowest_contact = &contacts[0];
872
873
for (int i = 1; i < (int)contacts.size(); i++) {
874
Contact &other_contact = contacts[i];
875
if (other_contact.depth < shallowest_contact->depth) {
876
shallowest_contact = &other_contact;
877
}
878
}
879
880
if (shallowest_contact->depth < p_depth) {
881
contact = shallowest_contact;
882
}
883
}
884
885
if (contact != nullptr) {
886
contact->normal = p_normal;
887
contact->position = p_position;
888
contact->collider_position = p_collider_position;
889
contact->velocity = p_velocity;
890
contact->collider_velocity = p_collider_velocity;
891
contact->impulse = p_impulse;
892
contact->collider_id = p_collider->get_instance_id();
893
contact->collider_rid = p_collider->get_rid();
894
contact->shape_index = p_shape_index;
895
contact->collider_shape_index = p_collider_shape_index;
896
}
897
}
898
899
void JoltBody3D::reset_mass_properties() {
900
if (custom_center_of_mass) {
901
custom_center_of_mass = false;
902
center_of_mass_custom.zero();
903
904
_shapes_changed();
905
}
906
907
inertia.zero();
908
909
_update_mass_properties();
910
}
911
912
void JoltBody3D::apply_force(const Vector3 &p_force, const Vector3 &p_position) {
913
ERR_FAIL_COND_MSG(!in_space(), vformat("Failed to apply force to '%s'. Doing so without a physics space is not supported when using Jolt Physics. If this relates to a node, try adding the node to a scene tree first.", to_string()));
914
915
if (unlikely(!is_rigid()) || custom_integrator || p_force == Vector3()) {
916
return;
917
}
918
919
jolt_body->AddForce(to_jolt(p_force), jolt_body->GetPosition() + to_jolt(p_position));
920
921
_motion_changed();
922
}
923
924
void JoltBody3D::apply_central_force(const Vector3 &p_force) {
925
ERR_FAIL_COND_MSG(!in_space(), vformat("Failed to apply central force to '%s'. Doing so without a physics space is not supported when using Jolt Physics. If this relates to a node, try adding the node to a scene tree first.", to_string()));
926
927
if (unlikely(!is_rigid()) || custom_integrator || p_force == Vector3()) {
928
return;
929
}
930
931
jolt_body->AddForce(to_jolt(p_force));
932
933
_motion_changed();
934
}
935
936
void JoltBody3D::apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position) {
937
ERR_FAIL_COND_MSG(!in_space(), vformat("Failed to apply impulse to '%s'. Doing so without a physics space is not supported when using Jolt Physics. If this relates to a node, try adding the node to a scene tree first.", to_string()));
938
939
if (unlikely(!is_rigid()) || p_impulse == Vector3()) {
940
return;
941
}
942
943
jolt_body->AddImpulse(to_jolt(p_impulse), jolt_body->GetPosition() + to_jolt(p_position));
944
945
_motion_changed();
946
}
947
948
void JoltBody3D::apply_central_impulse(const Vector3 &p_impulse) {
949
ERR_FAIL_COND_MSG(!in_space(), vformat("Failed to apply central impulse to '%s'. Doing so without a physics space is not supported when using Jolt Physics. If this relates to a node, try adding the node to a scene tree first.", to_string()));
950
951
if (unlikely(!is_rigid()) || p_impulse == Vector3()) {
952
return;
953
}
954
955
jolt_body->AddImpulse(to_jolt(p_impulse));
956
957
_motion_changed();
958
}
959
960
void JoltBody3D::apply_torque(const Vector3 &p_torque) {
961
ERR_FAIL_COND_MSG(!in_space(), vformat("Failed to apply torque to '%s'. Doing so without a physics space is not supported when using Jolt Physics. If this relates to a node, try adding the node to a scene tree first.", to_string()));
962
963
if (unlikely(!is_rigid()) || custom_integrator || p_torque == Vector3()) {
964
return;
965
}
966
967
jolt_body->AddTorque(to_jolt(p_torque));
968
969
_motion_changed();
970
}
971
972
void JoltBody3D::apply_torque_impulse(const Vector3 &p_impulse) {
973
ERR_FAIL_COND_MSG(!in_space(), vformat("Failed to apply torque impulse to '%s'. Doing so without a physics space is not supported when using Jolt Physics. If this relates to a node, try adding the node to a scene tree first.", to_string()));
974
975
if (unlikely(!is_rigid()) || p_impulse == Vector3()) {
976
return;
977
}
978
979
jolt_body->AddAngularImpulse(to_jolt(p_impulse));
980
981
_motion_changed();
982
}
983
984
void JoltBody3D::add_constant_central_force(const Vector3 &p_force) {
985
if (p_force == Vector3()) {
986
return;
987
}
988
989
constant_force += p_force;
990
991
_motion_changed();
992
}
993
994
void JoltBody3D::add_constant_force(const Vector3 &p_force, const Vector3 &p_position) {
995
if (p_force == Vector3()) {
996
return;
997
}
998
999
constant_force += p_force;
1000
constant_torque += (p_position - get_center_of_mass_relative()).cross(p_force);
1001
1002
_motion_changed();
1003
}
1004
1005
void JoltBody3D::add_constant_torque(const Vector3 &p_torque) {
1006
if (p_torque == Vector3()) {
1007
return;
1008
}
1009
1010
constant_torque += p_torque;
1011
1012
_motion_changed();
1013
}
1014
1015
Vector3 JoltBody3D::get_constant_force() const {
1016
return constant_force;
1017
}
1018
1019
void JoltBody3D::set_constant_force(const Vector3 &p_force) {
1020
if (constant_force == p_force) {
1021
return;
1022
}
1023
1024
constant_force = p_force;
1025
1026
_motion_changed();
1027
}
1028
1029
Vector3 JoltBody3D::get_constant_torque() const {
1030
return constant_torque;
1031
}
1032
1033
void JoltBody3D::set_constant_torque(const Vector3 &p_torque) {
1034
if (constant_torque == p_torque) {
1035
return;
1036
}
1037
1038
constant_torque = p_torque;
1039
1040
_motion_changed();
1041
}
1042
1043
void JoltBody3D::add_collision_exception(const RID &p_excepted_body) {
1044
exceptions.push_back(p_excepted_body);
1045
1046
_exceptions_changed();
1047
}
1048
1049
void JoltBody3D::remove_collision_exception(const RID &p_excepted_body) {
1050
exceptions.erase(p_excepted_body);
1051
1052
_exceptions_changed();
1053
}
1054
1055
bool JoltBody3D::has_collision_exception(const RID &p_excepted_body) const {
1056
return exceptions.find(p_excepted_body) >= 0;
1057
}
1058
1059
void JoltBody3D::add_area(JoltArea3D *p_area) {
1060
int i = 0;
1061
for (; i < (int)areas.size(); i++) {
1062
if (p_area->get_priority() > areas[i]->get_priority()) {
1063
break;
1064
}
1065
}
1066
1067
areas.insert(i, p_area);
1068
1069
_areas_changed();
1070
}
1071
1072
void JoltBody3D::remove_area(JoltArea3D *p_area) {
1073
areas.erase(p_area);
1074
1075
_areas_changed();
1076
}
1077
1078
void JoltBody3D::add_joint(JoltJoint3D *p_joint) {
1079
joints.push_back(p_joint);
1080
1081
_joints_changed();
1082
}
1083
1084
void JoltBody3D::remove_joint(JoltJoint3D *p_joint) {
1085
joints.erase(p_joint);
1086
1087
_joints_changed();
1088
}
1089
1090
void JoltBody3D::call_queries() {
1091
if (custom_integration_callback.is_valid()) {
1092
const Variant direct_state_variant = get_direct_state();
1093
const Variant *args[2] = { &direct_state_variant, &custom_integration_userdata };
1094
const int argc = custom_integration_userdata.get_type() != Variant::NIL ? 2 : 1;
1095
1096
Callable::CallError ce;
1097
Variant ret;
1098
custom_integration_callback.callp(args, argc, ret, ce);
1099
1100
if (unlikely(ce.error != Callable::CallError::CALL_OK)) {
1101
ERR_PRINT_ONCE(vformat("Failed to call force integration callback for '%s'. It returned the following error: '%s'.", to_string(), Variant::get_callable_error_text(custom_integration_callback, args, argc, ce)));
1102
}
1103
}
1104
1105
if (state_sync_callback.is_valid()) {
1106
const Variant direct_state_variant = get_direct_state();
1107
const Variant *args[1] = { &direct_state_variant };
1108
1109
Callable::CallError ce;
1110
Variant ret;
1111
state_sync_callback.callp(args, 1, ret, ce);
1112
1113
if (unlikely(ce.error != Callable::CallError::CALL_OK)) {
1114
ERR_PRINT_ONCE(vformat("Failed to call state synchronization callback for '%s'. It returned the following error: '%s'.", to_string(), Variant::get_callable_error_text(state_sync_callback, args, 1, ce)));
1115
}
1116
}
1117
}
1118
1119
void JoltBody3D::pre_step(float p_step, JPH::Body &p_jolt_body) {
1120
JoltObject3D::pre_step(p_step, p_jolt_body);
1121
1122
switch (mode) {
1123
case PhysicsServer3D::BODY_MODE_STATIC: {
1124
// Will never happen.
1125
} break;
1126
case PhysicsServer3D::BODY_MODE_RIGID:
1127
case PhysicsServer3D::BODY_MODE_RIGID_LINEAR: {
1128
_integrate_forces(p_step, p_jolt_body);
1129
} break;
1130
case PhysicsServer3D::BODY_MODE_KINEMATIC: {
1131
_update_gravity(p_jolt_body);
1132
_move_kinematic(p_step, p_jolt_body);
1133
} break;
1134
}
1135
1136
if (_should_call_queries()) {
1137
_enqueue_call_queries();
1138
}
1139
1140
contact_count = 0;
1141
}
1142
1143
JoltPhysicsDirectBodyState3D *JoltBody3D::get_direct_state() {
1144
if (direct_state == nullptr) {
1145
direct_state = memnew(JoltPhysicsDirectBodyState3D(this));
1146
}
1147
1148
return direct_state;
1149
}
1150
1151
void JoltBody3D::set_mode(PhysicsServer3D::BodyMode p_mode) {
1152
if (p_mode == mode) {
1153
return;
1154
}
1155
1156
mode = p_mode;
1157
1158
if (!in_space()) {
1159
_mode_changed();
1160
return;
1161
}
1162
1163
const JPH::EMotionType motion_type = _get_motion_type();
1164
1165
if (motion_type == JPH::EMotionType::Static) {
1166
put_to_sleep();
1167
}
1168
1169
jolt_body->SetMotionType(motion_type);
1170
1171
if (motion_type != JPH::EMotionType::Static) {
1172
wake_up();
1173
}
1174
1175
if (motion_type == JPH::EMotionType::Kinematic) {
1176
jolt_body->SetLinearVelocity(JPH::Vec3::sZero());
1177
jolt_body->SetAngularVelocity(JPH::Vec3::sZero());
1178
}
1179
1180
linear_surface_velocity = Vector3();
1181
angular_surface_velocity = Vector3();
1182
1183
_mode_changed();
1184
}
1185
1186
bool JoltBody3D::is_ccd_enabled() const {
1187
if (!in_space()) {
1188
return jolt_settings->mMotionQuality == JPH::EMotionQuality::LinearCast;
1189
} else {
1190
return !is_static() && jolt_body->GetMotionProperties()->GetMotionQuality() == JPH::EMotionQuality::LinearCast;
1191
}
1192
}
1193
1194
void JoltBody3D::set_ccd_enabled(bool p_enabled) {
1195
const JPH::EMotionQuality motion_quality = p_enabled ? JPH::EMotionQuality::LinearCast : JPH::EMotionQuality::Discrete;
1196
1197
if (!in_space()) {
1198
jolt_settings->mMotionQuality = motion_quality;
1199
} else {
1200
space->get_body_iface().SetMotionQuality(jolt_body->GetID(), motion_quality);
1201
}
1202
}
1203
1204
void JoltBody3D::set_mass(float p_mass) {
1205
if (p_mass != mass) {
1206
mass = p_mass;
1207
_update_mass_properties();
1208
}
1209
}
1210
1211
void JoltBody3D::set_inertia(const Vector3 &p_inertia) {
1212
if (p_inertia != inertia) {
1213
inertia = p_inertia;
1214
_update_mass_properties();
1215
}
1216
}
1217
1218
float JoltBody3D::get_bounce() const {
1219
if (!in_space()) {
1220
return jolt_settings->mRestitution;
1221
} else {
1222
return jolt_body->GetRestitution();
1223
}
1224
}
1225
1226
void JoltBody3D::set_bounce(float p_bounce) {
1227
if (!in_space()) {
1228
jolt_settings->mRestitution = p_bounce;
1229
} else {
1230
jolt_body->SetRestitution(p_bounce);
1231
}
1232
}
1233
1234
float JoltBody3D::get_friction() const {
1235
if (!in_space()) {
1236
return jolt_settings->mFriction;
1237
} else {
1238
return jolt_body->GetFriction();
1239
}
1240
}
1241
1242
void JoltBody3D::set_friction(float p_friction) {
1243
if (!in_space()) {
1244
jolt_settings->mFriction = p_friction;
1245
} else {
1246
jolt_body->SetFriction(p_friction);
1247
}
1248
}
1249
1250
void JoltBody3D::set_gravity_scale(float p_scale) {
1251
if (gravity_scale == p_scale) {
1252
return;
1253
}
1254
1255
gravity_scale = p_scale;
1256
1257
_motion_changed();
1258
}
1259
1260
void JoltBody3D::set_linear_damp(float p_damp) {
1261
p_damp = MAX(0.0f, p_damp);
1262
1263
if (p_damp == linear_damp) {
1264
return;
1265
}
1266
1267
linear_damp = p_damp;
1268
1269
_update_damp();
1270
}
1271
1272
void JoltBody3D::set_angular_damp(float p_damp) {
1273
p_damp = MAX(0.0f, p_damp);
1274
1275
if (p_damp == angular_damp) {
1276
return;
1277
}
1278
1279
angular_damp = p_damp;
1280
1281
_update_damp();
1282
}
1283
1284
void JoltBody3D::set_linear_damp_mode(DampMode p_mode) {
1285
if (p_mode == linear_damp_mode) {
1286
return;
1287
}
1288
1289
linear_damp_mode = p_mode;
1290
1291
_update_damp();
1292
}
1293
1294
void JoltBody3D::set_angular_damp_mode(DampMode p_mode) {
1295
if (p_mode == angular_damp_mode) {
1296
return;
1297
}
1298
1299
angular_damp_mode = p_mode;
1300
1301
_update_damp();
1302
}
1303
1304
bool JoltBody3D::is_axis_locked(PhysicsServer3D::BodyAxis p_axis) const {
1305
return (locked_axes & (uint32_t)p_axis) != 0;
1306
}
1307
1308
void JoltBody3D::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_enabled) {
1309
const uint32_t previous_locked_axes = locked_axes;
1310
1311
if (p_enabled) {
1312
locked_axes |= (uint32_t)p_axis;
1313
} else {
1314
locked_axes &= ~(uint32_t)p_axis;
1315
}
1316
1317
if (previous_locked_axes != locked_axes) {
1318
_axis_lock_changed();
1319
}
1320
}
1321
1322
bool JoltBody3D::can_interact_with(const JoltBody3D &p_other) const {
1323
return (can_collide_with(p_other) || p_other.can_collide_with(*this)) && !has_collision_exception(p_other.get_rid()) && !p_other.has_collision_exception(rid);
1324
}
1325
1326
bool JoltBody3D::can_interact_with(const JoltSoftBody3D &p_other) const {
1327
return p_other.can_interact_with(*this);
1328
}
1329
1330
bool JoltBody3D::can_interact_with(const JoltArea3D &p_other) const {
1331
return p_other.can_interact_with(*this);
1332
}
1333
1334