Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/modules/godot_physics_3d/godot_body_3d.cpp
10277 views
1
/**************************************************************************/
2
/* godot_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 "godot_body_3d.h"
32
33
#include "godot_area_3d.h"
34
#include "godot_body_direct_state_3d.h"
35
#include "godot_constraint_3d.h"
36
#include "godot_space_3d.h"
37
38
void GodotBody3D::_mass_properties_changed() {
39
if (get_space() && !mass_properties_update_list.in_list()) {
40
get_space()->body_add_to_mass_properties_update_list(&mass_properties_update_list);
41
}
42
}
43
44
void GodotBody3D::_update_transform_dependent() {
45
center_of_mass = get_transform().basis.xform(center_of_mass_local);
46
principal_inertia_axes = get_transform().basis * principal_inertia_axes_local;
47
48
// Update inertia tensor.
49
Basis tb = principal_inertia_axes;
50
Basis tbt = tb.transposed();
51
Basis diag;
52
diag.scale(_inv_inertia);
53
_inv_inertia_tensor = tb * diag * tbt;
54
}
55
56
void GodotBody3D::update_mass_properties() {
57
// Update shapes and motions.
58
59
switch (mode) {
60
case PhysicsServer3D::BODY_MODE_RIGID: {
61
real_t total_area = 0;
62
for (int i = 0; i < get_shape_count(); i++) {
63
if (is_shape_disabled(i)) {
64
continue;
65
}
66
67
total_area += get_shape_area(i);
68
}
69
70
if (calculate_center_of_mass) {
71
// We have to recompute the center of mass.
72
center_of_mass_local.zero();
73
74
if (total_area != 0.0) {
75
for (int i = 0; i < get_shape_count(); i++) {
76
if (is_shape_disabled(i)) {
77
continue;
78
}
79
80
real_t area = get_shape_area(i);
81
82
real_t mass_new = area * mass / total_area;
83
84
// NOTE: we assume that the shape origin is also its center of mass.
85
center_of_mass_local += mass_new * get_shape_transform(i).origin;
86
}
87
88
center_of_mass_local /= mass;
89
}
90
}
91
92
if (calculate_inertia) {
93
// Recompute the inertia tensor.
94
Basis inertia_tensor;
95
inertia_tensor.set_zero();
96
bool inertia_set = false;
97
98
for (int i = 0; i < get_shape_count(); i++) {
99
if (is_shape_disabled(i)) {
100
continue;
101
}
102
103
real_t area = get_shape_area(i);
104
if (area == 0.0) {
105
continue;
106
}
107
108
inertia_set = true;
109
110
const GodotShape3D *shape = get_shape(i);
111
112
real_t mass_new = area * mass / total_area;
113
114
Basis shape_inertia_tensor = Basis::from_scale(shape->get_moment_of_inertia(mass_new));
115
Transform3D shape_transform = get_shape_transform(i);
116
Basis shape_basis = shape_transform.basis.orthonormalized();
117
118
// NOTE: we don't take the scale of collision shapes into account when computing the inertia tensor!
119
shape_inertia_tensor = shape_basis * shape_inertia_tensor * shape_basis.transposed();
120
121
Vector3 shape_origin = shape_transform.origin - center_of_mass_local;
122
inertia_tensor += shape_inertia_tensor + (Basis() * shape_origin.dot(shape_origin) - shape_origin.outer(shape_origin)) * mass_new;
123
}
124
125
// Set the inertia to a valid value when there are no valid shapes.
126
if (!inertia_set) {
127
inertia_tensor = Basis();
128
}
129
130
// Handle partial custom inertia.
131
if (inertia.x > 0.0) {
132
inertia_tensor[0][0] = inertia.x;
133
}
134
if (inertia.y > 0.0) {
135
inertia_tensor[1][1] = inertia.y;
136
}
137
if (inertia.z > 0.0) {
138
inertia_tensor[2][2] = inertia.z;
139
}
140
141
// Compute the principal axes of inertia.
142
principal_inertia_axes_local = inertia_tensor.diagonalize().transposed();
143
_inv_inertia = inertia_tensor.get_main_diagonal().inverse();
144
}
145
146
if (mass) {
147
_inv_mass = 1.0 / mass;
148
} else {
149
_inv_mass = 0;
150
}
151
152
} break;
153
case PhysicsServer3D::BODY_MODE_KINEMATIC:
154
case PhysicsServer3D::BODY_MODE_STATIC: {
155
_inv_inertia = Vector3();
156
_inv_mass = 0;
157
} break;
158
case PhysicsServer3D::BODY_MODE_RIGID_LINEAR: {
159
_inv_inertia_tensor.set_zero();
160
_inv_mass = 1.0 / mass;
161
162
} break;
163
}
164
165
_update_transform_dependent();
166
}
167
168
void GodotBody3D::reset_mass_properties() {
169
calculate_inertia = true;
170
calculate_center_of_mass = true;
171
_mass_properties_changed();
172
}
173
174
void GodotBody3D::set_active(bool p_active) {
175
if (active == p_active) {
176
return;
177
}
178
179
active = p_active;
180
181
if (active) {
182
if (mode == PhysicsServer3D::BODY_MODE_STATIC) {
183
// Static bodies can't be active.
184
active = false;
185
} else if (get_space()) {
186
get_space()->body_add_to_active_list(&active_list);
187
}
188
} else if (get_space()) {
189
get_space()->body_remove_from_active_list(&active_list);
190
}
191
}
192
193
void GodotBody3D::set_param(PhysicsServer3D::BodyParameter p_param, const Variant &p_value) {
194
switch (p_param) {
195
case PhysicsServer3D::BODY_PARAM_BOUNCE: {
196
bounce = p_value;
197
} break;
198
case PhysicsServer3D::BODY_PARAM_FRICTION: {
199
friction = p_value;
200
} break;
201
case PhysicsServer3D::BODY_PARAM_MASS: {
202
real_t mass_value = p_value;
203
ERR_FAIL_COND(mass_value <= 0);
204
mass = mass_value;
205
if (mode >= PhysicsServer3D::BODY_MODE_RIGID) {
206
_mass_properties_changed();
207
}
208
} break;
209
case PhysicsServer3D::BODY_PARAM_INERTIA: {
210
inertia = p_value;
211
if ((inertia.x <= 0.0) || (inertia.y <= 0.0) || (inertia.z <= 0.0)) {
212
calculate_inertia = true;
213
if (mode == PhysicsServer3D::BODY_MODE_RIGID) {
214
_mass_properties_changed();
215
}
216
} else {
217
calculate_inertia = false;
218
if (mode == PhysicsServer3D::BODY_MODE_RIGID) {
219
principal_inertia_axes_local = Basis();
220
_inv_inertia = inertia.inverse();
221
_update_transform_dependent();
222
}
223
}
224
} break;
225
case PhysicsServer3D::BODY_PARAM_CENTER_OF_MASS: {
226
calculate_center_of_mass = false;
227
center_of_mass_local = p_value;
228
_update_transform_dependent();
229
} break;
230
case PhysicsServer3D::BODY_PARAM_GRAVITY_SCALE: {
231
if (Math::is_zero_approx(gravity_scale)) {
232
wakeup();
233
}
234
gravity_scale = p_value;
235
} break;
236
case PhysicsServer3D::BODY_PARAM_LINEAR_DAMP_MODE: {
237
int mode_value = p_value;
238
linear_damp_mode = (PhysicsServer3D::BodyDampMode)mode_value;
239
} break;
240
case PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP_MODE: {
241
int mode_value = p_value;
242
angular_damp_mode = (PhysicsServer3D::BodyDampMode)mode_value;
243
} break;
244
case PhysicsServer3D::BODY_PARAM_LINEAR_DAMP: {
245
linear_damp = p_value;
246
} break;
247
case PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP: {
248
angular_damp = p_value;
249
} break;
250
default: {
251
}
252
}
253
}
254
255
Variant GodotBody3D::get_param(PhysicsServer3D::BodyParameter p_param) const {
256
switch (p_param) {
257
case PhysicsServer3D::BODY_PARAM_BOUNCE: {
258
return bounce;
259
} break;
260
case PhysicsServer3D::BODY_PARAM_FRICTION: {
261
return friction;
262
} break;
263
case PhysicsServer3D::BODY_PARAM_MASS: {
264
return mass;
265
} break;
266
case PhysicsServer3D::BODY_PARAM_INERTIA: {
267
if (mode == PhysicsServer3D::BODY_MODE_RIGID) {
268
return _inv_inertia.inverse();
269
} else {
270
return Vector3();
271
}
272
} break;
273
case PhysicsServer3D::BODY_PARAM_CENTER_OF_MASS: {
274
return center_of_mass_local;
275
} break;
276
case PhysicsServer3D::BODY_PARAM_GRAVITY_SCALE: {
277
return gravity_scale;
278
} break;
279
case PhysicsServer3D::BODY_PARAM_LINEAR_DAMP_MODE: {
280
return linear_damp_mode;
281
}
282
case PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP_MODE: {
283
return angular_damp_mode;
284
}
285
case PhysicsServer3D::BODY_PARAM_LINEAR_DAMP: {
286
return linear_damp;
287
} break;
288
case PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP: {
289
return angular_damp;
290
} break;
291
292
default: {
293
}
294
}
295
296
return 0;
297
}
298
299
void GodotBody3D::set_mode(PhysicsServer3D::BodyMode p_mode) {
300
PhysicsServer3D::BodyMode prev = mode;
301
mode = p_mode;
302
303
switch (p_mode) {
304
case PhysicsServer3D::BODY_MODE_STATIC:
305
case PhysicsServer3D::BODY_MODE_KINEMATIC: {
306
_set_inv_transform(get_transform().affine_inverse());
307
_inv_mass = 0;
308
_inv_inertia = Vector3();
309
_set_static(p_mode == PhysicsServer3D::BODY_MODE_STATIC);
310
set_active(p_mode == PhysicsServer3D::BODY_MODE_KINEMATIC && contacts.size());
311
linear_velocity = Vector3();
312
angular_velocity = Vector3();
313
if (mode == PhysicsServer3D::BODY_MODE_KINEMATIC && prev != mode) {
314
first_time_kinematic = true;
315
}
316
_update_transform_dependent();
317
318
} break;
319
case PhysicsServer3D::BODY_MODE_RIGID: {
320
_inv_mass = mass > 0 ? (1.0 / mass) : 0;
321
if (!calculate_inertia) {
322
principal_inertia_axes_local = Basis();
323
_inv_inertia = inertia.inverse();
324
_update_transform_dependent();
325
}
326
_mass_properties_changed();
327
_set_static(false);
328
set_active(true);
329
330
} break;
331
case PhysicsServer3D::BODY_MODE_RIGID_LINEAR: {
332
_inv_mass = mass > 0 ? (1.0 / mass) : 0;
333
_inv_inertia = Vector3();
334
angular_velocity = Vector3();
335
_update_transform_dependent();
336
_set_static(false);
337
set_active(true);
338
}
339
}
340
}
341
342
PhysicsServer3D::BodyMode GodotBody3D::get_mode() const {
343
return mode;
344
}
345
346
void GodotBody3D::_shapes_changed() {
347
_mass_properties_changed();
348
wakeup();
349
wakeup_neighbours();
350
}
351
352
void GodotBody3D::set_state(PhysicsServer3D::BodyState p_state, const Variant &p_variant) {
353
switch (p_state) {
354
case PhysicsServer3D::BODY_STATE_TRANSFORM: {
355
if (mode == PhysicsServer3D::BODY_MODE_KINEMATIC) {
356
new_transform = p_variant;
357
//wakeup_neighbours();
358
set_active(true);
359
if (first_time_kinematic) {
360
_set_transform(p_variant);
361
_set_inv_transform(get_transform().affine_inverse());
362
first_time_kinematic = false;
363
}
364
365
} else if (mode == PhysicsServer3D::BODY_MODE_STATIC) {
366
_set_transform(p_variant);
367
_set_inv_transform(get_transform().affine_inverse());
368
wakeup_neighbours();
369
} else {
370
Transform3D t = p_variant;
371
t.orthonormalize();
372
new_transform = get_transform(); //used as old to compute motion
373
if (new_transform == t) {
374
break;
375
}
376
_set_transform(t);
377
_set_inv_transform(get_transform().inverse());
378
_update_transform_dependent();
379
}
380
wakeup();
381
382
} break;
383
case PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY: {
384
linear_velocity = p_variant;
385
constant_linear_velocity = linear_velocity;
386
wakeup();
387
} break;
388
case PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY: {
389
angular_velocity = p_variant;
390
constant_angular_velocity = angular_velocity;
391
wakeup();
392
393
} break;
394
case PhysicsServer3D::BODY_STATE_SLEEPING: {
395
if (mode == PhysicsServer3D::BODY_MODE_STATIC || mode == PhysicsServer3D::BODY_MODE_KINEMATIC) {
396
break;
397
}
398
bool do_sleep = p_variant;
399
if (do_sleep) {
400
linear_velocity = Vector3();
401
//biased_linear_velocity=Vector3();
402
angular_velocity = Vector3();
403
//biased_angular_velocity=Vector3();
404
set_active(false);
405
} else {
406
set_active(true);
407
}
408
} break;
409
case PhysicsServer3D::BODY_STATE_CAN_SLEEP: {
410
can_sleep = p_variant;
411
if (mode >= PhysicsServer3D::BODY_MODE_RIGID && !active && !can_sleep) {
412
set_active(true);
413
}
414
415
} break;
416
}
417
}
418
419
Variant GodotBody3D::get_state(PhysicsServer3D::BodyState p_state) const {
420
switch (p_state) {
421
case PhysicsServer3D::BODY_STATE_TRANSFORM: {
422
return get_transform();
423
} break;
424
case PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY: {
425
return linear_velocity;
426
} break;
427
case PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY: {
428
return angular_velocity;
429
} break;
430
case PhysicsServer3D::BODY_STATE_SLEEPING: {
431
return !is_active();
432
} break;
433
case PhysicsServer3D::BODY_STATE_CAN_SLEEP: {
434
return can_sleep;
435
} break;
436
}
437
438
return Variant();
439
}
440
441
void GodotBody3D::set_space(GodotSpace3D *p_space) {
442
if (get_space()) {
443
if (mass_properties_update_list.in_list()) {
444
get_space()->body_remove_from_mass_properties_update_list(&mass_properties_update_list);
445
}
446
if (active_list.in_list()) {
447
get_space()->body_remove_from_active_list(&active_list);
448
}
449
if (direct_state_query_list.in_list()) {
450
get_space()->body_remove_from_state_query_list(&direct_state_query_list);
451
}
452
}
453
454
_set_space(p_space);
455
456
if (get_space()) {
457
_mass_properties_changed();
458
459
if (active && !active_list.in_list()) {
460
get_space()->body_add_to_active_list(&active_list);
461
}
462
}
463
}
464
465
void GodotBody3D::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool lock) {
466
if (lock) {
467
locked_axis |= p_axis;
468
} else {
469
locked_axis &= ~p_axis;
470
}
471
}
472
473
bool GodotBody3D::is_axis_locked(PhysicsServer3D::BodyAxis p_axis) const {
474
return locked_axis & p_axis;
475
}
476
477
void GodotBody3D::integrate_forces(real_t p_step) {
478
if (mode == PhysicsServer3D::BODY_MODE_STATIC) {
479
return;
480
}
481
482
ERR_FAIL_NULL(get_space());
483
484
int ac = areas.size();
485
486
bool gravity_done = false;
487
bool linear_damp_done = false;
488
bool angular_damp_done = false;
489
490
bool stopped = false;
491
492
gravity = Vector3(0, 0, 0);
493
494
total_linear_damp = 0.0;
495
total_angular_damp = 0.0;
496
497
// Combine gravity and damping from overlapping areas in priority order.
498
if (ac) {
499
areas.sort();
500
const AreaCMP *aa = &areas[0];
501
for (int i = ac - 1; i >= 0 && !stopped; i--) {
502
if (!gravity_done) {
503
PhysicsServer3D::AreaSpaceOverrideMode area_gravity_mode = (PhysicsServer3D::AreaSpaceOverrideMode)(int)aa[i].area->get_param(PhysicsServer3D::AREA_PARAM_GRAVITY_OVERRIDE_MODE);
504
if (area_gravity_mode != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) {
505
Vector3 area_gravity;
506
aa[i].area->compute_gravity(get_transform().get_origin(), area_gravity);
507
switch (area_gravity_mode) {
508
case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE:
509
case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: {
510
gravity += area_gravity;
511
gravity_done = area_gravity_mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE;
512
} break;
513
case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE:
514
case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: {
515
gravity = area_gravity;
516
gravity_done = area_gravity_mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE;
517
} break;
518
default: {
519
}
520
}
521
}
522
}
523
if (!linear_damp_done) {
524
PhysicsServer3D::AreaSpaceOverrideMode area_linear_damp_mode = (PhysicsServer3D::AreaSpaceOverrideMode)(int)aa[i].area->get_param(PhysicsServer3D::AREA_PARAM_LINEAR_DAMP_OVERRIDE_MODE);
525
if (area_linear_damp_mode != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) {
526
real_t area_linear_damp = aa[i].area->get_linear_damp();
527
switch (area_linear_damp_mode) {
528
case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE:
529
case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: {
530
total_linear_damp += area_linear_damp;
531
linear_damp_done = area_linear_damp_mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE;
532
} break;
533
case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE:
534
case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: {
535
total_linear_damp = area_linear_damp;
536
linear_damp_done = area_linear_damp_mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE;
537
} break;
538
default: {
539
}
540
}
541
}
542
}
543
if (!angular_damp_done) {
544
PhysicsServer3D::AreaSpaceOverrideMode area_angular_damp_mode = (PhysicsServer3D::AreaSpaceOverrideMode)(int)aa[i].area->get_param(PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP_OVERRIDE_MODE);
545
if (area_angular_damp_mode != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) {
546
real_t area_angular_damp = aa[i].area->get_angular_damp();
547
switch (area_angular_damp_mode) {
548
case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE:
549
case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: {
550
total_angular_damp += area_angular_damp;
551
angular_damp_done = area_angular_damp_mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE;
552
} break;
553
case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE:
554
case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: {
555
total_angular_damp = area_angular_damp;
556
angular_damp_done = area_angular_damp_mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE;
557
} break;
558
default: {
559
}
560
}
561
}
562
}
563
stopped = gravity_done && linear_damp_done && angular_damp_done;
564
}
565
}
566
567
// Add default gravity and damping from space area.
568
if (!stopped) {
569
GodotArea3D *default_area = get_space()->get_default_area();
570
ERR_FAIL_NULL(default_area);
571
572
if (!gravity_done) {
573
Vector3 default_gravity;
574
default_area->compute_gravity(get_transform().get_origin(), default_gravity);
575
gravity += default_gravity;
576
}
577
578
if (!linear_damp_done) {
579
total_linear_damp += default_area->get_linear_damp();
580
}
581
582
if (!angular_damp_done) {
583
total_angular_damp += default_area->get_angular_damp();
584
}
585
}
586
587
// Override linear damping with body's value.
588
switch (linear_damp_mode) {
589
case PhysicsServer3D::BODY_DAMP_MODE_COMBINE: {
590
total_linear_damp += linear_damp;
591
} break;
592
case PhysicsServer3D::BODY_DAMP_MODE_REPLACE: {
593
total_linear_damp = linear_damp;
594
} break;
595
}
596
597
// Override angular damping with body's value.
598
switch (angular_damp_mode) {
599
case PhysicsServer3D::BODY_DAMP_MODE_COMBINE: {
600
total_angular_damp += angular_damp;
601
} break;
602
case PhysicsServer3D::BODY_DAMP_MODE_REPLACE: {
603
total_angular_damp = angular_damp;
604
} break;
605
}
606
607
gravity *= gravity_scale;
608
609
prev_linear_velocity = linear_velocity;
610
prev_angular_velocity = angular_velocity;
611
612
Vector3 motion;
613
bool do_motion = false;
614
615
if (mode == PhysicsServer3D::BODY_MODE_KINEMATIC) {
616
//compute motion, angular and etc. velocities from prev transform
617
motion = new_transform.origin - get_transform().origin;
618
do_motion = true;
619
linear_velocity = constant_linear_velocity + motion / p_step;
620
621
//compute a FAKE angular velocity, not so easy
622
Basis rot = new_transform.basis.orthonormalized() * get_transform().basis.orthonormalized().transposed();
623
Vector3 axis;
624
real_t angle;
625
626
rot.get_axis_angle(axis, angle);
627
axis.normalize();
628
angular_velocity = constant_angular_velocity + axis * (angle / p_step);
629
} else {
630
if (!omit_force_integration) {
631
//overridden by direct state query
632
633
Vector3 force = gravity * mass + applied_force + constant_force;
634
Vector3 torque = applied_torque + constant_torque;
635
636
real_t damp = 1.0 - p_step * total_linear_damp;
637
638
if (damp < 0) { // reached zero in the given time
639
damp = 0;
640
}
641
642
real_t angular_damp_new = 1.0 - p_step * total_angular_damp;
643
644
if (angular_damp_new < 0) { // reached zero in the given time
645
angular_damp_new = 0;
646
}
647
648
linear_velocity *= damp;
649
angular_velocity *= angular_damp_new;
650
651
linear_velocity += _inv_mass * force * p_step;
652
angular_velocity += _inv_inertia_tensor.xform(torque) * p_step;
653
}
654
655
if (continuous_cd) {
656
motion = linear_velocity * p_step;
657
do_motion = true;
658
}
659
}
660
661
applied_force = Vector3();
662
applied_torque = Vector3();
663
664
biased_angular_velocity = Vector3();
665
biased_linear_velocity = Vector3();
666
667
if (do_motion) { //shapes temporarily extend for raycast
668
_update_shapes_with_motion(motion);
669
}
670
671
contact_count = 0;
672
}
673
674
void GodotBody3D::integrate_velocities(real_t p_step) {
675
if (mode == PhysicsServer3D::BODY_MODE_STATIC) {
676
return;
677
}
678
679
ERR_FAIL_NULL(get_space());
680
681
if (fi_callback_data || body_state_callback.is_valid()) {
682
get_space()->body_add_to_state_query_list(&direct_state_query_list);
683
}
684
685
//apply axis lock linear
686
for (int i = 0; i < 3; i++) {
687
if (is_axis_locked((PhysicsServer3D::BodyAxis)(1 << i))) {
688
linear_velocity[i] = 0;
689
biased_linear_velocity[i] = 0;
690
new_transform.origin[i] = get_transform().origin[i];
691
}
692
}
693
//apply axis lock angular
694
for (int i = 0; i < 3; i++) {
695
if (is_axis_locked((PhysicsServer3D::BodyAxis)(1 << (i + 3)))) {
696
angular_velocity[i] = 0;
697
biased_angular_velocity[i] = 0;
698
}
699
}
700
701
if (mode == PhysicsServer3D::BODY_MODE_KINEMATIC) {
702
_set_transform(new_transform, false);
703
_set_inv_transform(new_transform.affine_inverse());
704
if (contacts.is_empty() && linear_velocity == Vector3() && angular_velocity == Vector3()) {
705
set_active(false); //stopped moving, deactivate
706
}
707
708
return;
709
}
710
711
Vector3 total_angular_velocity = angular_velocity + biased_angular_velocity;
712
713
real_t ang_vel = total_angular_velocity.length();
714
Transform3D transform_new = get_transform();
715
716
if (!Math::is_zero_approx(ang_vel)) {
717
Vector3 ang_vel_axis = total_angular_velocity / ang_vel;
718
Basis rot(ang_vel_axis, ang_vel * p_step);
719
Basis identity3(1, 0, 0, 0, 1, 0, 0, 0, 1);
720
transform_new.origin += ((identity3 - rot) * transform_new.basis).xform(center_of_mass_local);
721
transform_new.basis = rot * transform_new.basis;
722
transform_new.orthonormalize();
723
}
724
725
Vector3 total_linear_velocity = linear_velocity + biased_linear_velocity;
726
/*for(int i=0;i<3;i++) {
727
if (axis_lock&(1<<i)) {
728
transform_new.origin[i]=0.0;
729
}
730
}*/
731
732
transform_new.origin += total_linear_velocity * p_step;
733
734
_set_transform(transform_new);
735
_set_inv_transform(get_transform().inverse());
736
737
_update_transform_dependent();
738
}
739
740
void GodotBody3D::wakeup_neighbours() {
741
for (const KeyValue<GodotConstraint3D *, int> &E : constraint_map) {
742
const GodotConstraint3D *c = E.key;
743
GodotBody3D **n = c->get_body_ptr();
744
int bc = c->get_body_count();
745
746
for (int i = 0; i < bc; i++) {
747
if (i == E.value) {
748
continue;
749
}
750
GodotBody3D *b = n[i];
751
if (b->mode < PhysicsServer3D::BODY_MODE_RIGID) {
752
continue;
753
}
754
755
if (!b->is_active()) {
756
b->set_active(true);
757
}
758
}
759
}
760
}
761
762
void GodotBody3D::call_queries() {
763
Variant direct_state_variant = get_direct_state();
764
765
if (fi_callback_data) {
766
if (!fi_callback_data->callable.is_valid()) {
767
set_force_integration_callback(Callable());
768
} else {
769
const Variant *vp[2] = { &direct_state_variant, &fi_callback_data->udata };
770
771
Callable::CallError ce;
772
int argc = (fi_callback_data->udata.get_type() == Variant::NIL) ? 1 : 2;
773
Variant rv;
774
fi_callback_data->callable.callp(vp, argc, rv, ce);
775
}
776
}
777
778
if (body_state_callback.is_valid()) {
779
body_state_callback.call(direct_state_variant);
780
}
781
}
782
783
bool GodotBody3D::sleep_test(real_t p_step) {
784
if (mode == PhysicsServer3D::BODY_MODE_STATIC || mode == PhysicsServer3D::BODY_MODE_KINEMATIC) {
785
return true;
786
} else if (!can_sleep) {
787
return false;
788
}
789
790
ERR_FAIL_NULL_V(get_space(), true);
791
792
if (Math::abs(angular_velocity.length()) < get_space()->get_body_angular_velocity_sleep_threshold() && Math::abs(linear_velocity.length_squared()) < get_space()->get_body_linear_velocity_sleep_threshold() * get_space()->get_body_linear_velocity_sleep_threshold()) {
793
still_time += p_step;
794
795
return still_time > get_space()->get_body_time_to_sleep();
796
} else {
797
still_time = 0; //maybe this should be set to 0 on set_active?
798
return false;
799
}
800
}
801
802
void GodotBody3D::set_state_sync_callback(const Callable &p_callable) {
803
body_state_callback = p_callable;
804
}
805
806
void GodotBody3D::set_force_integration_callback(const Callable &p_callable, const Variant &p_udata) {
807
if (p_callable.is_valid()) {
808
if (!fi_callback_data) {
809
fi_callback_data = memnew(ForceIntegrationCallbackData);
810
}
811
fi_callback_data->callable = p_callable;
812
fi_callback_data->udata = p_udata;
813
} else if (fi_callback_data) {
814
memdelete(fi_callback_data);
815
fi_callback_data = nullptr;
816
}
817
}
818
819
GodotPhysicsDirectBodyState3D *GodotBody3D::get_direct_state() {
820
if (!direct_state) {
821
direct_state = memnew(GodotPhysicsDirectBodyState3D);
822
direct_state->body = this;
823
}
824
return direct_state;
825
}
826
827
GodotBody3D::GodotBody3D() :
828
GodotCollisionObject3D(TYPE_BODY),
829
active_list(this),
830
mass_properties_update_list(this),
831
direct_state_query_list(this) {
832
_set_static(false);
833
}
834
835
GodotBody3D::~GodotBody3D() {
836
if (fi_callback_data) {
837
memdelete(fi_callback_data);
838
}
839
if (direct_state) {
840
memdelete(direct_state);
841
}
842
}
843
844