Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/modules/jolt_physics/objects/jolt_shaped_object_3d.cpp
10278 views
1
/**************************************************************************/
2
/* jolt_shaped_object_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_shaped_object_3d.h"
32
33
#include "../misc/jolt_math_funcs.h"
34
#include "../misc/jolt_type_conversions.h"
35
#include "../shapes/jolt_custom_double_sided_shape.h"
36
#include "../shapes/jolt_shape_3d.h"
37
#include "../spaces/jolt_space_3d.h"
38
39
#include "Jolt/Physics/Collision/Shape/EmptyShape.h"
40
#include "Jolt/Physics/Collision/Shape/MutableCompoundShape.h"
41
#include "Jolt/Physics/Collision/Shape/StaticCompoundShape.h"
42
43
bool JoltShapedObject3D::_is_big() const {
44
// This number is completely arbitrary, and mostly just needs to capture `WorldBoundaryShape3D`, which needs to be kept out of the normal broadphase layers.
45
return get_aabb().get_longest_axis_size() >= 1000.0f;
46
}
47
48
JPH::ShapeRefC JoltShapedObject3D::_try_build_shape(bool p_optimize_compound) {
49
int built_shapes = 0;
50
51
for (JoltShapeInstance3D &shape : shapes) {
52
if (shape.is_enabled() && shape.try_build()) {
53
built_shapes += 1;
54
}
55
}
56
57
if (unlikely(built_shapes == 0)) {
58
return nullptr;
59
}
60
61
JPH::ShapeRefC result = built_shapes == 1 ? _try_build_single_shape() : _try_build_compound_shape(p_optimize_compound);
62
if (unlikely(result == nullptr)) {
63
return nullptr;
64
}
65
66
if (has_custom_center_of_mass()) {
67
result = JoltShape3D::with_center_of_mass(result, get_center_of_mass_custom());
68
}
69
70
if (scale != Vector3(1, 1, 1)) {
71
Vector3 actual_scale = scale;
72
JOLT_ENSURE_SCALE_VALID(result, actual_scale, vformat("Failed to correctly scale body '%s'.", to_string()));
73
result = JoltShape3D::with_scale(result, actual_scale);
74
}
75
76
if (is_area()) {
77
result = JoltShape3D::with_double_sided(result, true);
78
}
79
80
return result;
81
}
82
83
JPH::ShapeRefC JoltShapedObject3D::_try_build_single_shape() {
84
for (int shape_index = 0; shape_index < (int)shapes.size(); ++shape_index) {
85
const JoltShapeInstance3D &sub_shape = shapes[shape_index];
86
87
if (!sub_shape.is_enabled() || !sub_shape.is_built()) {
88
continue;
89
}
90
91
JPH::ShapeRefC jolt_sub_shape = sub_shape.get_jolt_ref();
92
93
Vector3 sub_shape_scale = sub_shape.get_scale();
94
const Transform3D sub_shape_transform = sub_shape.get_transform_unscaled();
95
96
if (sub_shape_scale != Vector3(1, 1, 1)) {
97
JOLT_ENSURE_SCALE_VALID(jolt_sub_shape, sub_shape_scale, vformat("Failed to correctly scale shape at index %d in body '%s'.", shape_index, to_string()));
98
jolt_sub_shape = JoltShape3D::with_scale(jolt_sub_shape, sub_shape_scale);
99
}
100
101
if (sub_shape_transform != Transform3D()) {
102
jolt_sub_shape = JoltShape3D::with_basis_origin(jolt_sub_shape, sub_shape_transform.basis, sub_shape_transform.origin);
103
}
104
105
return jolt_sub_shape;
106
}
107
108
return nullptr;
109
}
110
111
JPH::ShapeRefC JoltShapedObject3D::_try_build_compound_shape(bool p_optimize) {
112
JPH::StaticCompoundShapeSettings static_compound_shape_settings;
113
JPH::MutableCompoundShapeSettings mutable_compound_shape_settings;
114
JPH::CompoundShapeSettings *compound_shape_settings = p_optimize ? static_cast<JPH::CompoundShapeSettings *>(&static_compound_shape_settings) : static_cast<JPH::CompoundShapeSettings *>(&mutable_compound_shape_settings);
115
116
compound_shape_settings->mSubShapes.reserve((size_t)shapes.size());
117
118
for (int shape_index = 0; shape_index < (int)shapes.size(); ++shape_index) {
119
const JoltShapeInstance3D &sub_shape = shapes[shape_index];
120
121
if (!sub_shape.is_enabled() || !sub_shape.is_built()) {
122
continue;
123
}
124
125
JPH::ShapeRefC jolt_sub_shape = sub_shape.get_jolt_ref();
126
127
Vector3 sub_shape_scale = sub_shape.get_scale();
128
const Transform3D sub_shape_transform = sub_shape.get_transform_unscaled();
129
130
if (sub_shape_scale != Vector3(1, 1, 1)) {
131
JOLT_ENSURE_SCALE_VALID(jolt_sub_shape, sub_shape_scale, vformat("Failed to correctly scale shape at index %d for body '%s'.", shape_index, to_string()));
132
jolt_sub_shape = JoltShape3D::with_scale(jolt_sub_shape, sub_shape_scale);
133
}
134
135
compound_shape_settings->AddShape(to_jolt(sub_shape_transform.origin), to_jolt(sub_shape_transform.basis), jolt_sub_shape);
136
}
137
138
const JPH::ShapeSettings::ShapeResult shape_result = p_optimize ? static_compound_shape_settings.Create(space->get_temp_allocator()) : mutable_compound_shape_settings.Create();
139
ERR_FAIL_COND_V_MSG(shape_result.HasError(), nullptr, vformat("Failed to create compound shape for body '%s'. It returned the following error: '%s'.", to_string(), to_godot(shape_result.GetError())));
140
141
return shape_result.Get();
142
}
143
144
void JoltShapedObject3D::_enqueue_shapes_changed() {
145
if (space != nullptr) {
146
space->enqueue_shapes_changed(&shapes_changed_element);
147
}
148
}
149
150
void JoltShapedObject3D::_dequeue_shapes_changed() {
151
if (space != nullptr) {
152
space->dequeue_shapes_changed(&shapes_changed_element);
153
}
154
}
155
156
void JoltShapedObject3D::_enqueue_needs_optimization() {
157
if (space != nullptr) {
158
space->enqueue_needs_optimization(&needs_optimization_element);
159
}
160
}
161
162
void JoltShapedObject3D::_dequeue_needs_optimization() {
163
if (space != nullptr) {
164
space->dequeue_needs_optimization(&needs_optimization_element);
165
}
166
}
167
168
void JoltShapedObject3D::_shapes_changed() {
169
commit_shapes(false);
170
}
171
172
void JoltShapedObject3D::_shapes_committed() {
173
_update_object_layer();
174
}
175
176
void JoltShapedObject3D::_space_changing() {
177
JoltObject3D::_space_changing();
178
179
_dequeue_shapes_changed();
180
_dequeue_needs_optimization();
181
182
previous_jolt_shape = nullptr;
183
184
if (in_space()) {
185
jolt_settings = new JPH::BodyCreationSettings(jolt_body->GetBodyCreationSettings());
186
}
187
}
188
189
JoltShapedObject3D::JoltShapedObject3D(ObjectType p_object_type) :
190
JoltObject3D(p_object_type),
191
shapes_changed_element(this),
192
needs_optimization_element(this) {
193
jolt_settings->mAllowSleeping = true;
194
jolt_settings->mFriction = 1.0f;
195
jolt_settings->mRestitution = 0.0f;
196
jolt_settings->mLinearDamping = 0.0f;
197
jolt_settings->mAngularDamping = 0.0f;
198
jolt_settings->mGravityFactor = 0.0f;
199
}
200
201
JoltShapedObject3D::~JoltShapedObject3D() {
202
if (jolt_settings != nullptr) {
203
delete jolt_settings;
204
jolt_settings = nullptr;
205
}
206
}
207
208
Transform3D JoltShapedObject3D::get_transform_unscaled() const {
209
if (!in_space()) {
210
return Transform3D(to_godot(jolt_settings->mRotation), to_godot(jolt_settings->mPosition));
211
} else {
212
return Transform3D(to_godot(jolt_body->GetRotation()), to_godot(jolt_body->GetPosition()));
213
}
214
}
215
216
Transform3D JoltShapedObject3D::get_transform_scaled() const {
217
return get_transform_unscaled().scaled_local(scale);
218
}
219
220
Basis JoltShapedObject3D::get_basis() const {
221
if (!in_space()) {
222
return to_godot(jolt_settings->mRotation);
223
} else {
224
return to_godot(jolt_body->GetRotation());
225
}
226
}
227
228
Vector3 JoltShapedObject3D::get_position() const {
229
if (!in_space()) {
230
return to_godot(jolt_settings->mPosition);
231
} else {
232
return to_godot(jolt_body->GetPosition());
233
}
234
}
235
236
Vector3 JoltShapedObject3D::get_center_of_mass() const {
237
ERR_FAIL_COND_V_MSG(!in_space(), Vector3(), vformat("Failed to retrieve center-of-mass 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()));
238
return to_godot(jolt_body->GetCenterOfMassPosition());
239
}
240
241
Vector3 JoltShapedObject3D::get_center_of_mass_relative() const {
242
return get_center_of_mass() - get_position();
243
}
244
245
Vector3 JoltShapedObject3D::get_center_of_mass_local() const {
246
ERR_FAIL_NULL_V_MSG(space, Vector3(), vformat("Failed to retrieve local center-of-mass 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()));
247
248
return get_transform_scaled().xform_inv(get_center_of_mass());
249
}
250
251
Vector3 JoltShapedObject3D::get_linear_velocity() const {
252
if (!in_space()) {
253
return to_godot(jolt_settings->mLinearVelocity);
254
} else {
255
return to_godot(jolt_body->GetLinearVelocity());
256
}
257
}
258
259
Vector3 JoltShapedObject3D::get_angular_velocity() const {
260
if (!in_space()) {
261
return to_godot(jolt_settings->mAngularVelocity);
262
} else {
263
return to_godot(jolt_body->GetAngularVelocity());
264
}
265
}
266
267
AABB JoltShapedObject3D::get_aabb() const {
268
AABB result;
269
270
for (const JoltShapeInstance3D &shape : shapes) {
271
if (shape.is_disabled()) {
272
continue;
273
}
274
275
if (result == AABB()) {
276
result = shape.get_aabb();
277
} else {
278
result.merge_with(shape.get_aabb());
279
}
280
}
281
282
return get_transform_scaled().xform(result);
283
}
284
285
JPH::ShapeRefC JoltShapedObject3D::build_shapes(bool p_optimize_compound) {
286
JPH::ShapeRefC new_shape = _try_build_shape(p_optimize_compound);
287
288
if (new_shape == nullptr) {
289
if (has_custom_center_of_mass()) {
290
new_shape = JPH::EmptyShapeSettings(to_jolt(get_center_of_mass_custom())).Create().Get();
291
} else {
292
new_shape = new JPH::EmptyShape();
293
}
294
}
295
296
return new_shape;
297
}
298
299
void JoltShapedObject3D::commit_shapes(bool p_optimize_compound) {
300
if (!in_space()) {
301
_shapes_committed();
302
return;
303
}
304
305
JPH::ShapeRefC new_shape = build_shapes(p_optimize_compound);
306
if (new_shape == jolt_shape) {
307
return;
308
}
309
310
if (previous_jolt_shape == nullptr) {
311
previous_jolt_shape = jolt_shape;
312
}
313
314
jolt_shape = new_shape;
315
316
space->get_body_iface().SetShape(jolt_body->GetID(), jolt_shape, false, JPH::EActivation::DontActivate);
317
318
_enqueue_shapes_changed();
319
320
if (!p_optimize_compound && jolt_shape->GetType() == JPH::EShapeType::Compound) {
321
_enqueue_needs_optimization();
322
} else {
323
_dequeue_needs_optimization();
324
}
325
326
_shapes_committed();
327
}
328
329
void JoltShapedObject3D::add_shape(JoltShape3D *p_shape, Transform3D p_transform, bool p_disabled) {
330
JOLT_ENSURE_SCALE_NOT_ZERO(p_transform, vformat("An invalid transform was passed when adding shape at index %d to physics body '%s'.", shapes.size(), to_string()));
331
332
Vector3 shape_scale;
333
JoltMath::decompose(p_transform, shape_scale);
334
335
shapes.push_back(JoltShapeInstance3D(this, p_shape, p_transform, shape_scale, p_disabled));
336
337
_shapes_changed();
338
}
339
340
void JoltShapedObject3D::remove_shape(const JoltShape3D *p_shape) {
341
for (int i = shapes.size() - 1; i >= 0; i--) {
342
if (shapes[i].get_shape() == p_shape) {
343
shapes.remove_at(i);
344
}
345
}
346
347
_shapes_changed();
348
}
349
350
void JoltShapedObject3D::remove_shape(int p_index) {
351
ERR_FAIL_INDEX(p_index, (int)shapes.size());
352
shapes.remove_at(p_index);
353
354
_shapes_changed();
355
}
356
357
JoltShape3D *JoltShapedObject3D::get_shape(int p_index) const {
358
ERR_FAIL_INDEX_V(p_index, (int)shapes.size(), nullptr);
359
return shapes[p_index].get_shape();
360
}
361
362
void JoltShapedObject3D::set_shape(int p_index, JoltShape3D *p_shape) {
363
ERR_FAIL_INDEX(p_index, (int)shapes.size());
364
shapes[p_index] = JoltShapeInstance3D(this, p_shape);
365
366
_shapes_changed();
367
}
368
369
void JoltShapedObject3D::clear_shapes() {
370
shapes.clear();
371
372
_shapes_changed();
373
}
374
375
void JoltShapedObject3D::clear_previous_shape() {
376
previous_jolt_shape = nullptr;
377
}
378
379
int JoltShapedObject3D::find_shape_index(uint32_t p_shape_instance_id) const {
380
for (int i = 0; i < (int)shapes.size(); ++i) {
381
if (shapes[i].get_id() == p_shape_instance_id) {
382
return i;
383
}
384
}
385
386
return -1;
387
}
388
389
int JoltShapedObject3D::find_shape_index(const JPH::SubShapeID &p_sub_shape_id) const {
390
ERR_FAIL_NULL_V(jolt_shape, -1);
391
return find_shape_index((uint32_t)jolt_shape->GetSubShapeUserData(p_sub_shape_id));
392
}
393
394
JoltShape3D *JoltShapedObject3D::find_shape(uint32_t p_shape_instance_id) const {
395
const int shape_index = find_shape_index(p_shape_instance_id);
396
return shape_index != -1 ? shapes[shape_index].get_shape() : nullptr;
397
}
398
399
JoltShape3D *JoltShapedObject3D::find_shape(const JPH::SubShapeID &p_sub_shape_id) const {
400
const int shape_index = find_shape_index(p_sub_shape_id);
401
return shape_index != -1 ? shapes[shape_index].get_shape() : nullptr;
402
}
403
404
Transform3D JoltShapedObject3D::get_shape_transform_unscaled(int p_index) const {
405
ERR_FAIL_INDEX_V(p_index, (int)shapes.size(), Transform3D());
406
return shapes[p_index].get_transform_unscaled();
407
}
408
409
Transform3D JoltShapedObject3D::get_shape_transform_scaled(int p_index) const {
410
ERR_FAIL_INDEX_V(p_index, (int)shapes.size(), Transform3D());
411
return shapes[p_index].get_transform_scaled();
412
}
413
414
void JoltShapedObject3D::set_shape_transform(int p_index, Transform3D p_transform) {
415
ERR_FAIL_INDEX(p_index, (int)shapes.size());
416
JOLT_ENSURE_SCALE_NOT_ZERO(p_transform, "Failed to correctly set transform for shape at index %d in body '%s'.");
417
418
Vector3 new_scale;
419
JoltMath::decompose(p_transform, new_scale);
420
421
JoltShapeInstance3D &shape = shapes[p_index];
422
423
if (shape.get_transform_unscaled() == p_transform && shape.get_scale() == new_scale) {
424
return;
425
}
426
427
shape.set_transform(p_transform);
428
shape.set_scale(new_scale);
429
430
_shapes_changed();
431
}
432
433
Vector3 JoltShapedObject3D::get_shape_scale(int p_index) const {
434
ERR_FAIL_INDEX_V(p_index, (int)shapes.size(), Vector3());
435
return shapes[p_index].get_scale();
436
}
437
438
bool JoltShapedObject3D::is_shape_disabled(int p_index) const {
439
ERR_FAIL_INDEX_V(p_index, (int)shapes.size(), false);
440
return shapes[p_index].is_disabled();
441
}
442
443
void JoltShapedObject3D::set_shape_disabled(int p_index, bool p_disabled) {
444
ERR_FAIL_INDEX(p_index, (int)shapes.size());
445
446
JoltShapeInstance3D &shape = shapes[p_index];
447
448
if (shape.is_disabled() == p_disabled) {
449
return;
450
}
451
452
if (p_disabled) {
453
shape.disable();
454
} else {
455
shape.enable();
456
}
457
458
_shapes_changed();
459
}
460
461