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
10278 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
JPH::Vec3 linear_velocity = motion_properties.GetLinearVelocity();
184
JPH::Vec3 angular_velocity = motion_properties.GetAngularVelocity();
185
186
// Jolt applies damping differently from Godot Physics, where Godot Physics applies damping before integrating
187
// forces whereas Jolt does it after integrating forces. The way Godot Physics does it seems to yield more
188
// consistent results across different update frequencies when using high (>1) damping values, so we apply the
189
// damping ourselves instead, before any force integration happens.
190
191
linear_velocity *= MAX(1.0f - total_linear_damp * p_step, 0.0f);
192
angular_velocity *= MAX(1.0f - total_angular_damp * p_step, 0.0f);
193
194
linear_velocity += to_jolt(gravity) * p_step;
195
196
motion_properties.SetLinearVelocityClamped(linear_velocity);
197
motion_properties.SetAngularVelocityClamped(angular_velocity);
198
199
p_jolt_body.AddForce(to_jolt(constant_force));
200
p_jolt_body.AddTorque(to_jolt(constant_torque));
201
}
202
}
203
204
void JoltBody3D::_move_kinematic(float p_step, JPH::Body &p_jolt_body) {
205
p_jolt_body.SetLinearVelocity(JPH::Vec3::sZero());
206
p_jolt_body.SetAngularVelocity(JPH::Vec3::sZero());
207
208
const JPH::RVec3 current_position = p_jolt_body.GetPosition();
209
const JPH::Quat current_rotation = p_jolt_body.GetRotation();
210
211
const JPH::RVec3 new_position = to_jolt_r(kinematic_transform.origin);
212
const JPH::Quat new_rotation = to_jolt(kinematic_transform.basis);
213
214
if (new_position == current_position && new_rotation == current_rotation) {
215
return;
216
}
217
218
p_jolt_body.MoveKinematic(new_position, new_rotation, p_step);
219
}
220
221
JPH::EAllowedDOFs JoltBody3D::_calculate_allowed_dofs() const {
222
if (is_static()) {
223
return JPH::EAllowedDOFs::All;
224
}
225
226
JPH::EAllowedDOFs allowed_dofs = JPH::EAllowedDOFs::All;
227
228
if (is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_X)) {
229
allowed_dofs &= ~JPH::EAllowedDOFs::TranslationX;
230
}
231
232
if (is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_Y)) {
233
allowed_dofs &= ~JPH::EAllowedDOFs::TranslationY;
234
}
235
236
if (is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_Z)) {
237
allowed_dofs &= ~JPH::EAllowedDOFs::TranslationZ;
238
}
239
240
if (is_axis_locked(PhysicsServer3D::BODY_AXIS_ANGULAR_X) || is_rigid_linear()) {
241
allowed_dofs &= ~JPH::EAllowedDOFs::RotationX;
242
}
243
244
if (is_axis_locked(PhysicsServer3D::BODY_AXIS_ANGULAR_Y) || is_rigid_linear()) {
245
allowed_dofs &= ~JPH::EAllowedDOFs::RotationY;
246
}
247
248
if (is_axis_locked(PhysicsServer3D::BODY_AXIS_ANGULAR_Z) || is_rigid_linear()) {
249
allowed_dofs &= ~JPH::EAllowedDOFs::RotationZ;
250
}
251
252
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()));
253
254
return allowed_dofs;
255
}
256
257
JPH::MassProperties JoltBody3D::_calculate_mass_properties(const JPH::Shape &p_shape) const {
258
const bool calculate_mass = mass <= 0;
259
const bool calculate_inertia = inertia.x <= 0 || inertia.y <= 0 || inertia.z <= 0;
260
261
JPH::MassProperties mass_properties = p_shape.GetMassProperties();
262
263
if (calculate_mass && calculate_inertia) {
264
// Use the mass properties calculated by the shape
265
} else if (calculate_inertia) {
266
mass_properties.ScaleToMass(mass);
267
} else {
268
mass_properties.mMass = mass;
269
}
270
271
if (inertia.x > 0) {
272
mass_properties.mInertia(0, 0) = (float)inertia.x;
273
mass_properties.mInertia(0, 1) = 0;
274
mass_properties.mInertia(0, 2) = 0;
275
mass_properties.mInertia(1, 0) = 0;
276
mass_properties.mInertia(2, 0) = 0;
277
}
278
279
if (inertia.y > 0) {
280
mass_properties.mInertia(1, 1) = (float)inertia.y;
281
mass_properties.mInertia(1, 0) = 0;
282
mass_properties.mInertia(1, 2) = 0;
283
mass_properties.mInertia(0, 1) = 0;
284
mass_properties.mInertia(2, 1) = 0;
285
}
286
287
if (inertia.z > 0) {
288
mass_properties.mInertia(2, 2) = (float)inertia.z;
289
mass_properties.mInertia(2, 0) = 0;
290
mass_properties.mInertia(2, 1) = 0;
291
mass_properties.mInertia(0, 2) = 0;
292
mass_properties.mInertia(1, 2) = 0;
293
}
294
295
mass_properties.mInertia(3, 3) = 1.0f;
296
297
return mass_properties;
298
}
299
300
JPH::MassProperties JoltBody3D::_calculate_mass_properties() const {
301
return _calculate_mass_properties(*jolt_shape);
302
}
303
304
void JoltBody3D::_on_wake_up() {
305
// This method will be called from the body activation listener on multiple threads during the simulation step.
306
307
if (_should_call_queries()) {
308
_enqueue_call_queries();
309
}
310
}
311
312
void JoltBody3D::_update_mass_properties() {
313
if (in_space()) {
314
jolt_body->GetMotionPropertiesUnchecked()->SetMassProperties(_calculate_allowed_dofs(), _calculate_mass_properties());
315
}
316
}
317
318
void JoltBody3D::_update_gravity(JPH::Body &p_jolt_body) {
319
gravity = Vector3();
320
321
const Vector3 position = to_godot(p_jolt_body.GetPosition());
322
323
bool gravity_done = false;
324
325
for (const JoltArea3D *area : areas) {
326
gravity_done = integrate(gravity, area->get_gravity_mode(), [&]() {
327
return area->compute_gravity(position);
328
});
329
330
if (gravity_done) {
331
break;
332
}
333
}
334
335
if (!gravity_done) {
336
gravity += space->get_default_area()->compute_gravity(position);
337
}
338
339
gravity *= gravity_scale;
340
}
341
342
void JoltBody3D::_update_damp() {
343
if (!in_space()) {
344
return;
345
}
346
347
total_linear_damp = 0.0;
348
total_angular_damp = 0.0;
349
350
bool linear_damp_done = linear_damp_mode == PhysicsServer3D::BODY_DAMP_MODE_REPLACE;
351
bool angular_damp_done = angular_damp_mode == PhysicsServer3D::BODY_DAMP_MODE_REPLACE;
352
353
for (const JoltArea3D *area : areas) {
354
if (!linear_damp_done) {
355
linear_damp_done = integrate(total_linear_damp, area->get_linear_damp_mode(), [&]() {
356
return area->get_linear_damp();
357
});
358
}
359
360
if (!angular_damp_done) {
361
angular_damp_done = integrate(total_angular_damp, area->get_angular_damp_mode(), [&]() {
362
return area->get_angular_damp();
363
});
364
}
365
366
if (linear_damp_done && angular_damp_done) {
367
break;
368
}
369
}
370
371
const JoltArea3D *default_area = space->get_default_area();
372
373
if (!linear_damp_done) {
374
total_linear_damp += default_area->get_linear_damp();
375
}
376
377
if (!angular_damp_done) {
378
total_angular_damp += default_area->get_angular_damp();
379
}
380
381
switch (linear_damp_mode) {
382
case PhysicsServer3D::BODY_DAMP_MODE_COMBINE: {
383
total_linear_damp += linear_damp;
384
} break;
385
case PhysicsServer3D::BODY_DAMP_MODE_REPLACE: {
386
total_linear_damp = linear_damp;
387
} break;
388
}
389
390
switch (angular_damp_mode) {
391
case PhysicsServer3D::BODY_DAMP_MODE_COMBINE: {
392
total_angular_damp += angular_damp;
393
} break;
394
case PhysicsServer3D::BODY_DAMP_MODE_REPLACE: {
395
total_angular_damp = angular_damp;
396
} break;
397
}
398
399
_motion_changed();
400
}
401
402
void JoltBody3D::_update_kinematic_transform() {
403
if (is_kinematic()) {
404
kinematic_transform = get_transform_unscaled();
405
}
406
}
407
408
void JoltBody3D::_update_joint_constraints() {
409
for (JoltJoint3D *joint : joints) {
410
joint->rebuild();
411
}
412
}
413
414
void JoltBody3D::_update_possible_kinematic_contacts() {
415
const bool value = reports_all_kinematic_contacts();
416
417
if (!in_space()) {
418
jolt_settings->mCollideKinematicVsNonDynamic = value;
419
} else {
420
jolt_body->SetCollideKinematicVsNonDynamic(value);
421
}
422
}
423
424
void JoltBody3D::_update_sleep_allowed() {
425
const bool value = is_sleep_actually_allowed();
426
427
if (!in_space()) {
428
jolt_settings->mAllowSleeping = value;
429
} else {
430
jolt_body->SetAllowSleeping(value);
431
}
432
}
433
434
void JoltBody3D::_destroy_joint_constraints() {
435
for (JoltJoint3D *joint : joints) {
436
joint->destroy();
437
}
438
}
439
440
void JoltBody3D::_exit_all_areas() {
441
if (!in_space()) {
442
return;
443
}
444
445
for (JoltArea3D *area : areas) {
446
area->body_exited(jolt_body->GetID(), false);
447
}
448
449
areas.clear();
450
}
451
452
void JoltBody3D::_update_group_filter() {
453
JPH::GroupFilter *group_filter = !exceptions.is_empty() ? JoltGroupFilter::instance : nullptr;
454
455
if (!in_space()) {
456
jolt_settings->mCollisionGroup.SetGroupFilter(group_filter);
457
} else {
458
jolt_body->GetCollisionGroup().SetGroupFilter(group_filter);
459
}
460
}
461
462
void JoltBody3D::_mode_changed() {
463
_update_object_layer();
464
_update_kinematic_transform();
465
_update_mass_properties();
466
_update_sleep_allowed();
467
wake_up();
468
}
469
470
void JoltBody3D::_shapes_committed() {
471
JoltShapedObject3D::_shapes_committed();
472
473
_update_mass_properties();
474
_update_joint_constraints();
475
wake_up();
476
}
477
478
void JoltBody3D::_space_changing() {
479
JoltShapedObject3D::_space_changing();
480
481
sleep_initially = is_sleeping();
482
483
_destroy_joint_constraints();
484
_exit_all_areas();
485
_dequeue_call_queries();
486
}
487
488
void JoltBody3D::_space_changed() {
489
JoltShapedObject3D::_space_changed();
490
491
_update_kinematic_transform();
492
_update_group_filter();
493
_update_joint_constraints();
494
_update_sleep_allowed();
495
_areas_changed();
496
}
497
498
void JoltBody3D::_areas_changed() {
499
_update_damp();
500
wake_up();
501
}
502
503
void JoltBody3D::_joints_changed() {
504
wake_up();
505
}
506
507
void JoltBody3D::_transform_changed() {
508
wake_up();
509
}
510
511
void JoltBody3D::_motion_changed() {
512
wake_up();
513
}
514
515
void JoltBody3D::_exceptions_changed() {
516
_update_group_filter();
517
}
518
519
void JoltBody3D::_axis_lock_changed() {
520
_update_mass_properties();
521
wake_up();
522
}
523
524
void JoltBody3D::_contact_reporting_changed() {
525
_update_possible_kinematic_contacts();
526
_update_sleep_allowed();
527
wake_up();
528
}
529
530
void JoltBody3D::_sleep_allowed_changed() {
531
_update_sleep_allowed();
532
wake_up();
533
}
534
535
JoltBody3D::JoltBody3D() :
536
JoltShapedObject3D(OBJECT_TYPE_BODY),
537
call_queries_element(this) {
538
}
539
540
JoltBody3D::~JoltBody3D() {
541
if (direct_state != nullptr) {
542
memdelete(direct_state);
543
direct_state = nullptr;
544
}
545
}
546
547
void JoltBody3D::set_transform(Transform3D p_transform) {
548
JOLT_ENSURE_SCALE_NOT_ZERO(p_transform, vformat("An invalid transform was passed to physics body '%s'.", to_string()));
549
550
Vector3 new_scale;
551
JoltMath::decompose(p_transform, new_scale);
552
553
// Ideally we would do an exact comparison here, but due to floating-point precision this would be invalidated very often.
554
if (!scale.is_equal_approx(new_scale)) {
555
scale = new_scale;
556
_shapes_changed();
557
}
558
559
if (!in_space()) {
560
jolt_settings->mPosition = to_jolt_r(p_transform.origin);
561
jolt_settings->mRotation = to_jolt(p_transform.basis);
562
} else if (is_kinematic()) {
563
kinematic_transform = p_transform;
564
} else {
565
space->get_body_iface().SetPositionAndRotation(jolt_body->GetID(), to_jolt_r(p_transform.origin), to_jolt(p_transform.basis), JPH::EActivation::DontActivate);
566
}
567
568
_transform_changed();
569
}
570
571
Variant JoltBody3D::get_state(PhysicsServer3D::BodyState p_state) const {
572
switch (p_state) {
573
case PhysicsServer3D::BODY_STATE_TRANSFORM: {
574
return get_transform_scaled();
575
}
576
case PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY: {
577
return get_linear_velocity();
578
}
579
case PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY: {
580
return get_angular_velocity();
581
}
582
case PhysicsServer3D::BODY_STATE_SLEEPING: {
583
return is_sleeping();
584
}
585
case PhysicsServer3D::BODY_STATE_CAN_SLEEP: {
586
return is_sleep_allowed();
587
}
588
default: {
589
ERR_FAIL_V_MSG(Variant(), vformat("Unhandled body state: '%d'. This should not happen. Please report this.", p_state));
590
}
591
}
592
}
593
594
void JoltBody3D::set_state(PhysicsServer3D::BodyState p_state, const Variant &p_value) {
595
switch (p_state) {
596
case PhysicsServer3D::BODY_STATE_TRANSFORM: {
597
set_transform(p_value);
598
} break;
599
case PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY: {
600
set_linear_velocity(p_value);
601
} break;
602
case PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY: {
603
set_angular_velocity(p_value);
604
} break;
605
case PhysicsServer3D::BODY_STATE_SLEEPING: {
606
set_is_sleeping(p_value);
607
} break;
608
case PhysicsServer3D::BODY_STATE_CAN_SLEEP: {
609
set_is_sleep_allowed(p_value);
610
} break;
611
default: {
612
ERR_FAIL_MSG(vformat("Unhandled body state: '%d'. This should not happen. Please report this.", p_state));
613
} break;
614
}
615
}
616
617
Variant JoltBody3D::get_param(PhysicsServer3D::BodyParameter p_param) const {
618
switch (p_param) {
619
case PhysicsServer3D::BODY_PARAM_BOUNCE: {
620
return get_bounce();
621
}
622
case PhysicsServer3D::BODY_PARAM_FRICTION: {
623
return get_friction();
624
}
625
case PhysicsServer3D::BODY_PARAM_MASS: {
626
return get_mass();
627
}
628
case PhysicsServer3D::BODY_PARAM_INERTIA: {
629
return get_inertia();
630
}
631
case PhysicsServer3D::BODY_PARAM_CENTER_OF_MASS: {
632
return get_center_of_mass_custom();
633
}
634
case PhysicsServer3D::BODY_PARAM_GRAVITY_SCALE: {
635
return get_gravity_scale();
636
}
637
case PhysicsServer3D::BODY_PARAM_LINEAR_DAMP_MODE: {
638
return get_linear_damp_mode();
639
}
640
case PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP_MODE: {
641
return get_angular_damp_mode();
642
}
643
case PhysicsServer3D::BODY_PARAM_LINEAR_DAMP: {
644
return get_linear_damp();
645
}
646
case PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP: {
647
return get_angular_damp();
648
}
649
default: {
650
ERR_FAIL_V_MSG(Variant(), vformat("Unhandled body parameter: '%d'. This should not happen. Please report this.", p_param));
651
}
652
}
653
}
654
655
void JoltBody3D::set_param(PhysicsServer3D::BodyParameter p_param, const Variant &p_value) {
656
switch (p_param) {
657
case PhysicsServer3D::BODY_PARAM_BOUNCE: {
658
set_bounce(p_value);
659
} break;
660
case PhysicsServer3D::BODY_PARAM_FRICTION: {
661
set_friction(p_value);
662
} break;
663
case PhysicsServer3D::BODY_PARAM_MASS: {
664
set_mass(p_value);
665
} break;
666
case PhysicsServer3D::BODY_PARAM_INERTIA: {
667
set_inertia(p_value);
668
} break;
669
case PhysicsServer3D::BODY_PARAM_CENTER_OF_MASS: {
670
set_center_of_mass_custom(p_value);
671
} break;
672
case PhysicsServer3D::BODY_PARAM_GRAVITY_SCALE: {
673
set_gravity_scale(p_value);
674
} break;
675
case PhysicsServer3D::BODY_PARAM_LINEAR_DAMP_MODE: {
676
set_linear_damp_mode((DampMode)(int)p_value);
677
} break;
678
case PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP_MODE: {
679
set_angular_damp_mode((DampMode)(int)p_value);
680
} break;
681
case PhysicsServer3D::BODY_PARAM_LINEAR_DAMP: {
682
set_linear_damp(p_value);
683
} break;
684
case PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP: {
685
set_angular_damp(p_value);
686
} break;
687
default: {
688
ERR_FAIL_MSG(vformat("Unhandled body parameter: '%d'. This should not happen. Please report this.", p_param));
689
} break;
690
}
691
}
692
693
void JoltBody3D::set_custom_integrator(bool p_enabled) {
694
if (custom_integrator == p_enabled) {
695
return;
696
}
697
698
custom_integrator = p_enabled;
699
700
if (in_space()) {
701
jolt_body->ResetForce();
702
jolt_body->ResetTorque();
703
}
704
705
_motion_changed();
706
}
707
708
bool JoltBody3D::is_sleeping() const {
709
if (!in_space()) {
710
return sleep_initially;
711
} else {
712
return !jolt_body->IsActive();
713
}
714
}
715
716
bool JoltBody3D::is_sleep_actually_allowed() const {
717
return sleep_allowed && !(is_kinematic() && reports_contacts());
718
}
719
720
void JoltBody3D::set_is_sleeping(bool p_enabled) {
721
if (!in_space()) {
722
sleep_initially = p_enabled;
723
} else {
724
space->set_is_object_sleeping(jolt_body->GetID(), p_enabled);
725
}
726
}
727
728
void JoltBody3D::set_is_sleep_allowed(bool p_enabled) {
729
if (sleep_allowed == p_enabled) {
730
return;
731
}
732
733
sleep_allowed = p_enabled;
734
735
_sleep_allowed_changed();
736
}
737
738
Basis JoltBody3D::get_principal_inertia_axes() const {
739
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()));
740
741
if (unlikely(is_static() || is_kinematic())) {
742
return Basis();
743
}
744
745
return to_godot(jolt_body->GetRotation() * jolt_body->GetMotionPropertiesUnchecked()->GetInertiaRotation());
746
}
747
748
Vector3 JoltBody3D::get_inverse_inertia() const {
749
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()));
750
751
if (unlikely(is_static() || is_kinematic())) {
752
return Vector3();
753
}
754
755
return to_godot(jolt_body->GetMotionPropertiesUnchecked()->GetLocalSpaceInverseInertia().GetDiagonal3());
756
}
757
758
Basis JoltBody3D::get_inverse_inertia_tensor() const {
759
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()));
760
761
if (unlikely(is_static() || is_kinematic())) {
762
return Basis();
763
}
764
765
return to_godot(jolt_body->GetInverseInertia()).basis;
766
}
767
768
void JoltBody3D::set_linear_velocity(const Vector3 &p_velocity) {
769
if (is_static() || is_kinematic()) {
770
linear_surface_velocity = p_velocity;
771
} else {
772
if (!in_space()) {
773
jolt_settings->mLinearVelocity = to_jolt(p_velocity);
774
} else {
775
jolt_body->GetMotionPropertiesUnchecked()->SetLinearVelocityClamped(to_jolt(p_velocity));
776
}
777
}
778
779
_motion_changed();
780
}
781
782
void JoltBody3D::set_angular_velocity(const Vector3 &p_velocity) {
783
if (is_static() || is_kinematic()) {
784
angular_surface_velocity = p_velocity;
785
} else {
786
if (!in_space()) {
787
jolt_settings->mAngularVelocity = to_jolt(p_velocity);
788
} else {
789
jolt_body->GetMotionPropertiesUnchecked()->SetAngularVelocityClamped(to_jolt(p_velocity));
790
}
791
}
792
793
_motion_changed();
794
}
795
796
void JoltBody3D::set_axis_velocity(const Vector3 &p_axis_velocity) {
797
const Vector3 axis = p_axis_velocity.normalized();
798
799
if (!in_space()) {
800
Vector3 linear_velocity = to_godot(jolt_settings->mLinearVelocity);
801
linear_velocity -= axis * axis.dot(linear_velocity);
802
linear_velocity += p_axis_velocity;
803
jolt_settings->mLinearVelocity = to_jolt(linear_velocity);
804
} else {
805
Vector3 linear_velocity = get_linear_velocity();
806
linear_velocity -= axis * axis.dot(linear_velocity);
807
linear_velocity += p_axis_velocity;
808
set_linear_velocity(linear_velocity);
809
}
810
811
_motion_changed();
812
}
813
814
Vector3 JoltBody3D::get_velocity_at_position(const Vector3 &p_position) const {
815
if (unlikely(!in_space())) {
816
return Vector3();
817
}
818
819
const JPH::MotionProperties &motion_properties = *jolt_body->GetMotionPropertiesUnchecked();
820
const Vector3 total_linear_velocity = to_godot(motion_properties.GetLinearVelocity()) + linear_surface_velocity;
821
const Vector3 total_angular_velocity = to_godot(motion_properties.GetAngularVelocity()) + angular_surface_velocity;
822
const Vector3 com_to_pos = p_position - to_godot(jolt_body->GetCenterOfMassPosition());
823
824
return total_linear_velocity + total_angular_velocity.cross(com_to_pos);
825
}
826
827
void JoltBody3D::set_center_of_mass_custom(const Vector3 &p_center_of_mass) {
828
if (custom_center_of_mass && p_center_of_mass == center_of_mass_custom) {
829
return;
830
}
831
832
custom_center_of_mass = true;
833
center_of_mass_custom = p_center_of_mass;
834
835
_shapes_changed();
836
}
837
838
void JoltBody3D::set_max_contacts_reported(int p_count) {
839
ERR_FAIL_INDEX(p_count, MAX_CONTACTS_REPORTED_3D_MAX);
840
841
if (unlikely((int)contacts.size() == p_count)) {
842
return;
843
}
844
845
contacts.resize(p_count);
846
contact_count = MIN(contact_count, p_count);
847
848
const bool use_manifold_reduction = !reports_contacts();
849
850
if (!in_space()) {
851
jolt_settings->mUseManifoldReduction = use_manifold_reduction;
852
} else {
853
space->get_body_iface().SetUseManifoldReduction(jolt_body->GetID(), use_manifold_reduction);
854
}
855
856
_contact_reporting_changed();
857
}
858
859
bool JoltBody3D::reports_all_kinematic_contacts() const {
860
return reports_contacts() && JoltProjectSettings::generate_all_kinematic_contacts;
861
}
862
863
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) {
864
const int max_contacts = get_max_contacts_reported();
865
866
if (max_contacts == 0) {
867
return;
868
}
869
870
Contact *contact = nullptr;
871
872
if (contact_count < max_contacts) {
873
contact = &contacts[contact_count++];
874
} else {
875
Contact *shallowest_contact = &contacts[0];
876
877
for (int i = 1; i < (int)contacts.size(); i++) {
878
Contact &other_contact = contacts[i];
879
if (other_contact.depth < shallowest_contact->depth) {
880
shallowest_contact = &other_contact;
881
}
882
}
883
884
if (shallowest_contact->depth < p_depth) {
885
contact = shallowest_contact;
886
}
887
}
888
889
if (contact != nullptr) {
890
contact->normal = p_normal;
891
contact->position = p_position;
892
contact->collider_position = p_collider_position;
893
contact->velocity = p_velocity;
894
contact->collider_velocity = p_collider_velocity;
895
contact->impulse = p_impulse;
896
contact->collider_id = p_collider->get_instance_id();
897
contact->collider_rid = p_collider->get_rid();
898
contact->shape_index = p_shape_index;
899
contact->collider_shape_index = p_collider_shape_index;
900
}
901
}
902
903
void JoltBody3D::reset_mass_properties() {
904
if (custom_center_of_mass) {
905
custom_center_of_mass = false;
906
center_of_mass_custom.zero();
907
908
_shapes_changed();
909
}
910
911
inertia.zero();
912
913
_update_mass_properties();
914
}
915
916
void JoltBody3D::apply_force(const Vector3 &p_force, const Vector3 &p_position) {
917
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()));
918
919
if (unlikely(!is_rigid()) || custom_integrator || p_force == Vector3()) {
920
return;
921
}
922
923
jolt_body->AddForce(to_jolt(p_force), jolt_body->GetPosition() + to_jolt(p_position));
924
925
_motion_changed();
926
}
927
928
void JoltBody3D::apply_central_force(const Vector3 &p_force) {
929
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()));
930
931
if (unlikely(!is_rigid()) || custom_integrator || p_force == Vector3()) {
932
return;
933
}
934
935
jolt_body->AddForce(to_jolt(p_force));
936
937
_motion_changed();
938
}
939
940
void JoltBody3D::apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position) {
941
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()));
942
943
if (unlikely(!is_rigid()) || p_impulse == Vector3()) {
944
return;
945
}
946
947
jolt_body->AddImpulse(to_jolt(p_impulse), jolt_body->GetPosition() + to_jolt(p_position));
948
949
_motion_changed();
950
}
951
952
void JoltBody3D::apply_central_impulse(const Vector3 &p_impulse) {
953
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()));
954
955
if (unlikely(!is_rigid()) || p_impulse == Vector3()) {
956
return;
957
}
958
959
jolt_body->AddImpulse(to_jolt(p_impulse));
960
961
_motion_changed();
962
}
963
964
void JoltBody3D::apply_torque(const Vector3 &p_torque) {
965
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()));
966
967
if (unlikely(!is_rigid()) || custom_integrator || p_torque == Vector3()) {
968
return;
969
}
970
971
jolt_body->AddTorque(to_jolt(p_torque));
972
973
_motion_changed();
974
}
975
976
void JoltBody3D::apply_torque_impulse(const Vector3 &p_impulse) {
977
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()));
978
979
if (unlikely(!is_rigid()) || p_impulse == Vector3()) {
980
return;
981
}
982
983
jolt_body->AddAngularImpulse(to_jolt(p_impulse));
984
985
_motion_changed();
986
}
987
988
void JoltBody3D::add_constant_central_force(const Vector3 &p_force) {
989
if (p_force == Vector3()) {
990
return;
991
}
992
993
constant_force += p_force;
994
995
_motion_changed();
996
}
997
998
void JoltBody3D::add_constant_force(const Vector3 &p_force, const Vector3 &p_position) {
999
if (p_force == Vector3()) {
1000
return;
1001
}
1002
1003
constant_force += p_force;
1004
constant_torque += (p_position - get_center_of_mass_relative()).cross(p_force);
1005
1006
_motion_changed();
1007
}
1008
1009
void JoltBody3D::add_constant_torque(const Vector3 &p_torque) {
1010
if (p_torque == Vector3()) {
1011
return;
1012
}
1013
1014
constant_torque += p_torque;
1015
1016
_motion_changed();
1017
}
1018
1019
Vector3 JoltBody3D::get_constant_force() const {
1020
return constant_force;
1021
}
1022
1023
void JoltBody3D::set_constant_force(const Vector3 &p_force) {
1024
if (constant_force == p_force) {
1025
return;
1026
}
1027
1028
constant_force = p_force;
1029
1030
_motion_changed();
1031
}
1032
1033
Vector3 JoltBody3D::get_constant_torque() const {
1034
return constant_torque;
1035
}
1036
1037
void JoltBody3D::set_constant_torque(const Vector3 &p_torque) {
1038
if (constant_torque == p_torque) {
1039
return;
1040
}
1041
1042
constant_torque = p_torque;
1043
1044
_motion_changed();
1045
}
1046
1047
void JoltBody3D::add_collision_exception(const RID &p_excepted_body) {
1048
exceptions.push_back(p_excepted_body);
1049
1050
_exceptions_changed();
1051
}
1052
1053
void JoltBody3D::remove_collision_exception(const RID &p_excepted_body) {
1054
exceptions.erase(p_excepted_body);
1055
1056
_exceptions_changed();
1057
}
1058
1059
bool JoltBody3D::has_collision_exception(const RID &p_excepted_body) const {
1060
return exceptions.find(p_excepted_body) >= 0;
1061
}
1062
1063
void JoltBody3D::add_area(JoltArea3D *p_area) {
1064
int i = 0;
1065
for (; i < (int)areas.size(); i++) {
1066
if (p_area->get_priority() > areas[i]->get_priority()) {
1067
break;
1068
}
1069
}
1070
1071
areas.insert(i, p_area);
1072
1073
_areas_changed();
1074
}
1075
1076
void JoltBody3D::remove_area(JoltArea3D *p_area) {
1077
areas.erase(p_area);
1078
1079
_areas_changed();
1080
}
1081
1082
void JoltBody3D::add_joint(JoltJoint3D *p_joint) {
1083
joints.push_back(p_joint);
1084
1085
_joints_changed();
1086
}
1087
1088
void JoltBody3D::remove_joint(JoltJoint3D *p_joint) {
1089
joints.erase(p_joint);
1090
1091
_joints_changed();
1092
}
1093
1094
void JoltBody3D::call_queries() {
1095
if (custom_integration_callback.is_valid()) {
1096
const Variant direct_state_variant = get_direct_state();
1097
const Variant *args[2] = { &direct_state_variant, &custom_integration_userdata };
1098
const int argc = custom_integration_userdata.get_type() != Variant::NIL ? 2 : 1;
1099
1100
Callable::CallError ce;
1101
Variant ret;
1102
custom_integration_callback.callp(args, argc, ret, ce);
1103
1104
if (unlikely(ce.error != Callable::CallError::CALL_OK)) {
1105
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)));
1106
}
1107
}
1108
1109
if (state_sync_callback.is_valid()) {
1110
const Variant direct_state_variant = get_direct_state();
1111
const Variant *args[1] = { &direct_state_variant };
1112
1113
Callable::CallError ce;
1114
Variant ret;
1115
state_sync_callback.callp(args, 1, ret, ce);
1116
1117
if (unlikely(ce.error != Callable::CallError::CALL_OK)) {
1118
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)));
1119
}
1120
}
1121
}
1122
1123
void JoltBody3D::pre_step(float p_step, JPH::Body &p_jolt_body) {
1124
JoltObject3D::pre_step(p_step, p_jolt_body);
1125
1126
switch (mode) {
1127
case PhysicsServer3D::BODY_MODE_STATIC: {
1128
// Will never happen.
1129
} break;
1130
case PhysicsServer3D::BODY_MODE_RIGID:
1131
case PhysicsServer3D::BODY_MODE_RIGID_LINEAR: {
1132
_integrate_forces(p_step, p_jolt_body);
1133
} break;
1134
case PhysicsServer3D::BODY_MODE_KINEMATIC: {
1135
_update_gravity(p_jolt_body);
1136
_move_kinematic(p_step, p_jolt_body);
1137
} break;
1138
}
1139
1140
if (_should_call_queries()) {
1141
_enqueue_call_queries();
1142
}
1143
1144
contact_count = 0;
1145
}
1146
1147
JoltPhysicsDirectBodyState3D *JoltBody3D::get_direct_state() {
1148
if (direct_state == nullptr) {
1149
direct_state = memnew(JoltPhysicsDirectBodyState3D(this));
1150
}
1151
1152
return direct_state;
1153
}
1154
1155
void JoltBody3D::set_mode(PhysicsServer3D::BodyMode p_mode) {
1156
if (p_mode == mode) {
1157
return;
1158
}
1159
1160
mode = p_mode;
1161
1162
if (!in_space()) {
1163
_mode_changed();
1164
return;
1165
}
1166
1167
const JPH::EMotionType motion_type = _get_motion_type();
1168
1169
if (motion_type == JPH::EMotionType::Static) {
1170
put_to_sleep();
1171
}
1172
1173
jolt_body->SetMotionType(motion_type);
1174
1175
if (motion_type != JPH::EMotionType::Static) {
1176
wake_up();
1177
}
1178
1179
if (motion_type == JPH::EMotionType::Kinematic) {
1180
jolt_body->SetLinearVelocity(JPH::Vec3::sZero());
1181
jolt_body->SetAngularVelocity(JPH::Vec3::sZero());
1182
}
1183
1184
linear_surface_velocity = Vector3();
1185
angular_surface_velocity = Vector3();
1186
1187
_mode_changed();
1188
}
1189
1190
bool JoltBody3D::is_ccd_enabled() const {
1191
if (!in_space()) {
1192
return jolt_settings->mMotionQuality == JPH::EMotionQuality::LinearCast;
1193
} else {
1194
return !is_static() && jolt_body->GetMotionProperties()->GetMotionQuality() == JPH::EMotionQuality::LinearCast;
1195
}
1196
}
1197
1198
void JoltBody3D::set_ccd_enabled(bool p_enabled) {
1199
const JPH::EMotionQuality motion_quality = p_enabled ? JPH::EMotionQuality::LinearCast : JPH::EMotionQuality::Discrete;
1200
1201
if (!in_space()) {
1202
jolt_settings->mMotionQuality = motion_quality;
1203
} else {
1204
space->get_body_iface().SetMotionQuality(jolt_body->GetID(), motion_quality);
1205
}
1206
}
1207
1208
void JoltBody3D::set_mass(float p_mass) {
1209
if (p_mass != mass) {
1210
mass = p_mass;
1211
_update_mass_properties();
1212
}
1213
}
1214
1215
void JoltBody3D::set_inertia(const Vector3 &p_inertia) {
1216
if (p_inertia != inertia) {
1217
inertia = p_inertia;
1218
_update_mass_properties();
1219
}
1220
}
1221
1222
float JoltBody3D::get_bounce() const {
1223
if (!in_space()) {
1224
return jolt_settings->mRestitution;
1225
} else {
1226
return jolt_body->GetRestitution();
1227
}
1228
}
1229
1230
void JoltBody3D::set_bounce(float p_bounce) {
1231
if (!in_space()) {
1232
jolt_settings->mRestitution = p_bounce;
1233
} else {
1234
jolt_body->SetRestitution(p_bounce);
1235
}
1236
}
1237
1238
float JoltBody3D::get_friction() const {
1239
if (!in_space()) {
1240
return jolt_settings->mFriction;
1241
} else {
1242
return jolt_body->GetFriction();
1243
}
1244
}
1245
1246
void JoltBody3D::set_friction(float p_friction) {
1247
if (!in_space()) {
1248
jolt_settings->mFriction = p_friction;
1249
} else {
1250
jolt_body->SetFriction(p_friction);
1251
}
1252
}
1253
1254
void JoltBody3D::set_gravity_scale(float p_scale) {
1255
if (gravity_scale == p_scale) {
1256
return;
1257
}
1258
1259
gravity_scale = p_scale;
1260
1261
_motion_changed();
1262
}
1263
1264
void JoltBody3D::set_linear_damp(float p_damp) {
1265
p_damp = MAX(0.0f, p_damp);
1266
1267
if (p_damp == linear_damp) {
1268
return;
1269
}
1270
1271
linear_damp = p_damp;
1272
1273
_update_damp();
1274
}
1275
1276
void JoltBody3D::set_angular_damp(float p_damp) {
1277
p_damp = MAX(0.0f, p_damp);
1278
1279
if (p_damp == angular_damp) {
1280
return;
1281
}
1282
1283
angular_damp = p_damp;
1284
1285
_update_damp();
1286
}
1287
1288
void JoltBody3D::set_linear_damp_mode(DampMode p_mode) {
1289
if (p_mode == linear_damp_mode) {
1290
return;
1291
}
1292
1293
linear_damp_mode = p_mode;
1294
1295
_update_damp();
1296
}
1297
1298
void JoltBody3D::set_angular_damp_mode(DampMode p_mode) {
1299
if (p_mode == angular_damp_mode) {
1300
return;
1301
}
1302
1303
angular_damp_mode = p_mode;
1304
1305
_update_damp();
1306
}
1307
1308
bool JoltBody3D::is_axis_locked(PhysicsServer3D::BodyAxis p_axis) const {
1309
return (locked_axes & (uint32_t)p_axis) != 0;
1310
}
1311
1312
void JoltBody3D::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_enabled) {
1313
const uint32_t previous_locked_axes = locked_axes;
1314
1315
if (p_enabled) {
1316
locked_axes |= (uint32_t)p_axis;
1317
} else {
1318
locked_axes &= ~(uint32_t)p_axis;
1319
}
1320
1321
if (previous_locked_axes != locked_axes) {
1322
_axis_lock_changed();
1323
}
1324
}
1325
1326
bool JoltBody3D::can_interact_with(const JoltBody3D &p_other) const {
1327
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);
1328
}
1329
1330
bool JoltBody3D::can_interact_with(const JoltSoftBody3D &p_other) const {
1331
return p_other.can_interact_with(*this);
1332
}
1333
1334
bool JoltBody3D::can_interact_with(const JoltArea3D &p_other) const {
1335
return p_other.can_interact_with(*this);
1336
}
1337
1338