Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/modules/jolt_physics/spaces/jolt_space_3d.cpp
20969 views
1
/**************************************************************************/
2
/* jolt_space_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_space_3d.h"
32
33
#include "../joints/jolt_joint_3d.h"
34
#include "../jolt_physics_server_3d.h"
35
#include "../jolt_project_settings.h"
36
#include "../misc/jolt_stream_wrappers.h"
37
#include "../objects/jolt_area_3d.h"
38
#include "../objects/jolt_body_3d.h"
39
#include "../shapes/jolt_custom_shape_type.h"
40
#include "../shapes/jolt_shape_3d.h"
41
#include "jolt_body_activation_listener_3d.h"
42
#include "jolt_contact_listener_3d.h"
43
#include "jolt_layers.h"
44
#include "jolt_physics_direct_space_state_3d.h"
45
#include "jolt_temp_allocator.h"
46
47
#include "core/io/file_access.h"
48
#include "core/os/time.h"
49
#include "core/string/print_string.h"
50
#include "core/variant/variant_utility.h"
51
52
#include "Jolt/Physics/Collision/CollideShapeVsShapePerLeaf.h"
53
#include "Jolt/Physics/Collision/CollisionCollectorImpl.h"
54
#include "Jolt/Physics/PhysicsScene.h"
55
56
namespace {
57
58
constexpr double SPACE_DEFAULT_CONTACT_RECYCLE_RADIUS = 0.01;
59
constexpr double SPACE_DEFAULT_CONTACT_MAX_SEPARATION = 0.05;
60
constexpr double SPACE_DEFAULT_CONTACT_MAX_ALLOWED_PENETRATION = 0.01;
61
constexpr double SPACE_DEFAULT_CONTACT_DEFAULT_BIAS = 0.8;
62
constexpr double SPACE_DEFAULT_SLEEP_THRESHOLD_LINEAR = 0.1;
63
constexpr double SPACE_DEFAULT_SLEEP_THRESHOLD_ANGULAR = 8.0 * Math::PI / 180;
64
constexpr double SPACE_DEFAULT_SOLVER_ITERATIONS = 8;
65
66
} // namespace
67
68
void JoltSpace3D::_pre_step(float p_step) {
69
flush_pending_objects();
70
71
while (needs_optimization_list.first()) {
72
JoltShapedObject3D *object = needs_optimization_list.first()->self();
73
needs_optimization_list.remove(needs_optimization_list.first());
74
object->commit_shapes(true);
75
}
76
77
contact_listener->pre_step();
78
79
const JPH::BodyLockInterface &lock_iface = get_lock_iface();
80
const JPH::BodyID *active_rigid_bodies = physics_system->GetActiveBodiesUnsafe(JPH::EBodyType::RigidBody);
81
const JPH::uint32 active_rigid_body_count = physics_system->GetNumActiveBodies(JPH::EBodyType::RigidBody);
82
83
for (JPH::uint32 i = 0; i < active_rigid_body_count; i++) {
84
JPH::Body *jolt_body = lock_iface.TryGetBody(active_rigid_bodies[i]);
85
JoltObject3D *object = reinterpret_cast<JoltObject3D *>(jolt_body->GetUserData());
86
object->pre_step(p_step, *jolt_body);
87
}
88
}
89
90
void JoltSpace3D::_post_step(float p_step) {
91
contact_listener->post_step();
92
93
while (shapes_changed_list.first()) {
94
JoltShapedObject3D *object = shapes_changed_list.first()->self();
95
shapes_changed_list.remove(shapes_changed_list.first());
96
object->clear_previous_shape();
97
}
98
}
99
100
JoltSpace3D::JoltSpace3D(JPH::JobSystem *p_job_system) :
101
job_system(p_job_system),
102
temp_allocator(new JoltTempAllocator()),
103
layers(new JoltLayers()),
104
contact_listener(new JoltContactListener3D(this)),
105
body_activation_listener(new JoltBodyActivationListener3D()),
106
physics_system(new JPH::PhysicsSystem()) {
107
physics_system->Init((JPH::uint)JoltProjectSettings::max_bodies, 0, (JPH::uint)JoltProjectSettings::max_body_pairs, (JPH::uint)JoltProjectSettings::max_contact_constraints, *layers, *layers, *layers);
108
109
JPH::PhysicsSettings settings;
110
settings.mBaumgarte = JoltProjectSettings::baumgarte_stabilization_factor;
111
settings.mSpeculativeContactDistance = JoltProjectSettings::speculative_contact_distance;
112
settings.mPenetrationSlop = JoltProjectSettings::penetration_slop;
113
settings.mLinearCastThreshold = JoltProjectSettings::ccd_movement_threshold;
114
settings.mLinearCastMaxPenetration = JoltProjectSettings::ccd_max_penetration;
115
settings.mBodyPairCacheMaxDeltaPositionSq = JoltProjectSettings::body_pair_cache_distance_sq;
116
settings.mBodyPairCacheCosMaxDeltaRotationDiv2 = JoltProjectSettings::body_pair_cache_angle_cos_div2;
117
settings.mNumVelocitySteps = (JPH::uint)JoltProjectSettings::simulation_velocity_steps;
118
settings.mNumPositionSteps = (JPH::uint)JoltProjectSettings::simulation_position_steps;
119
settings.mMinVelocityForRestitution = JoltProjectSettings::bounce_velocity_threshold;
120
settings.mTimeBeforeSleep = JoltProjectSettings::sleep_time_threshold;
121
settings.mPointVelocitySleepThreshold = JoltProjectSettings::sleep_velocity_threshold;
122
settings.mUseBodyPairContactCache = JoltProjectSettings::body_pair_contact_cache_enabled;
123
settings.mAllowSleeping = JoltProjectSettings::sleep_allowed;
124
125
physics_system->SetPhysicsSettings(settings);
126
physics_system->SetGravity(JPH::Vec3::sZero());
127
physics_system->SetContactListener(contact_listener);
128
physics_system->SetSoftBodyContactListener(contact_listener);
129
130
physics_system->SetSimCollideBodyVsBody([](const JPH::Body &p_body1, const JPH::Body &p_body2, JPH::Mat44Arg p_transform_com1, JPH::Mat44Arg p_transform_com2, JPH::CollideShapeSettings &p_collide_shape_settings, JPH::CollideShapeCollector &p_collector, const JPH::ShapeFilter &p_shape_filter) {
131
if (p_body1.IsSensor() || p_body2.IsSensor()) {
132
JPH::CollideShapeSettings new_collide_shape_settings = p_collide_shape_settings;
133
// Since we're breaking the sensor down into leaf shapes we'll end up stripping away our `JoltCustomDoubleSidedShape` decorator shape and thus any back-face collision, so we simply force-enable it like this rather than going through the trouble of reapplying the decorator.
134
new_collide_shape_settings.mBackFaceMode = JPH::EBackFaceMode::CollideWithBackFaces;
135
JPH::SubShapeIDCreator part1, part2;
136
JPH::CollideShapeVsShapePerLeaf<JPH::AnyHitCollisionCollector<JPH::CollideShapeCollector>>(p_body1.GetShape(), p_body2.GetShape(), JPH::Vec3::sOne(), JPH::Vec3::sOne(), p_transform_com1, p_transform_com2, part1, part2, new_collide_shape_settings, p_collector, p_shape_filter);
137
} else {
138
JPH::PhysicsSystem::sDefaultSimCollideBodyVsBody(p_body1, p_body2, p_transform_com1, p_transform_com2, p_collide_shape_settings, p_collector, p_shape_filter);
139
}
140
});
141
142
physics_system->SetCombineFriction([](const JPH::Body &p_body1, const JPH::SubShapeID &p_sub_shape_id1, const JPH::Body &p_body2, const JPH::SubShapeID &p_sub_shape_id2) {
143
return Math::abs(MIN(p_body1.GetFriction(), p_body2.GetFriction()));
144
});
145
146
physics_system->SetCombineRestitution([](const JPH::Body &p_body1, const JPH::SubShapeID &p_sub_shape_id1, const JPH::Body &p_body2, const JPH::SubShapeID &p_sub_shape_id2) {
147
return CLAMP(p_body1.GetRestitution() + p_body2.GetRestitution(), 0.0f, 1.0f);
148
});
149
}
150
151
JoltSpace3D::~JoltSpace3D() {
152
if (direct_state != nullptr) {
153
memdelete(direct_state);
154
direct_state = nullptr;
155
}
156
157
if (physics_system != nullptr) {
158
delete physics_system;
159
physics_system = nullptr;
160
}
161
162
if (body_activation_listener != nullptr) {
163
delete body_activation_listener;
164
body_activation_listener = nullptr;
165
}
166
167
if (contact_listener != nullptr) {
168
delete contact_listener;
169
contact_listener = nullptr;
170
}
171
172
if (layers != nullptr) {
173
delete layers;
174
layers = nullptr;
175
}
176
177
if (temp_allocator != nullptr) {
178
delete temp_allocator;
179
temp_allocator = nullptr;
180
}
181
}
182
183
void JoltSpace3D::step(float p_step) {
184
stepping = true;
185
last_step = p_step;
186
187
_pre_step(p_step);
188
189
physics_system->SetBodyActivationListener(body_activation_listener);
190
191
const JPH::EPhysicsUpdateError update_error = physics_system->Update(p_step, 1, temp_allocator, job_system);
192
193
if ((update_error & JPH::EPhysicsUpdateError::ManifoldCacheFull) != JPH::EPhysicsUpdateError::None) {
194
WARN_PRINT_ONCE(vformat("Jolt Physics manifold cache exceeded capacity and contacts were ignored. "
195
"Consider increasing maximum number of contact constraints in project settings. "
196
"Maximum number of contact constraints is currently set to %d.",
197
JoltProjectSettings::max_contact_constraints));
198
}
199
200
if ((update_error & JPH::EPhysicsUpdateError::BodyPairCacheFull) != JPH::EPhysicsUpdateError::None) {
201
WARN_PRINT_ONCE(vformat("Jolt Physics body pair cache exceeded capacity and contacts were ignored. "
202
"Consider increasing maximum number of body pairs in project settings. "
203
"Maximum number of body pairs is currently set to %d.",
204
JoltProjectSettings::max_body_pairs));
205
}
206
207
if ((update_error & JPH::EPhysicsUpdateError::ContactConstraintsFull) != JPH::EPhysicsUpdateError::None) {
208
WARN_PRINT_ONCE(vformat("Jolt Physics contact constraint buffer exceeded capacity and contacts were ignored. "
209
"Consider increasing maximum number of contact constraints in project settings. "
210
"Maximum number of contact constraints is currently set to %d.",
211
JoltProjectSettings::max_contact_constraints));
212
}
213
214
// We only want a listener during the step, as it will otherwise be called when pending bodies are flushed, which causes issues (e.g. GH-115322).
215
physics_system->SetBodyActivationListener(nullptr);
216
217
_post_step(p_step);
218
219
stepping = false;
220
}
221
222
void JoltSpace3D::call_queries() {
223
while (body_call_queries_list.first()) {
224
JoltBody3D *body = body_call_queries_list.first()->self();
225
body_call_queries_list.remove(body_call_queries_list.first());
226
body->call_queries();
227
}
228
229
while (area_call_queries_list.first()) {
230
JoltArea3D *body = area_call_queries_list.first()->self();
231
area_call_queries_list.remove(area_call_queries_list.first());
232
body->call_queries();
233
}
234
}
235
236
double JoltSpace3D::get_param(PhysicsServer3D::SpaceParameter p_param) const {
237
switch (p_param) {
238
case PhysicsServer3D::SPACE_PARAM_CONTACT_RECYCLE_RADIUS: {
239
return SPACE_DEFAULT_CONTACT_RECYCLE_RADIUS;
240
}
241
case PhysicsServer3D::SPACE_PARAM_CONTACT_MAX_SEPARATION: {
242
return SPACE_DEFAULT_CONTACT_MAX_SEPARATION;
243
}
244
case PhysicsServer3D::SPACE_PARAM_CONTACT_MAX_ALLOWED_PENETRATION: {
245
return SPACE_DEFAULT_CONTACT_MAX_ALLOWED_PENETRATION;
246
}
247
case PhysicsServer3D::SPACE_PARAM_CONTACT_DEFAULT_BIAS: {
248
return SPACE_DEFAULT_CONTACT_DEFAULT_BIAS;
249
}
250
case PhysicsServer3D::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD: {
251
return SPACE_DEFAULT_SLEEP_THRESHOLD_LINEAR;
252
}
253
case PhysicsServer3D::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD: {
254
return SPACE_DEFAULT_SLEEP_THRESHOLD_ANGULAR;
255
}
256
case PhysicsServer3D::SPACE_PARAM_BODY_TIME_TO_SLEEP: {
257
return JoltProjectSettings::sleep_time_threshold;
258
}
259
case PhysicsServer3D::SPACE_PARAM_SOLVER_ITERATIONS: {
260
return SPACE_DEFAULT_SOLVER_ITERATIONS;
261
}
262
default: {
263
ERR_FAIL_V_MSG(0.0, vformat("Unhandled space parameter: '%d'. This should not happen. Please report this.", p_param));
264
}
265
}
266
}
267
268
void JoltSpace3D::set_param(PhysicsServer3D::SpaceParameter p_param, double p_value) {
269
switch (p_param) {
270
case PhysicsServer3D::SPACE_PARAM_CONTACT_RECYCLE_RADIUS: {
271
WARN_PRINT("Space-specific contact recycle radius is not supported when using Jolt Physics. Any such value will be ignored.");
272
} break;
273
case PhysicsServer3D::SPACE_PARAM_CONTACT_MAX_SEPARATION: {
274
WARN_PRINT("Space-specific contact max separation is not supported when using Jolt Physics. Any such value will be ignored.");
275
} break;
276
case PhysicsServer3D::SPACE_PARAM_CONTACT_MAX_ALLOWED_PENETRATION: {
277
WARN_PRINT("Space-specific contact max allowed penetration is not supported when using Jolt Physics. Any such value will be ignored.");
278
} break;
279
case PhysicsServer3D::SPACE_PARAM_CONTACT_DEFAULT_BIAS: {
280
WARN_PRINT("Space-specific contact default bias is not supported when using Jolt Physics. Any such value will be ignored.");
281
} break;
282
case PhysicsServer3D::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD: {
283
WARN_PRINT("Space-specific linear velocity sleep threshold is not supported when using Jolt Physics. Any such value will be ignored.");
284
} break;
285
case PhysicsServer3D::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD: {
286
WARN_PRINT("Space-specific angular velocity sleep threshold is not supported when using Jolt Physics. Any such value will be ignored.");
287
} break;
288
case PhysicsServer3D::SPACE_PARAM_BODY_TIME_TO_SLEEP: {
289
WARN_PRINT("Space-specific body sleep time is not supported when using Jolt Physics. Any such value will be ignored.");
290
} break;
291
case PhysicsServer3D::SPACE_PARAM_SOLVER_ITERATIONS: {
292
WARN_PRINT("Space-specific solver iterations is not supported when using Jolt Physics. Any such value will be ignored.");
293
} break;
294
default: {
295
ERR_FAIL_MSG(vformat("Unhandled space parameter: '%d'. This should not happen. Please report this.", p_param));
296
} break;
297
}
298
}
299
300
JPH::BodyInterface &JoltSpace3D::get_body_iface() {
301
return physics_system->GetBodyInterfaceNoLock();
302
}
303
304
const JPH::BodyInterface &JoltSpace3D::get_body_iface() const {
305
return physics_system->GetBodyInterfaceNoLock();
306
}
307
308
const JPH::BodyLockInterface &JoltSpace3D::get_lock_iface() const {
309
return physics_system->GetBodyLockInterfaceNoLock();
310
}
311
312
const JPH::BroadPhaseQuery &JoltSpace3D::get_broad_phase_query() const {
313
return physics_system->GetBroadPhaseQuery();
314
}
315
316
const JPH::NarrowPhaseQuery &JoltSpace3D::get_narrow_phase_query() const {
317
return physics_system->GetNarrowPhaseQueryNoLock();
318
}
319
320
JPH::ObjectLayer JoltSpace3D::map_to_object_layer(JPH::BroadPhaseLayer p_broad_phase_layer, uint32_t p_collision_layer, uint32_t p_collision_mask) {
321
return layers->to_object_layer(p_broad_phase_layer, p_collision_layer, p_collision_mask);
322
}
323
324
void JoltSpace3D::map_from_object_layer(JPH::ObjectLayer p_object_layer, JPH::BroadPhaseLayer &r_broad_phase_layer, uint32_t &r_collision_layer, uint32_t &r_collision_mask) const {
325
layers->from_object_layer(p_object_layer, r_broad_phase_layer, r_collision_layer, r_collision_mask);
326
}
327
328
JPH::Body *JoltSpace3D::try_get_jolt_body(const JPH::BodyID &p_body_id) const {
329
return get_lock_iface().TryGetBody(p_body_id);
330
}
331
332
JoltObject3D *JoltSpace3D::try_get_object(const JPH::BodyID &p_body_id) const {
333
const JPH::Body *jolt_body = try_get_jolt_body(p_body_id);
334
if (unlikely(jolt_body == nullptr)) {
335
return nullptr;
336
}
337
338
return reinterpret_cast<JoltObject3D *>(jolt_body->GetUserData());
339
}
340
341
JoltShapedObject3D *JoltSpace3D::try_get_shaped(const JPH::BodyID &p_body_id) const {
342
JoltObject3D *object = try_get_object(p_body_id);
343
if (unlikely(object == nullptr)) {
344
return nullptr;
345
}
346
347
return object->as_shaped();
348
}
349
350
JoltBody3D *JoltSpace3D::try_get_body(const JPH::BodyID &p_body_id) const {
351
JoltObject3D *object = try_get_object(p_body_id);
352
if (unlikely(object == nullptr)) {
353
return nullptr;
354
}
355
356
return object->as_body();
357
}
358
359
JoltArea3D *JoltSpace3D::try_get_area(const JPH::BodyID &p_body_id) const {
360
JoltObject3D *object = try_get_object(p_body_id);
361
if (unlikely(object == nullptr)) {
362
return nullptr;
363
}
364
365
return object->as_area();
366
}
367
368
JoltSoftBody3D *JoltSpace3D::try_get_soft_body(const JPH::BodyID &p_body_id) const {
369
JoltObject3D *object = try_get_object(p_body_id);
370
if (unlikely(object == nullptr)) {
371
return nullptr;
372
}
373
374
return object->as_soft_body();
375
}
376
377
JoltPhysicsDirectSpaceState3D *JoltSpace3D::get_direct_state() {
378
if (direct_state == nullptr) {
379
direct_state = memnew(JoltPhysicsDirectSpaceState3D(this));
380
}
381
382
return direct_state;
383
}
384
385
void JoltSpace3D::set_default_area(JoltArea3D *p_area) {
386
if (default_area == p_area) {
387
return;
388
}
389
390
if (default_area != nullptr) {
391
default_area->set_default_area(false);
392
}
393
394
default_area = p_area;
395
396
if (default_area != nullptr) {
397
default_area->set_default_area(true);
398
}
399
}
400
401
JPH::Body *JoltSpace3D::add_object(const JoltObject3D &p_object, const JPH::BodyCreationSettings &p_settings, bool p_sleeping) {
402
JPH::BodyInterface &body_iface = get_body_iface();
403
JPH::Body *jolt_body = body_iface.CreateBody(p_settings);
404
if (unlikely(jolt_body == nullptr)) {
405
ERR_PRINT_ONCE(vformat("Failed to create underlying Jolt Physics body for '%s'. "
406
"Consider increasing maximum number of bodies in project settings. "
407
"Maximum number of bodies is currently set to %d.",
408
p_object.to_string(), JoltProjectSettings::max_bodies));
409
410
return nullptr;
411
}
412
413
if (p_sleeping) {
414
pending_objects_sleeping.push_back(jolt_body->GetID());
415
} else {
416
pending_objects_awake.push_back(jolt_body->GetID());
417
}
418
419
return jolt_body;
420
}
421
422
JPH::Body *JoltSpace3D::add_object(const JoltObject3D &p_object, const JPH::SoftBodyCreationSettings &p_settings, bool p_sleeping) {
423
JPH::BodyInterface &body_iface = get_body_iface();
424
JPH::Body *jolt_body = body_iface.CreateSoftBody(p_settings);
425
if (unlikely(jolt_body == nullptr)) {
426
ERR_PRINT_ONCE(vformat("Failed to create underlying Jolt Physics body for '%s'. "
427
"Consider increasing maximum number of bodies in project settings. "
428
"Maximum number of bodies is currently set to %d.",
429
p_object.to_string(), JoltProjectSettings::max_bodies));
430
431
return nullptr;
432
}
433
434
if (p_sleeping) {
435
pending_objects_sleeping.push_back(jolt_body->GetID());
436
} else {
437
pending_objects_awake.push_back(jolt_body->GetID());
438
}
439
440
return jolt_body;
441
}
442
443
void JoltSpace3D::remove_object(const JPH::BodyID &p_jolt_id) {
444
JPH::BodyInterface &body_iface = get_body_iface();
445
446
if (!pending_objects_sleeping.erase_unordered(p_jolt_id) && !pending_objects_awake.erase_unordered(p_jolt_id)) {
447
body_iface.RemoveBody(p_jolt_id);
448
}
449
450
body_iface.DestroyBody(p_jolt_id);
451
452
// If we're never going to step this space, like in the editor viewport, we need to manually clean up Jolt's broad phase instead, otherwise performance can degrade when doing things like switching scenes.
453
// We'll never actually have zero bodies in any space though, since we always have the default area, so we check if there's one or fewer left instead.
454
if (!JoltPhysicsServer3D::get_singleton()->is_active() && physics_system->GetNumBodies() <= 1) {
455
physics_system->OptimizeBroadPhase();
456
}
457
}
458
459
void JoltSpace3D::flush_pending_objects() {
460
if (pending_objects_sleeping.is_empty() && pending_objects_awake.is_empty()) {
461
return;
462
}
463
464
// We only care about locking within this method, because it's called when performing queries, which aren't covered by `PhysicsServer3DWrapMT`.
465
MutexLock pending_objects_lock(pending_objects_mutex);
466
467
JPH::BodyInterface &body_iface = get_body_iface();
468
469
if (!pending_objects_sleeping.is_empty()) {
470
JPH::BodyInterface::AddState add_state = body_iface.AddBodiesPrepare(pending_objects_sleeping.ptr(), pending_objects_sleeping.size());
471
body_iface.AddBodiesFinalize(pending_objects_sleeping.ptr(), pending_objects_sleeping.size(), add_state, JPH::EActivation::DontActivate);
472
pending_objects_sleeping.reset();
473
}
474
475
if (!pending_objects_awake.is_empty()) {
476
JPH::BodyInterface::AddState add_state = body_iface.AddBodiesPrepare(pending_objects_awake.ptr(), pending_objects_awake.size());
477
body_iface.AddBodiesFinalize(pending_objects_awake.ptr(), pending_objects_awake.size(), add_state, JPH::EActivation::Activate);
478
pending_objects_awake.reset();
479
}
480
}
481
482
void JoltSpace3D::set_is_object_sleeping(const JPH::BodyID &p_jolt_id, bool p_enable) {
483
if (p_enable) {
484
if (pending_objects_awake.erase_unordered(p_jolt_id)) {
485
pending_objects_sleeping.push_back(p_jolt_id);
486
} else if (pending_objects_sleeping.has(p_jolt_id)) {
487
// Do nothing.
488
} else {
489
get_body_iface().DeactivateBody(p_jolt_id);
490
}
491
} else {
492
if (pending_objects_sleeping.erase_unordered(p_jolt_id)) {
493
pending_objects_awake.push_back(p_jolt_id);
494
} else if (pending_objects_awake.has(p_jolt_id)) {
495
// Do nothing.
496
} else {
497
get_body_iface().ActivateBody(p_jolt_id);
498
}
499
}
500
}
501
502
void JoltSpace3D::enqueue_call_queries(SelfList<JoltBody3D> *p_body) {
503
// This method will be called from the body activation listener on multiple threads during the simulation step.
504
MutexLock body_call_queries_lock(body_call_queries_mutex);
505
506
if (!p_body->in_list()) {
507
body_call_queries_list.add(p_body);
508
}
509
}
510
511
void JoltSpace3D::enqueue_call_queries(SelfList<JoltArea3D> *p_area) {
512
if (!p_area->in_list()) {
513
area_call_queries_list.add(p_area);
514
}
515
}
516
517
void JoltSpace3D::dequeue_call_queries(SelfList<JoltBody3D> *p_body) {
518
if (p_body->in_list()) {
519
body_call_queries_list.remove(p_body);
520
}
521
}
522
523
void JoltSpace3D::dequeue_call_queries(SelfList<JoltArea3D> *p_area) {
524
if (p_area->in_list()) {
525
area_call_queries_list.remove(p_area);
526
}
527
}
528
529
void JoltSpace3D::enqueue_shapes_changed(SelfList<JoltShapedObject3D> *p_object) {
530
if (!p_object->in_list()) {
531
shapes_changed_list.add(p_object);
532
}
533
}
534
535
void JoltSpace3D::dequeue_shapes_changed(SelfList<JoltShapedObject3D> *p_object) {
536
if (p_object->in_list()) {
537
shapes_changed_list.remove(p_object);
538
}
539
}
540
541
void JoltSpace3D::enqueue_needs_optimization(SelfList<JoltShapedObject3D> *p_object) {
542
if (!p_object->in_list()) {
543
needs_optimization_list.add(p_object);
544
}
545
}
546
547
void JoltSpace3D::dequeue_needs_optimization(SelfList<JoltShapedObject3D> *p_object) {
548
if (p_object->in_list()) {
549
needs_optimization_list.remove(p_object);
550
}
551
}
552
553
void JoltSpace3D::add_joint(JPH::Constraint *p_jolt_ref) {
554
physics_system->AddConstraint(p_jolt_ref);
555
}
556
557
void JoltSpace3D::add_joint(JoltJoint3D *p_joint) {
558
add_joint(p_joint->get_jolt_ref());
559
}
560
561
void JoltSpace3D::remove_joint(JPH::Constraint *p_jolt_ref) {
562
physics_system->RemoveConstraint(p_jolt_ref);
563
}
564
565
void JoltSpace3D::remove_joint(JoltJoint3D *p_joint) {
566
remove_joint(p_joint->get_jolt_ref());
567
}
568
569
#ifdef DEBUG_ENABLED
570
571
void JoltSpace3D::dump_debug_snapshot(const String &p_dir) {
572
const Dictionary datetime = Time::get_singleton()->get_datetime_dict_from_system();
573
const String datetime_str = vformat("%04d-%02d-%02d_%02d-%02d-%02d", datetime["year"], datetime["month"], datetime["day"], datetime["hour"], datetime["minute"], datetime["second"]);
574
const String path = p_dir + vformat("/jolt_snapshot_%s_%d.bin", datetime_str, rid.get_id());
575
576
Ref<FileAccess> file_access = FileAccess::open(path, FileAccess::ModeFlags::WRITE);
577
ERR_FAIL_COND_MSG(file_access.is_null(), vformat("Failed to open '%s' for writing when saving snapshot of physics space with RID '%d'.", path, rid.get_id()));
578
579
JPH::PhysicsScene physics_scene;
580
physics_scene.FromPhysicsSystem(physics_system);
581
582
for (JPH::BodyCreationSettings &settings : physics_scene.GetBodies()) {
583
const JoltObject3D *object = reinterpret_cast<const JoltObject3D *>(settings.mUserData);
584
585
if (const JoltBody3D *body = object->as_body()) {
586
// Since we do our own integration of gravity and damping, while leaving Jolt's own values at zero, we need to transfer over the correct values.
587
settings.mGravityFactor = body->get_gravity_scale();
588
settings.mLinearDamping = body->get_total_linear_damp();
589
settings.mAngularDamping = body->get_total_angular_damp();
590
}
591
592
settings.SetShape(JoltShape3D::without_custom_shapes(settings.GetShape()));
593
}
594
595
JoltStreamOutputWrapper output_stream(file_access);
596
physics_scene.SaveBinaryState(output_stream, true, false);
597
598
ERR_FAIL_COND_MSG(file_access->get_error() != OK, vformat("Writing snapshot of physics space with RID '%d' to '%s' failed with error '%s'.", rid.get_id(), path, VariantUtilityFunctions::error_string(file_access->get_error())));
599
600
print_line(vformat("Snapshot of physics space with RID '%d' saved to '%s'.", rid.get_id(), path));
601
}
602
603
const PackedVector3Array &JoltSpace3D::get_debug_contacts() const {
604
return contact_listener->get_debug_contacts();
605
}
606
607
int JoltSpace3D::get_debug_contact_count() const {
608
return contact_listener->get_debug_contact_count();
609
}
610
611
int JoltSpace3D::get_max_debug_contacts() const {
612
return contact_listener->get_max_debug_contacts();
613
}
614
615
void JoltSpace3D::set_max_debug_contacts(int p_count) {
616
contact_listener->set_max_debug_contacts(p_count);
617
}
618
619
#endif
620
621