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
10278 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
physics_system->SetBodyActivationListener(body_activation_listener);
130
131
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) {
132
if (p_body1.IsSensor() || p_body2.IsSensor()) {
133
JPH::CollideShapeSettings new_collide_shape_settings = p_collide_shape_settings;
134
// 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.
135
new_collide_shape_settings.mBackFaceMode = JPH::EBackFaceMode::CollideWithBackFaces;
136
JPH::SubShapeIDCreator part1, part2;
137
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);
138
} else {
139
JPH::PhysicsSystem::sDefaultSimCollideBodyVsBody(p_body1, p_body2, p_transform_com1, p_transform_com2, p_collide_shape_settings, p_collector, p_shape_filter);
140
}
141
});
142
143
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) {
144
return Math::abs(MIN(p_body1.GetFriction(), p_body2.GetFriction()));
145
});
146
147
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) {
148
return CLAMP(p_body1.GetRestitution() + p_body2.GetRestitution(), 0.0f, 1.0f);
149
});
150
}
151
152
JoltSpace3D::~JoltSpace3D() {
153
if (direct_state != nullptr) {
154
memdelete(direct_state);
155
direct_state = nullptr;
156
}
157
158
if (physics_system != nullptr) {
159
delete physics_system;
160
physics_system = nullptr;
161
}
162
163
if (body_activation_listener != nullptr) {
164
delete body_activation_listener;
165
body_activation_listener = nullptr;
166
}
167
168
if (contact_listener != nullptr) {
169
delete contact_listener;
170
contact_listener = nullptr;
171
}
172
173
if (layers != nullptr) {
174
delete layers;
175
layers = nullptr;
176
}
177
178
if (temp_allocator != nullptr) {
179
delete temp_allocator;
180
temp_allocator = nullptr;
181
}
182
}
183
184
void JoltSpace3D::step(float p_step) {
185
stepping = true;
186
last_step = p_step;
187
188
_pre_step(p_step);
189
190
const JPH::EPhysicsUpdateError update_error = physics_system->Update(p_step, 1, temp_allocator, job_system);
191
192
if ((update_error & JPH::EPhysicsUpdateError::ManifoldCacheFull) != JPH::EPhysicsUpdateError::None) {
193
WARN_PRINT_ONCE(vformat("Jolt Physics manifold cache exceeded capacity and contacts were ignored. "
194
"Consider increasing maximum number of contact constraints in project settings. "
195
"Maximum number of contact constraints is currently set to %d.",
196
JoltProjectSettings::max_contact_constraints));
197
}
198
199
if ((update_error & JPH::EPhysicsUpdateError::BodyPairCacheFull) != JPH::EPhysicsUpdateError::None) {
200
WARN_PRINT_ONCE(vformat("Jolt Physics body pair cache exceeded capacity and contacts were ignored. "
201
"Consider increasing maximum number of body pairs in project settings. "
202
"Maximum number of body pairs is currently set to %d.",
203
JoltProjectSettings::max_body_pairs));
204
}
205
206
if ((update_error & JPH::EPhysicsUpdateError::ContactConstraintsFull) != JPH::EPhysicsUpdateError::None) {
207
WARN_PRINT_ONCE(vformat("Jolt Physics contact constraint buffer exceeded capacity and contacts were ignored. "
208
"Consider increasing maximum number of contact constraints in project settings. "
209
"Maximum number of contact constraints is currently set to %d.",
210
JoltProjectSettings::max_contact_constraints));
211
}
212
213
_post_step(p_step);
214
215
stepping = false;
216
}
217
218
void JoltSpace3D::call_queries() {
219
while (body_call_queries_list.first()) {
220
JoltBody3D *body = body_call_queries_list.first()->self();
221
body_call_queries_list.remove(body_call_queries_list.first());
222
body->call_queries();
223
}
224
225
while (area_call_queries_list.first()) {
226
JoltArea3D *body = area_call_queries_list.first()->self();
227
area_call_queries_list.remove(area_call_queries_list.first());
228
body->call_queries();
229
}
230
}
231
232
double JoltSpace3D::get_param(PhysicsServer3D::SpaceParameter p_param) const {
233
switch (p_param) {
234
case PhysicsServer3D::SPACE_PARAM_CONTACT_RECYCLE_RADIUS: {
235
return SPACE_DEFAULT_CONTACT_RECYCLE_RADIUS;
236
}
237
case PhysicsServer3D::SPACE_PARAM_CONTACT_MAX_SEPARATION: {
238
return SPACE_DEFAULT_CONTACT_MAX_SEPARATION;
239
}
240
case PhysicsServer3D::SPACE_PARAM_CONTACT_MAX_ALLOWED_PENETRATION: {
241
return SPACE_DEFAULT_CONTACT_MAX_ALLOWED_PENETRATION;
242
}
243
case PhysicsServer3D::SPACE_PARAM_CONTACT_DEFAULT_BIAS: {
244
return SPACE_DEFAULT_CONTACT_DEFAULT_BIAS;
245
}
246
case PhysicsServer3D::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD: {
247
return SPACE_DEFAULT_SLEEP_THRESHOLD_LINEAR;
248
}
249
case PhysicsServer3D::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD: {
250
return SPACE_DEFAULT_SLEEP_THRESHOLD_ANGULAR;
251
}
252
case PhysicsServer3D::SPACE_PARAM_BODY_TIME_TO_SLEEP: {
253
return JoltProjectSettings::sleep_time_threshold;
254
}
255
case PhysicsServer3D::SPACE_PARAM_SOLVER_ITERATIONS: {
256
return SPACE_DEFAULT_SOLVER_ITERATIONS;
257
}
258
default: {
259
ERR_FAIL_V_MSG(0.0, vformat("Unhandled space parameter: '%d'. This should not happen. Please report this.", p_param));
260
}
261
}
262
}
263
264
void JoltSpace3D::set_param(PhysicsServer3D::SpaceParameter p_param, double p_value) {
265
switch (p_param) {
266
case PhysicsServer3D::SPACE_PARAM_CONTACT_RECYCLE_RADIUS: {
267
WARN_PRINT("Space-specific contact recycle radius is not supported when using Jolt Physics. Any such value will be ignored.");
268
} break;
269
case PhysicsServer3D::SPACE_PARAM_CONTACT_MAX_SEPARATION: {
270
WARN_PRINT("Space-specific contact max separation is not supported when using Jolt Physics. Any such value will be ignored.");
271
} break;
272
case PhysicsServer3D::SPACE_PARAM_CONTACT_MAX_ALLOWED_PENETRATION: {
273
WARN_PRINT("Space-specific contact max allowed penetration is not supported when using Jolt Physics. Any such value will be ignored.");
274
} break;
275
case PhysicsServer3D::SPACE_PARAM_CONTACT_DEFAULT_BIAS: {
276
WARN_PRINT("Space-specific contact default bias is not supported when using Jolt Physics. Any such value will be ignored.");
277
} break;
278
case PhysicsServer3D::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD: {
279
WARN_PRINT("Space-specific linear velocity sleep threshold is not supported when using Jolt Physics. Any such value will be ignored.");
280
} break;
281
case PhysicsServer3D::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD: {
282
WARN_PRINT("Space-specific angular velocity sleep threshold is not supported when using Jolt Physics. Any such value will be ignored.");
283
} break;
284
case PhysicsServer3D::SPACE_PARAM_BODY_TIME_TO_SLEEP: {
285
WARN_PRINT("Space-specific body sleep time is not supported when using Jolt Physics. Any such value will be ignored.");
286
} break;
287
case PhysicsServer3D::SPACE_PARAM_SOLVER_ITERATIONS: {
288
WARN_PRINT("Space-specific solver iterations is not supported when using Jolt Physics. Any such value will be ignored.");
289
} break;
290
default: {
291
ERR_FAIL_MSG(vformat("Unhandled space parameter: '%d'. This should not happen. Please report this.", p_param));
292
} break;
293
}
294
}
295
296
JPH::BodyInterface &JoltSpace3D::get_body_iface() {
297
return physics_system->GetBodyInterfaceNoLock();
298
}
299
300
const JPH::BodyInterface &JoltSpace3D::get_body_iface() const {
301
return physics_system->GetBodyInterfaceNoLock();
302
}
303
304
const JPH::BodyLockInterface &JoltSpace3D::get_lock_iface() const {
305
return physics_system->GetBodyLockInterfaceNoLock();
306
}
307
308
const JPH::BroadPhaseQuery &JoltSpace3D::get_broad_phase_query() const {
309
return physics_system->GetBroadPhaseQuery();
310
}
311
312
const JPH::NarrowPhaseQuery &JoltSpace3D::get_narrow_phase_query() const {
313
return physics_system->GetNarrowPhaseQueryNoLock();
314
}
315
316
JPH::ObjectLayer JoltSpace3D::map_to_object_layer(JPH::BroadPhaseLayer p_broad_phase_layer, uint32_t p_collision_layer, uint32_t p_collision_mask) {
317
return layers->to_object_layer(p_broad_phase_layer, p_collision_layer, p_collision_mask);
318
}
319
320
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 {
321
layers->from_object_layer(p_object_layer, r_broad_phase_layer, r_collision_layer, r_collision_mask);
322
}
323
324
JPH::Body *JoltSpace3D::try_get_jolt_body(const JPH::BodyID &p_body_id) const {
325
return get_lock_iface().TryGetBody(p_body_id);
326
}
327
328
JoltObject3D *JoltSpace3D::try_get_object(const JPH::BodyID &p_body_id) const {
329
const JPH::Body *jolt_body = try_get_jolt_body(p_body_id);
330
if (unlikely(jolt_body == nullptr)) {
331
return nullptr;
332
}
333
334
return reinterpret_cast<JoltObject3D *>(jolt_body->GetUserData());
335
}
336
337
JoltShapedObject3D *JoltSpace3D::try_get_shaped(const JPH::BodyID &p_body_id) const {
338
JoltObject3D *object = try_get_object(p_body_id);
339
if (unlikely(object == nullptr)) {
340
return nullptr;
341
}
342
343
return object->as_shaped();
344
}
345
346
JoltBody3D *JoltSpace3D::try_get_body(const JPH::BodyID &p_body_id) const {
347
JoltObject3D *object = try_get_object(p_body_id);
348
if (unlikely(object == nullptr)) {
349
return nullptr;
350
}
351
352
return object->as_body();
353
}
354
355
JoltArea3D *JoltSpace3D::try_get_area(const JPH::BodyID &p_body_id) const {
356
JoltObject3D *object = try_get_object(p_body_id);
357
if (unlikely(object == nullptr)) {
358
return nullptr;
359
}
360
361
return object->as_area();
362
}
363
364
JoltSoftBody3D *JoltSpace3D::try_get_soft_body(const JPH::BodyID &p_body_id) const {
365
JoltObject3D *object = try_get_object(p_body_id);
366
if (unlikely(object == nullptr)) {
367
return nullptr;
368
}
369
370
return object->as_soft_body();
371
}
372
373
JoltPhysicsDirectSpaceState3D *JoltSpace3D::get_direct_state() {
374
if (direct_state == nullptr) {
375
direct_state = memnew(JoltPhysicsDirectSpaceState3D(this));
376
}
377
378
return direct_state;
379
}
380
381
void JoltSpace3D::set_default_area(JoltArea3D *p_area) {
382
if (default_area == p_area) {
383
return;
384
}
385
386
if (default_area != nullptr) {
387
default_area->set_default_area(false);
388
}
389
390
default_area = p_area;
391
392
if (default_area != nullptr) {
393
default_area->set_default_area(true);
394
}
395
}
396
397
JPH::Body *JoltSpace3D::add_object(const JoltObject3D &p_object, const JPH::BodyCreationSettings &p_settings, bool p_sleeping) {
398
JPH::BodyInterface &body_iface = get_body_iface();
399
JPH::Body *jolt_body = body_iface.CreateBody(p_settings);
400
if (unlikely(jolt_body == nullptr)) {
401
ERR_PRINT_ONCE(vformat("Failed to create underlying Jolt Physics body for '%s'. "
402
"Consider increasing maximum number of bodies in project settings. "
403
"Maximum number of bodies is currently set to %d.",
404
p_object.to_string(), JoltProjectSettings::max_bodies));
405
406
return nullptr;
407
}
408
409
if (p_sleeping) {
410
pending_objects_sleeping.push_back(jolt_body->GetID());
411
} else {
412
pending_objects_awake.push_back(jolt_body->GetID());
413
}
414
415
return jolt_body;
416
}
417
418
JPH::Body *JoltSpace3D::add_object(const JoltObject3D &p_object, const JPH::SoftBodyCreationSettings &p_settings, bool p_sleeping) {
419
JPH::BodyInterface &body_iface = get_body_iface();
420
JPH::Body *jolt_body = body_iface.CreateSoftBody(p_settings);
421
if (unlikely(jolt_body == nullptr)) {
422
ERR_PRINT_ONCE(vformat("Failed to create underlying Jolt Physics body for '%s'. "
423
"Consider increasing maximum number of bodies in project settings. "
424
"Maximum number of bodies is currently set to %d.",
425
p_object.to_string(), JoltProjectSettings::max_bodies));
426
427
return nullptr;
428
}
429
430
if (p_sleeping) {
431
pending_objects_sleeping.push_back(jolt_body->GetID());
432
} else {
433
pending_objects_awake.push_back(jolt_body->GetID());
434
}
435
436
return jolt_body;
437
}
438
439
void JoltSpace3D::remove_object(const JPH::BodyID &p_jolt_id) {
440
JPH::BodyInterface &body_iface = get_body_iface();
441
442
if (!pending_objects_sleeping.erase_unordered(p_jolt_id) && !pending_objects_awake.erase_unordered(p_jolt_id)) {
443
body_iface.RemoveBody(p_jolt_id);
444
}
445
446
body_iface.DestroyBody(p_jolt_id);
447
448
// 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.
449
// 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.
450
if (!JoltPhysicsServer3D::get_singleton()->is_active() && physics_system->GetNumBodies() <= 1) {
451
physics_system->OptimizeBroadPhase();
452
}
453
}
454
455
void JoltSpace3D::flush_pending_objects() {
456
if (pending_objects_sleeping.is_empty() && pending_objects_awake.is_empty()) {
457
return;
458
}
459
460
// We only care about locking within this method, because it's called when performing queries, which aren't covered by `PhysicsServer3DWrapMT`.
461
MutexLock pending_objects_lock(pending_objects_mutex);
462
463
JPH::BodyInterface &body_iface = get_body_iface();
464
465
if (!pending_objects_sleeping.is_empty()) {
466
JPH::BodyInterface::AddState add_state = body_iface.AddBodiesPrepare(pending_objects_sleeping.ptr(), pending_objects_sleeping.size());
467
body_iface.AddBodiesFinalize(pending_objects_sleeping.ptr(), pending_objects_sleeping.size(), add_state, JPH::EActivation::DontActivate);
468
pending_objects_sleeping.reset();
469
}
470
471
if (!pending_objects_awake.is_empty()) {
472
JPH::BodyInterface::AddState add_state = body_iface.AddBodiesPrepare(pending_objects_awake.ptr(), pending_objects_awake.size());
473
body_iface.AddBodiesFinalize(pending_objects_awake.ptr(), pending_objects_awake.size(), add_state, JPH::EActivation::Activate);
474
pending_objects_awake.reset();
475
}
476
}
477
478
void JoltSpace3D::set_is_object_sleeping(const JPH::BodyID &p_jolt_id, bool p_enable) {
479
if (p_enable) {
480
if (pending_objects_awake.erase_unordered(p_jolt_id)) {
481
pending_objects_sleeping.push_back(p_jolt_id);
482
} else if (pending_objects_sleeping.has(p_jolt_id)) {
483
// Do nothing.
484
} else {
485
get_body_iface().DeactivateBody(p_jolt_id);
486
}
487
} else {
488
if (pending_objects_sleeping.erase_unordered(p_jolt_id)) {
489
pending_objects_awake.push_back(p_jolt_id);
490
} else if (pending_objects_awake.has(p_jolt_id)) {
491
// Do nothing.
492
} else {
493
get_body_iface().ActivateBody(p_jolt_id);
494
}
495
}
496
}
497
498
void JoltSpace3D::enqueue_call_queries(SelfList<JoltBody3D> *p_body) {
499
// This method will be called from the body activation listener on multiple threads during the simulation step.
500
MutexLock body_call_queries_lock(body_call_queries_mutex);
501
502
if (!p_body->in_list()) {
503
body_call_queries_list.add(p_body);
504
}
505
}
506
507
void JoltSpace3D::enqueue_call_queries(SelfList<JoltArea3D> *p_area) {
508
if (!p_area->in_list()) {
509
area_call_queries_list.add(p_area);
510
}
511
}
512
513
void JoltSpace3D::dequeue_call_queries(SelfList<JoltBody3D> *p_body) {
514
if (p_body->in_list()) {
515
body_call_queries_list.remove(p_body);
516
}
517
}
518
519
void JoltSpace3D::dequeue_call_queries(SelfList<JoltArea3D> *p_area) {
520
if (p_area->in_list()) {
521
area_call_queries_list.remove(p_area);
522
}
523
}
524
525
void JoltSpace3D::enqueue_shapes_changed(SelfList<JoltShapedObject3D> *p_object) {
526
if (!p_object->in_list()) {
527
shapes_changed_list.add(p_object);
528
}
529
}
530
531
void JoltSpace3D::dequeue_shapes_changed(SelfList<JoltShapedObject3D> *p_object) {
532
if (p_object->in_list()) {
533
shapes_changed_list.remove(p_object);
534
}
535
}
536
537
void JoltSpace3D::enqueue_needs_optimization(SelfList<JoltShapedObject3D> *p_object) {
538
if (!p_object->in_list()) {
539
needs_optimization_list.add(p_object);
540
}
541
}
542
543
void JoltSpace3D::dequeue_needs_optimization(SelfList<JoltShapedObject3D> *p_object) {
544
if (p_object->in_list()) {
545
needs_optimization_list.remove(p_object);
546
}
547
}
548
549
void JoltSpace3D::add_joint(JPH::Constraint *p_jolt_ref) {
550
physics_system->AddConstraint(p_jolt_ref);
551
}
552
553
void JoltSpace3D::add_joint(JoltJoint3D *p_joint) {
554
add_joint(p_joint->get_jolt_ref());
555
}
556
557
void JoltSpace3D::remove_joint(JPH::Constraint *p_jolt_ref) {
558
physics_system->RemoveConstraint(p_jolt_ref);
559
}
560
561
void JoltSpace3D::remove_joint(JoltJoint3D *p_joint) {
562
remove_joint(p_joint->get_jolt_ref());
563
}
564
565
#ifdef DEBUG_ENABLED
566
567
void JoltSpace3D::dump_debug_snapshot(const String &p_dir) {
568
const Dictionary datetime = Time::get_singleton()->get_datetime_dict_from_system();
569
const String datetime_str = vformat("%04d-%02d-%02d_%02d-%02d-%02d", datetime["year"], datetime["month"], datetime["day"], datetime["hour"], datetime["minute"], datetime["second"]);
570
const String path = p_dir + vformat("/jolt_snapshot_%s_%d.bin", datetime_str, rid.get_id());
571
572
Ref<FileAccess> file_access = FileAccess::open(path, FileAccess::ModeFlags::WRITE);
573
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()));
574
575
JPH::PhysicsScene physics_scene;
576
physics_scene.FromPhysicsSystem(physics_system);
577
578
for (JPH::BodyCreationSettings &settings : physics_scene.GetBodies()) {
579
const JoltObject3D *object = reinterpret_cast<const JoltObject3D *>(settings.mUserData);
580
581
if (const JoltBody3D *body = object->as_body()) {
582
// 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.
583
settings.mGravityFactor = body->get_gravity_scale();
584
settings.mLinearDamping = body->get_total_linear_damp();
585
settings.mAngularDamping = body->get_total_angular_damp();
586
}
587
588
settings.SetShape(JoltShape3D::without_custom_shapes(settings.GetShape()));
589
}
590
591
JoltStreamOutputWrapper output_stream(file_access);
592
physics_scene.SaveBinaryState(output_stream, true, false);
593
594
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())));
595
596
print_line(vformat("Snapshot of physics space with RID '%d' saved to '%s'.", rid.get_id(), path));
597
}
598
599
const PackedVector3Array &JoltSpace3D::get_debug_contacts() const {
600
return contact_listener->get_debug_contacts();
601
}
602
603
int JoltSpace3D::get_debug_contact_count() const {
604
return contact_listener->get_debug_contact_count();
605
}
606
607
int JoltSpace3D::get_max_debug_contacts() const {
608
return contact_listener->get_max_debug_contacts();
609
}
610
611
void JoltSpace3D::set_max_debug_contacts(int p_count) {
612
contact_listener->set_max_debug_contacts(p_count);
613
}
614
615
#endif
616
617