Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/modules/godot_physics_3d/godot_soft_body_3d.cpp
10277 views
1
/**************************************************************************/
2
/* godot_soft_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_soft_body_3d.h"
32
33
#include "godot_space_3d.h"
34
35
#include "core/math/geometry_3d.h"
36
#include "servers/rendering_server.h"
37
38
// Based on Bullet soft body.
39
40
/*
41
Bullet Continuous Collision Detection and Physics Library
42
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
43
44
This software is provided 'as-is', without any express or implied warranty.
45
In no event will the authors be held liable for any damages arising from the use of this software.
46
Permission is granted to anyone to use this software for any purpose,
47
including commercial applications, and to alter it and redistribute it freely,
48
subject to the following restrictions:
49
50
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
51
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
52
3. This notice may not be removed or altered from any source distribution.
53
*/
54
///btSoftBody implementation by Nathanael Presson
55
56
GodotSoftBody3D::GodotSoftBody3D() :
57
GodotCollisionObject3D(TYPE_SOFT_BODY),
58
active_list(this) {
59
_set_static(false);
60
}
61
62
void GodotSoftBody3D::_shapes_changed() {
63
}
64
65
void GodotSoftBody3D::set_state(PhysicsServer3D::BodyState p_state, const Variant &p_variant) {
66
switch (p_state) {
67
case PhysicsServer3D::BODY_STATE_TRANSFORM: {
68
_set_transform(p_variant);
69
_set_inv_transform(get_transform().inverse());
70
71
apply_nodes_transform(get_transform());
72
73
} break;
74
case PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY: {
75
// Not supported.
76
ERR_FAIL_MSG("Linear velocity is not supported for Soft bodies.");
77
} break;
78
case PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY: {
79
ERR_FAIL_MSG("Angular velocity is not supported for Soft bodies.");
80
} break;
81
case PhysicsServer3D::BODY_STATE_SLEEPING: {
82
ERR_FAIL_MSG("Sleeping state is not supported for Soft bodies.");
83
} break;
84
case PhysicsServer3D::BODY_STATE_CAN_SLEEP: {
85
ERR_FAIL_MSG("Sleeping state is not supported for Soft bodies.");
86
} break;
87
}
88
}
89
90
Variant GodotSoftBody3D::get_state(PhysicsServer3D::BodyState p_state) const {
91
switch (p_state) {
92
case PhysicsServer3D::BODY_STATE_TRANSFORM: {
93
return get_transform();
94
} break;
95
case PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY: {
96
ERR_FAIL_V_MSG(Vector3(), "Linear velocity is not supported for Soft bodies.");
97
} break;
98
case PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY: {
99
ERR_FAIL_V_MSG(Vector3(), "Angular velocity is not supported for Soft bodies.");
100
} break;
101
case PhysicsServer3D::BODY_STATE_SLEEPING: {
102
ERR_FAIL_V_MSG(false, "Sleeping state is not supported for Soft bodies.");
103
} break;
104
case PhysicsServer3D::BODY_STATE_CAN_SLEEP: {
105
ERR_FAIL_V_MSG(false, "Sleeping state is not supported for Soft bodies.");
106
} break;
107
}
108
109
return Variant();
110
}
111
112
void GodotSoftBody3D::set_space(GodotSpace3D *p_space) {
113
if (get_space()) {
114
get_space()->soft_body_remove_from_active_list(&active_list);
115
116
deinitialize_shape();
117
}
118
119
_set_space(p_space);
120
121
if (get_space()) {
122
get_space()->soft_body_add_to_active_list(&active_list);
123
124
if (bounds != AABB()) {
125
initialize_shape(true);
126
}
127
}
128
}
129
130
void GodotSoftBody3D::set_mesh(RID p_mesh) {
131
destroy();
132
133
soft_mesh = p_mesh;
134
135
if (soft_mesh.is_null()) {
136
return;
137
}
138
139
// TODO: calling RenderingServer::mesh_surface_get_arrays() from the physics thread
140
// is not safe and can deadlock when physics/3d/run_on_separate_thread is enabled.
141
// This method blocks on the main thread to return data, but the main thread may be
142
// blocked waiting on us in PhysicsServer3D::sync().
143
Array arrays = RenderingServer::get_singleton()->mesh_surface_get_arrays(soft_mesh, 0);
144
ERR_FAIL_COND(arrays.is_empty());
145
146
const Vector<int> &indices = arrays[RenderingServer::ARRAY_INDEX];
147
const Vector<Vector3> &vertices = arrays[RenderingServer::ARRAY_VERTEX];
148
ERR_FAIL_COND_MSG(indices.is_empty(), "Soft body's mesh needs to have indices");
149
ERR_FAIL_COND_MSG(vertices.is_empty(), "Soft body's mesh needs to have vertices");
150
151
bool success = create_from_trimesh(indices, vertices);
152
if (!success) {
153
destroy();
154
}
155
}
156
157
void GodotSoftBody3D::update_rendering_server(PhysicsServer3DRenderingServerHandler *p_rendering_server_handler) {
158
if (soft_mesh.is_null()) {
159
return;
160
}
161
162
const uint32_t vertex_count = map_visual_to_physics.size();
163
for (uint32_t i = 0; i < vertex_count; ++i) {
164
const uint32_t node_index = map_visual_to_physics[i];
165
const Node &node = nodes[node_index];
166
167
p_rendering_server_handler->set_vertex(i, node.x);
168
p_rendering_server_handler->set_normal(i, node.n);
169
}
170
171
p_rendering_server_handler->set_aabb(bounds);
172
}
173
174
void GodotSoftBody3D::update_normals_and_centroids() {
175
for (Node &node : nodes) {
176
node.n = Vector3();
177
}
178
179
for (Face &face : faces) {
180
const Vector3 n = vec3_cross(face.n[0]->x - face.n[2]->x, face.n[0]->x - face.n[1]->x);
181
face.n[0]->n += n;
182
face.n[1]->n += n;
183
face.n[2]->n += n;
184
face.normal = n;
185
face.normal.normalize();
186
face.centroid = 0.33333333333 * (face.n[0]->x + face.n[1]->x + face.n[2]->x);
187
}
188
189
for (Node &node : nodes) {
190
real_t len = node.n.length();
191
if (len > CMP_EPSILON) {
192
node.n /= len;
193
}
194
}
195
}
196
197
void GodotSoftBody3D::update_bounds() {
198
AABB prev_bounds = bounds;
199
prev_bounds.grow_by(collision_margin);
200
201
bounds = AABB();
202
203
const uint32_t nodes_count = nodes.size();
204
if (nodes_count == 0) {
205
deinitialize_shape();
206
return;
207
}
208
209
bool first = true;
210
bool moved = false;
211
for (uint32_t node_index = 0; node_index < nodes_count; ++node_index) {
212
const Node &node = nodes[node_index];
213
if (!prev_bounds.has_point(node.x)) {
214
moved = true;
215
}
216
if (first) {
217
bounds.position = node.x;
218
first = false;
219
} else {
220
bounds.expand_to(node.x);
221
}
222
}
223
224
if (get_space()) {
225
initialize_shape(moved);
226
}
227
}
228
229
void GodotSoftBody3D::update_constants() {
230
reset_link_rest_lengths();
231
update_link_constants();
232
update_area();
233
}
234
235
void GodotSoftBody3D::update_area() {
236
int i, ni;
237
238
// Face area.
239
for (Face &face : faces) {
240
const Vector3 &x0 = face.n[0]->x;
241
const Vector3 &x1 = face.n[1]->x;
242
const Vector3 &x2 = face.n[2]->x;
243
244
const Vector3 a = x1 - x0;
245
const Vector3 b = x2 - x0;
246
const Vector3 cr = vec3_cross(a, b);
247
face.ra = cr.length() * 0.5;
248
}
249
250
// Node area.
251
LocalVector<int> counts;
252
if (nodes.size() > 0) {
253
counts.resize(nodes.size());
254
memset(counts.ptr(), 0, counts.size() * sizeof(int));
255
}
256
257
for (Node &node : nodes) {
258
node.area = 0.0;
259
}
260
261
for (const Face &face : faces) {
262
for (int j = 0; j < 3; ++j) {
263
const int index = (int)(face.n[j] - &nodes[0]);
264
counts[index]++;
265
face.n[j]->area += Math::abs(face.ra);
266
}
267
}
268
269
for (i = 0, ni = nodes.size(); i < ni; ++i) {
270
if (counts[i] > 0) {
271
nodes[i].area /= (real_t)counts[i];
272
} else {
273
nodes[i].area = 0.0;
274
}
275
}
276
}
277
278
void GodotSoftBody3D::reset_link_rest_lengths() {
279
float multiplier = 1.0 - shrinking_factor;
280
for (Link &link : links) {
281
link.rl = (link.n[0]->x - link.n[1]->x).length();
282
link.rl *= multiplier;
283
link.c1 = link.rl * link.rl;
284
}
285
}
286
287
void GodotSoftBody3D::update_link_constants() {
288
real_t inv_linear_stiffness = 1.0 / linear_stiffness;
289
for (Link &link : links) {
290
link.c0 = (link.n[0]->im + link.n[1]->im) * inv_linear_stiffness;
291
}
292
}
293
294
void GodotSoftBody3D::apply_nodes_transform(const Transform3D &p_transform) {
295
if (soft_mesh.is_null()) {
296
return;
297
}
298
299
uint32_t node_count = nodes.size();
300
Vector3 leaf_size = Vector3(collision_margin, collision_margin, collision_margin) * 2.0;
301
for (uint32_t node_index = 0; node_index < node_count; ++node_index) {
302
Node &node = nodes[node_index];
303
304
node.x = p_transform.xform(node.x);
305
node.q = node.x;
306
node.v = Vector3();
307
node.bv = Vector3();
308
309
AABB node_aabb(node.x, leaf_size);
310
node_tree.update(node.leaf, node_aabb);
311
}
312
313
face_tree.clear();
314
315
update_normals_and_centroids();
316
update_bounds();
317
update_constants();
318
}
319
320
Vector3 GodotSoftBody3D::get_vertex_position(int p_index) const {
321
ERR_FAIL_COND_V(p_index < 0, Vector3());
322
323
if (soft_mesh.is_null()) {
324
return Vector3();
325
}
326
327
ERR_FAIL_COND_V(p_index >= (int)map_visual_to_physics.size(), Vector3());
328
uint32_t node_index = map_visual_to_physics[p_index];
329
330
ERR_FAIL_COND_V(node_index >= nodes.size(), Vector3());
331
return nodes[node_index].x;
332
}
333
334
void GodotSoftBody3D::set_vertex_position(int p_index, const Vector3 &p_position) {
335
ERR_FAIL_COND(p_index < 0);
336
337
if (soft_mesh.is_null()) {
338
return;
339
}
340
341
ERR_FAIL_COND(p_index >= (int)map_visual_to_physics.size());
342
uint32_t node_index = map_visual_to_physics[p_index];
343
344
ERR_FAIL_COND(node_index >= nodes.size());
345
Node &node = nodes[node_index];
346
node.q = node.x;
347
node.x = p_position;
348
}
349
350
void GodotSoftBody3D::pin_vertex(int p_index) {
351
ERR_FAIL_COND(p_index < 0);
352
353
if (is_vertex_pinned(p_index)) {
354
return;
355
}
356
357
pinned_vertices.push_back(p_index);
358
359
if (!soft_mesh.is_null()) {
360
ERR_FAIL_COND(p_index >= (int)map_visual_to_physics.size());
361
uint32_t node_index = map_visual_to_physics[p_index];
362
363
ERR_FAIL_COND(node_index >= nodes.size());
364
Node &node = nodes[node_index];
365
node.im = 0.0;
366
}
367
}
368
369
void GodotSoftBody3D::unpin_vertex(int p_index) {
370
ERR_FAIL_COND(p_index < 0);
371
372
uint32_t pinned_count = pinned_vertices.size();
373
for (uint32_t i = 0; i < pinned_count; ++i) {
374
if (p_index == pinned_vertices[i]) {
375
pinned_vertices.remove_at(i);
376
377
if (!soft_mesh.is_null()) {
378
ERR_FAIL_COND(p_index >= (int)map_visual_to_physics.size());
379
uint32_t node_index = map_visual_to_physics[p_index];
380
381
ERR_FAIL_COND(node_index >= nodes.size());
382
real_t inv_node_mass = nodes.size() * inv_total_mass;
383
384
Node &node = nodes[node_index];
385
node.im = inv_node_mass;
386
}
387
388
return;
389
}
390
}
391
}
392
393
void GodotSoftBody3D::unpin_all_vertices() {
394
if (!soft_mesh.is_null()) {
395
real_t inv_node_mass = nodes.size() * inv_total_mass;
396
uint32_t pinned_count = pinned_vertices.size();
397
for (uint32_t i = 0; i < pinned_count; ++i) {
398
int pinned_vertex = pinned_vertices[i];
399
400
ERR_CONTINUE(pinned_vertex >= (int)map_visual_to_physics.size());
401
uint32_t node_index = map_visual_to_physics[pinned_vertex];
402
403
ERR_CONTINUE(node_index >= nodes.size());
404
Node &node = nodes[node_index];
405
node.im = inv_node_mass;
406
}
407
}
408
409
pinned_vertices.clear();
410
}
411
412
bool GodotSoftBody3D::is_vertex_pinned(int p_index) const {
413
ERR_FAIL_COND_V(p_index < 0, false);
414
415
uint32_t pinned_count = pinned_vertices.size();
416
for (uint32_t i = 0; i < pinned_count; ++i) {
417
if (p_index == pinned_vertices[i]) {
418
return true;
419
}
420
}
421
422
return false;
423
}
424
425
uint32_t GodotSoftBody3D::get_node_count() const {
426
return nodes.size();
427
}
428
429
real_t GodotSoftBody3D::get_node_inv_mass(uint32_t p_node_index) const {
430
ERR_FAIL_UNSIGNED_INDEX_V(p_node_index, nodes.size(), 0.0);
431
return nodes[p_node_index].im;
432
}
433
434
Vector3 GodotSoftBody3D::get_node_position(uint32_t p_node_index) const {
435
ERR_FAIL_UNSIGNED_INDEX_V(p_node_index, nodes.size(), Vector3());
436
return nodes[p_node_index].x;
437
}
438
439
Vector3 GodotSoftBody3D::get_node_velocity(uint32_t p_node_index) const {
440
ERR_FAIL_UNSIGNED_INDEX_V(p_node_index, nodes.size(), Vector3());
441
return nodes[p_node_index].v;
442
}
443
444
Vector3 GodotSoftBody3D::get_node_biased_velocity(uint32_t p_node_index) const {
445
ERR_FAIL_UNSIGNED_INDEX_V(p_node_index, nodes.size(), Vector3());
446
return nodes[p_node_index].bv;
447
}
448
449
void GodotSoftBody3D::apply_node_impulse(uint32_t p_node_index, const Vector3 &p_impulse) {
450
ERR_FAIL_UNSIGNED_INDEX(p_node_index, nodes.size());
451
Node &node = nodes[p_node_index];
452
node.v += p_impulse * node.im;
453
}
454
455
void GodotSoftBody3D::apply_node_force(uint32_t p_node_index, const Vector3 &p_force) {
456
ERR_FAIL_UNSIGNED_INDEX(p_node_index, nodes.size());
457
Node &node = nodes[p_node_index];
458
node.f += p_force;
459
}
460
461
void GodotSoftBody3D::apply_central_impulse(const Vector3 &p_impulse) {
462
const Vector3 impulse = p_impulse / nodes.size();
463
for (Node &node : nodes) {
464
if (node.im > 0) {
465
node.v += impulse * node.im;
466
}
467
}
468
}
469
470
void GodotSoftBody3D::apply_central_force(const Vector3 &p_force) {
471
const Vector3 force = p_force / nodes.size();
472
for (Node &node : nodes) {
473
if (node.im > 0) {
474
node.f += force;
475
}
476
}
477
}
478
479
void GodotSoftBody3D::apply_node_bias_impulse(uint32_t p_node_index, const Vector3 &p_impulse) {
480
ERR_FAIL_UNSIGNED_INDEX(p_node_index, nodes.size());
481
Node &node = nodes[p_node_index];
482
node.bv += p_impulse * node.im;
483
}
484
485
uint32_t GodotSoftBody3D::get_face_count() const {
486
return faces.size();
487
}
488
489
void GodotSoftBody3D::get_face_points(uint32_t p_face_index, Vector3 &r_point_1, Vector3 &r_point_2, Vector3 &r_point_3) const {
490
ERR_FAIL_UNSIGNED_INDEX(p_face_index, faces.size());
491
const Face &face = faces[p_face_index];
492
r_point_1 = face.n[0]->x;
493
r_point_2 = face.n[1]->x;
494
r_point_3 = face.n[2]->x;
495
}
496
497
Vector3 GodotSoftBody3D::get_face_normal(uint32_t p_face_index) const {
498
ERR_FAIL_UNSIGNED_INDEX_V(p_face_index, faces.size(), Vector3());
499
return faces[p_face_index].normal;
500
}
501
502
bool GodotSoftBody3D::create_from_trimesh(const Vector<int> &p_indices, const Vector<Vector3> &p_vertices) {
503
ERR_FAIL_COND_V(p_indices.is_empty(), false);
504
ERR_FAIL_COND_V(p_vertices.is_empty(), false);
505
506
uint32_t node_count = 0;
507
LocalVector<Vector3> vertices;
508
const int visual_vertex_count(p_vertices.size());
509
510
LocalVector<int> triangles;
511
const uint32_t triangle_count(p_indices.size() / 3);
512
triangles.resize(triangle_count * 3);
513
514
// Merge all overlapping vertices and create a map of physical vertices to visual vertices.
515
{
516
// Process vertices.
517
{
518
uint32_t vertex_count = 0;
519
HashMap<Vector3, uint32_t> unique_vertices;
520
521
vertices.resize(visual_vertex_count);
522
map_visual_to_physics.resize(visual_vertex_count);
523
524
for (int visual_vertex_index = 0; visual_vertex_index < visual_vertex_count; ++visual_vertex_index) {
525
const Vector3 &vertex = p_vertices[visual_vertex_index];
526
527
HashMap<Vector3, uint32_t>::Iterator e = unique_vertices.find(vertex);
528
uint32_t vertex_id;
529
if (e) {
530
// Already existing.
531
vertex_id = e->value;
532
} else {
533
// Create new one.
534
vertex_id = vertex_count++;
535
unique_vertices[vertex] = vertex_id;
536
vertices[vertex_id] = vertex;
537
}
538
539
map_visual_to_physics[visual_vertex_index] = vertex_id;
540
}
541
542
vertices.resize(vertex_count);
543
}
544
545
// Process triangles.
546
{
547
for (uint32_t triangle_index = 0; triangle_index < triangle_count; ++triangle_index) {
548
for (int i = 0; i < 3; ++i) {
549
int visual_index = 3 * triangle_index + i;
550
int physics_index = map_visual_to_physics[p_indices[visual_index]];
551
triangles[visual_index] = physics_index;
552
node_count = MAX((int)node_count, physics_index);
553
}
554
}
555
}
556
}
557
558
++node_count;
559
560
// Create nodes from vertices.
561
nodes.resize(node_count);
562
real_t inv_node_mass = node_count * inv_total_mass;
563
Vector3 leaf_size = Vector3(collision_margin, collision_margin, collision_margin) * 2.0;
564
for (uint32_t i = 0; i < node_count; ++i) {
565
Node &node = nodes[i];
566
node.s = vertices[i];
567
node.x = node.s;
568
node.q = node.s;
569
node.im = inv_node_mass;
570
571
AABB node_aabb(node.x, leaf_size);
572
node.leaf = node_tree.insert(node_aabb, &node);
573
574
node.index = i;
575
}
576
577
// Create links and faces from triangles.
578
LocalVector<bool> chks;
579
chks.resize(node_count * node_count);
580
memset(chks.ptr(), 0, chks.size() * sizeof(bool));
581
582
for (uint32_t i = 0; i < triangle_count * 3; i += 3) {
583
const int idx[] = { triangles[i], triangles[i + 1], triangles[i + 2] };
584
585
for (int j = 2, k = 0; k < 3; j = k++) {
586
int chk = idx[k] * node_count + idx[j];
587
if (!chks[chk]) {
588
chks[chk] = true;
589
int inv_chk = idx[j] * node_count + idx[k];
590
chks[inv_chk] = true;
591
592
append_link(idx[j], idx[k]);
593
}
594
}
595
596
append_face(idx[0], idx[1], idx[2]);
597
}
598
599
// Set pinned nodes.
600
uint32_t pinned_count = pinned_vertices.size();
601
for (uint32_t i = 0; i < pinned_count; ++i) {
602
int pinned_vertex = pinned_vertices[i];
603
604
ERR_CONTINUE(pinned_vertex >= visual_vertex_count);
605
uint32_t node_index = map_visual_to_physics[pinned_vertex];
606
607
ERR_CONTINUE(node_index >= node_count);
608
Node &node = nodes[node_index];
609
node.im = 0.0;
610
}
611
612
generate_bending_constraints(2);
613
reoptimize_link_order();
614
615
update_constants();
616
update_normals_and_centroids();
617
update_bounds();
618
619
return true;
620
}
621
622
void GodotSoftBody3D::generate_bending_constraints(int p_distance) {
623
uint32_t i, j;
624
625
if (p_distance > 1) {
626
// Build graph.
627
const uint32_t n = nodes.size();
628
const unsigned inf = (~(unsigned)0) >> 1;
629
const uint32_t adj_size = n * n;
630
unsigned *adj = memnew_arr(unsigned, adj_size);
631
632
#define IDX(_x_, _y_) ((_y_) * n + (_x_))
633
for (j = 0; j < n; ++j) {
634
for (i = 0; i < n; ++i) {
635
int idx_ij = j * n + i;
636
int idx_ji = i * n + j;
637
if (i != j) {
638
adj[idx_ij] = adj[idx_ji] = inf;
639
} else {
640
adj[idx_ij] = adj[idx_ji] = 0;
641
}
642
}
643
}
644
for (Link &link : links) {
645
const int ia = (int)(link.n[0] - &nodes[0]);
646
const int ib = (int)(link.n[1] - &nodes[0]);
647
int idx = ib * n + ia;
648
int idx_inv = ia * n + ib;
649
adj[idx] = 1;
650
adj[idx_inv] = 1;
651
}
652
653
// Special optimized case for distance == 2.
654
if (p_distance == 2) {
655
LocalVector<LocalVector<int>> node_links;
656
657
// Build node links.
658
node_links.resize(nodes.size());
659
660
for (Link &link : links) {
661
const int ia = (int)(link.n[0] - &nodes[0]);
662
const int ib = (int)(link.n[1] - &nodes[0]);
663
if (!node_links[ia].has(ib)) {
664
node_links[ia].push_back(ib);
665
}
666
667
if (!node_links[ib].has(ia)) {
668
node_links[ib].push_back(ia);
669
}
670
}
671
for (uint32_t ii = 0; ii < node_links.size(); ii++) {
672
for (uint32_t jj = 0; jj < node_links[ii].size(); jj++) {
673
int k = node_links[ii][jj];
674
for (const int &l : node_links[k]) {
675
if ((int)ii != l) {
676
int idx_ik = k * n + ii;
677
int idx_kj = l * n + k;
678
const unsigned sum = adj[idx_ik] + adj[idx_kj];
679
ERR_FAIL_COND(sum != 2);
680
int idx_ij = l * n + ii;
681
if (adj[idx_ij] > sum) {
682
int idx_ji = l * n + ii;
683
adj[idx_ij] = adj[idx_ji] = sum;
684
}
685
}
686
}
687
}
688
}
689
} else {
690
// Generic Floyd's algorithm.
691
for (uint32_t k = 0; k < n; ++k) {
692
for (j = 0; j < n; ++j) {
693
for (i = j + 1; i < n; ++i) {
694
int idx_ik = k * n + i;
695
int idx_kj = j * n + k;
696
const unsigned sum = adj[idx_ik] + adj[idx_kj];
697
int idx_ij = j * n + i;
698
if (adj[idx_ij] > sum) {
699
int idx_ji = j * n + i;
700
adj[idx_ij] = adj[idx_ji] = sum;
701
}
702
}
703
}
704
}
705
}
706
707
// Build links.
708
for (j = 0; j < n; ++j) {
709
for (i = j + 1; i < n; ++i) {
710
int idx_ij = j * n + i;
711
if (adj[idx_ij] == (unsigned)p_distance) {
712
append_link(i, j);
713
}
714
}
715
}
716
memdelete_arr(adj);
717
}
718
}
719
720
//===================================================================
721
//
722
//
723
// This function takes in a list of interdependent Links and tries
724
// to maximize the distance between calculation
725
// of dependent links. This increases the amount of parallelism that can
726
// be exploited by out-of-order instruction processors with large but
727
// (inevitably) finite instruction windows.
728
//
729
//===================================================================
730
731
// A small structure to track lists of dependent link calculations.
732
class LinkDeps {
733
public:
734
// A link calculation that is dependent on this one.
735
// Positive values = "input A" while negative values = "input B".
736
int value;
737
// Next dependence in the list.
738
LinkDeps *next;
739
};
740
typedef LinkDeps *LinkDepsPtr;
741
742
void GodotSoftBody3D::reoptimize_link_order() {
743
const int reop_not_dependent = -1;
744
const int reop_node_complete = -2;
745
746
uint32_t link_count = links.size();
747
uint32_t node_count = nodes.size();
748
749
if (link_count < 1 || node_count < 2) {
750
return;
751
}
752
753
uint32_t i;
754
Link *lr;
755
int ar, br;
756
Node *node0 = &(nodes[0]);
757
Node *node1 = &(nodes[1]);
758
LinkDepsPtr link_dep;
759
int ready_list_head, ready_list_tail, link_num, link_dep_frees, dep_link;
760
761
// Allocate temporary buffers.
762
int *node_written_at = memnew_arr(int, node_count + 1); // What link calculation produced this node's current values?
763
int *link_dep_A = memnew_arr(int, link_count); // Link calculation input is dependent upon prior calculation #N
764
int *link_dep_B = memnew_arr(int, link_count);
765
int *ready_list = memnew_arr(int, link_count); // List of ready-to-process link calculations (# of links, maximum)
766
LinkDeps *link_dep_free_list = memnew_arr(LinkDeps, 2 * link_count); // Dependent-on-me list elements (2x# of links, maximum)
767
LinkDepsPtr *link_dep_list_starts = memnew_arr(LinkDepsPtr, link_count); // Start nodes of dependent-on-me lists, one for each link
768
769
// Copy the original, unsorted links to a side buffer.
770
Link *link_buffer = memnew_arr(Link, link_count);
771
memcpy(link_buffer, &(links[0]), sizeof(Link) * link_count);
772
773
// Clear out the node setup and ready list.
774
for (i = 0; i < node_count + 1; i++) {
775
node_written_at[i] = reop_not_dependent;
776
}
777
for (i = 0; i < link_count; i++) {
778
link_dep_list_starts[i] = nullptr;
779
}
780
ready_list_head = ready_list_tail = link_dep_frees = 0;
781
782
// Initial link analysis to set up data structures.
783
for (i = 0; i < link_count; i++) {
784
// Note which prior link calculations we are dependent upon & build up dependence lists.
785
lr = &(links[i]);
786
ar = (lr->n[0] - node0) / (node1 - node0);
787
br = (lr->n[1] - node0) / (node1 - node0);
788
if (node_written_at[ar] > reop_not_dependent) {
789
link_dep_A[i] = node_written_at[ar];
790
link_dep = &link_dep_free_list[link_dep_frees++];
791
link_dep->value = i;
792
link_dep->next = link_dep_list_starts[node_written_at[ar]];
793
link_dep_list_starts[node_written_at[ar]] = link_dep;
794
} else {
795
link_dep_A[i] = reop_not_dependent;
796
}
797
if (node_written_at[br] > reop_not_dependent) {
798
link_dep_B[i] = node_written_at[br];
799
link_dep = &link_dep_free_list[link_dep_frees++];
800
link_dep->value = -(int)(i + 1);
801
link_dep->next = link_dep_list_starts[node_written_at[br]];
802
link_dep_list_starts[node_written_at[br]] = link_dep;
803
} else {
804
link_dep_B[i] = reop_not_dependent;
805
}
806
807
// Add this link to the initial ready list, if it is not dependent on any other links.
808
if ((link_dep_A[i] == reop_not_dependent) && (link_dep_B[i] == reop_not_dependent)) {
809
ready_list[ready_list_tail++] = i;
810
link_dep_A[i] = link_dep_B[i] = reop_node_complete; // Probably not needed now.
811
}
812
813
// Update the nodes to mark which ones are calculated by this link.
814
node_written_at[ar] = node_written_at[br] = i;
815
}
816
817
// Process the ready list and create the sorted list of links:
818
// -- By treating the ready list as a queue, we maximize the distance between any
819
// inter-dependent node calculations.
820
// -- All other (non-related) nodes in the ready list will automatically be inserted
821
// in between each set of inter-dependent link calculations by this loop.
822
i = 0;
823
while (ready_list_head != ready_list_tail) {
824
// Use ready list to select the next link to process.
825
link_num = ready_list[ready_list_head++];
826
// Copy the next-to-calculate link back into the original link array.
827
links[i++] = link_buffer[link_num];
828
829
// Free up any link inputs that are dependent on this one.
830
link_dep = link_dep_list_starts[link_num];
831
while (link_dep) {
832
dep_link = link_dep->value;
833
if (dep_link >= 0) {
834
link_dep_A[dep_link] = reop_not_dependent;
835
} else {
836
dep_link = -dep_link - 1;
837
link_dep_B[dep_link] = reop_not_dependent;
838
}
839
// Add this dependent link calculation to the ready list if *both* inputs are clear.
840
if ((link_dep_A[dep_link] == reop_not_dependent) && (link_dep_B[dep_link] == reop_not_dependent)) {
841
ready_list[ready_list_tail++] = dep_link;
842
link_dep_A[dep_link] = link_dep_B[dep_link] = reop_node_complete; // Probably not needed now.
843
}
844
link_dep = link_dep->next;
845
}
846
}
847
848
// Delete the temporary buffers.
849
memdelete_arr(node_written_at);
850
memdelete_arr(link_dep_A);
851
memdelete_arr(link_dep_B);
852
memdelete_arr(ready_list);
853
memdelete_arr(link_dep_free_list);
854
memdelete_arr(link_dep_list_starts);
855
memdelete_arr(link_buffer);
856
}
857
858
void GodotSoftBody3D::append_link(uint32_t p_node1, uint32_t p_node2) {
859
if (p_node1 == p_node2) {
860
return;
861
}
862
863
Node *node1 = &nodes[p_node1];
864
Node *node2 = &nodes[p_node2];
865
866
Link link;
867
link.n[0] = node1;
868
link.n[1] = node2;
869
link.rl = (node1->x - node2->x).length();
870
link.rl *= 1.0 - shrinking_factor;
871
872
links.push_back(link);
873
}
874
875
void GodotSoftBody3D::append_face(uint32_t p_node1, uint32_t p_node2, uint32_t p_node3) {
876
if (p_node1 == p_node2) {
877
return;
878
}
879
if (p_node1 == p_node3) {
880
return;
881
}
882
if (p_node2 == p_node3) {
883
return;
884
}
885
886
Node *node1 = &nodes[p_node1];
887
Node *node2 = &nodes[p_node2];
888
Node *node3 = &nodes[p_node3];
889
890
Face face;
891
face.n[0] = node1;
892
face.n[1] = node2;
893
face.n[2] = node3;
894
895
face.index = faces.size();
896
897
faces.push_back(face);
898
}
899
900
void GodotSoftBody3D::set_iteration_count(int p_val) {
901
iteration_count = p_val;
902
}
903
904
void GodotSoftBody3D::set_total_mass(real_t p_val) {
905
ERR_FAIL_COND(p_val < 0.0);
906
907
inv_total_mass = 1.0 / p_val;
908
real_t mass_factor = total_mass * inv_total_mass;
909
total_mass = p_val;
910
911
uint32_t node_count = nodes.size();
912
for (uint32_t node_index = 0; node_index < node_count; ++node_index) {
913
Node &node = nodes[node_index];
914
node.im *= mass_factor;
915
}
916
917
update_constants();
918
}
919
920
void GodotSoftBody3D::set_collision_margin(real_t p_val) {
921
collision_margin = p_val;
922
}
923
924
void GodotSoftBody3D::set_linear_stiffness(real_t p_val) {
925
linear_stiffness = p_val;
926
}
927
928
void GodotSoftBody3D::set_shrinking_factor(real_t p_val) {
929
shrinking_factor = p_val;
930
}
931
932
void GodotSoftBody3D::set_pressure_coefficient(real_t p_val) {
933
pressure_coefficient = p_val;
934
}
935
936
void GodotSoftBody3D::set_damping_coefficient(real_t p_val) {
937
damping_coefficient = p_val;
938
}
939
940
void GodotSoftBody3D::set_drag_coefficient(real_t p_val) {
941
drag_coefficient = p_val;
942
}
943
944
void GodotSoftBody3D::add_velocity(const Vector3 &p_velocity) {
945
for (Node &node : nodes) {
946
if (node.im > 0) {
947
node.v += p_velocity;
948
}
949
}
950
}
951
952
void GodotSoftBody3D::apply_forces(const LocalVector<GodotArea3D *> &p_wind_areas) {
953
if (nodes.is_empty()) {
954
return;
955
}
956
957
int32_t j;
958
959
real_t volume = 0.0;
960
const Vector3 &org = nodes[0].x;
961
962
// Iterate over faces (try not to iterate elsewhere if possible).
963
for (const Face &face : faces) {
964
Vector3 wind_force(0, 0, 0);
965
966
// Compute volume.
967
volume += vec3_dot(face.n[0]->x - org, vec3_cross(face.n[1]->x - org, face.n[2]->x - org));
968
969
// Compute nodal forces from area winds.
970
if (!p_wind_areas.is_empty()) {
971
for (const GodotArea3D *area : p_wind_areas) {
972
wind_force += _compute_area_windforce(area, &face);
973
}
974
975
for (j = 0; j < 3; j++) {
976
Node *current_node = face.n[j];
977
current_node->f += wind_force;
978
}
979
}
980
}
981
volume /= 6.0;
982
983
// Apply nodal pressure forces.
984
if (pressure_coefficient > CMP_EPSILON) {
985
real_t ivolumetp = 1.0 / Math::abs(volume) * pressure_coefficient;
986
for (Node &node : nodes) {
987
if (node.im > 0) {
988
node.f += node.n * (node.area * ivolumetp);
989
}
990
}
991
}
992
}
993
994
Vector3 GodotSoftBody3D::_compute_area_windforce(const GodotArea3D *p_area, const Face *p_face) {
995
real_t wfm = p_area->get_wind_force_magnitude();
996
real_t waf = p_area->get_wind_attenuation_factor();
997
const Vector3 &wd = p_area->get_wind_direction();
998
const Vector3 &ws = p_area->get_wind_source();
999
real_t projection_on_tri_normal = vec3_dot(p_face->normal, wd);
1000
real_t projection_toward_centroid = vec3_dot(p_face->centroid - ws, wd);
1001
real_t attenuation_over_distance = std::pow(projection_toward_centroid, -waf);
1002
real_t nodal_force_magnitude = wfm * 0.33333333333 * p_face->ra * projection_on_tri_normal * attenuation_over_distance;
1003
return nodal_force_magnitude * p_face->normal;
1004
}
1005
1006
void GodotSoftBody3D::predict_motion(real_t p_delta) {
1007
const real_t inv_delta = 1.0 / p_delta;
1008
1009
ERR_FAIL_NULL(get_space());
1010
1011
bool gravity_done = false;
1012
Vector3 gravity;
1013
1014
LocalVector<GodotArea3D *> wind_areas;
1015
1016
int ac = areas.size();
1017
if (ac) {
1018
areas.sort();
1019
const AreaCMP *aa = &areas[0];
1020
for (int i = ac - 1; i >= 0; i--) {
1021
if (!gravity_done) {
1022
PhysicsServer3D::AreaSpaceOverrideMode area_gravity_mode = (PhysicsServer3D::AreaSpaceOverrideMode)(int)aa[i].area->get_param(PhysicsServer3D::AREA_PARAM_GRAVITY_OVERRIDE_MODE);
1023
if (area_gravity_mode != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) {
1024
Vector3 area_gravity;
1025
aa[i].area->compute_gravity(get_transform().get_origin(), area_gravity);
1026
switch (area_gravity_mode) {
1027
case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE:
1028
case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: {
1029
gravity += area_gravity;
1030
gravity_done = area_gravity_mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE;
1031
} break;
1032
case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE:
1033
case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: {
1034
gravity = area_gravity;
1035
gravity_done = area_gravity_mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE;
1036
} break;
1037
default: {
1038
}
1039
}
1040
}
1041
}
1042
1043
if (aa[i].area->get_wind_force_magnitude() > CMP_EPSILON) {
1044
wind_areas.push_back(aa[i].area);
1045
}
1046
}
1047
}
1048
1049
// Add default gravity and damping from space area.
1050
if (!gravity_done) {
1051
GodotArea3D *default_area = get_space()->get_default_area();
1052
ERR_FAIL_NULL(default_area);
1053
1054
Vector3 default_gravity;
1055
default_area->compute_gravity(get_transform().get_origin(), default_gravity);
1056
gravity += default_gravity;
1057
}
1058
1059
// Apply forces.
1060
add_velocity(gravity * p_delta);
1061
if (pressure_coefficient > CMP_EPSILON || !wind_areas.is_empty()) {
1062
apply_forces(wind_areas);
1063
}
1064
1065
// Avoid soft body from 'exploding' so use some upper threshold of maximum motion
1066
// that a node can travel per frame.
1067
const real_t max_displacement = 1000.0;
1068
real_t clamp_delta_v = max_displacement * inv_delta;
1069
1070
// Integrate.
1071
for (Node &node : nodes) {
1072
node.q = node.x;
1073
Vector3 delta_v = node.f * node.im * p_delta;
1074
for (int c = 0; c < 3; c++) {
1075
delta_v[c] = CLAMP(delta_v[c], -clamp_delta_v, clamp_delta_v);
1076
}
1077
node.v += delta_v;
1078
node.x += node.v * p_delta;
1079
node.f = Vector3();
1080
}
1081
1082
// Bounds and tree update.
1083
update_bounds();
1084
1085
// Node tree update.
1086
for (const Node &node : nodes) {
1087
AABB node_aabb(node.x, Vector3());
1088
node_aabb.expand_to(node.x + node.v * p_delta);
1089
node_aabb.grow_by(collision_margin);
1090
1091
node_tree.update(node.leaf, node_aabb);
1092
}
1093
1094
// Face tree update.
1095
if (!face_tree.is_empty()) {
1096
update_face_tree(p_delta);
1097
}
1098
1099
// Optimize node tree.
1100
node_tree.optimize_incremental(1);
1101
face_tree.optimize_incremental(1);
1102
}
1103
1104
void GodotSoftBody3D::solve_constraints(real_t p_delta) {
1105
const real_t inv_delta = 1.0 / p_delta;
1106
1107
for (Link &link : links) {
1108
link.c3 = link.n[1]->q - link.n[0]->q;
1109
link.c2 = 1 / (link.c3.length_squared() * link.c0);
1110
}
1111
1112
// Solve velocities.
1113
for (Node &node : nodes) {
1114
node.x = node.q + node.v * p_delta;
1115
}
1116
1117
// Solve positions.
1118
for (int isolve = 0; isolve < iteration_count; ++isolve) {
1119
const real_t ti = isolve / (real_t)iteration_count;
1120
solve_links(1.0, ti);
1121
}
1122
const real_t vc = (1.0 - damping_coefficient) * inv_delta;
1123
for (Node &node : nodes) {
1124
node.x += node.bv * p_delta;
1125
node.bv = Vector3();
1126
1127
node.v = (node.x - node.q) * vc;
1128
1129
node.q = node.x;
1130
}
1131
1132
update_normals_and_centroids();
1133
}
1134
1135
void GodotSoftBody3D::solve_links(real_t kst, real_t ti) {
1136
for (Link &link : links) {
1137
if (link.c0 > 0) {
1138
Node &node_a = *link.n[0];
1139
Node &node_b = *link.n[1];
1140
const Vector3 del = node_b.x - node_a.x;
1141
const real_t len = del.length_squared();
1142
if (link.c1 + len > CMP_EPSILON) {
1143
const real_t k = ((link.c1 - len) / (link.c0 * (link.c1 + len))) * kst;
1144
node_a.x -= del * (k * node_a.im);
1145
node_b.x += del * (k * node_b.im);
1146
}
1147
}
1148
}
1149
}
1150
1151
struct AABBQueryResult {
1152
const GodotSoftBody3D *soft_body = nullptr;
1153
void *userdata = nullptr;
1154
GodotSoftBody3D::QueryResultCallback result_callback = nullptr;
1155
1156
_FORCE_INLINE_ bool operator()(void *p_data) {
1157
return result_callback(soft_body->get_node_index(p_data), userdata);
1158
}
1159
};
1160
1161
void GodotSoftBody3D::query_aabb(const AABB &p_aabb, GodotSoftBody3D::QueryResultCallback p_result_callback, void *p_userdata) {
1162
AABBQueryResult query_result;
1163
query_result.soft_body = this;
1164
query_result.result_callback = p_result_callback;
1165
query_result.userdata = p_userdata;
1166
1167
node_tree.aabb_query(p_aabb, query_result);
1168
}
1169
1170
struct RayQueryResult {
1171
const GodotSoftBody3D *soft_body = nullptr;
1172
void *userdata = nullptr;
1173
GodotSoftBody3D::QueryResultCallback result_callback = nullptr;
1174
1175
_FORCE_INLINE_ bool operator()(void *p_data) {
1176
return result_callback(soft_body->get_face_index(p_data), userdata);
1177
}
1178
};
1179
1180
void GodotSoftBody3D::query_ray(const Vector3 &p_from, const Vector3 &p_to, GodotSoftBody3D::QueryResultCallback p_result_callback, void *p_userdata) {
1181
if (face_tree.is_empty()) {
1182
initialize_face_tree();
1183
}
1184
1185
RayQueryResult query_result;
1186
query_result.soft_body = this;
1187
query_result.result_callback = p_result_callback;
1188
query_result.userdata = p_userdata;
1189
1190
face_tree.ray_query(p_from, p_to, query_result);
1191
}
1192
1193
void GodotSoftBody3D::initialize_face_tree() {
1194
face_tree.clear();
1195
for (Face &face : faces) {
1196
AABB face_aabb;
1197
1198
face_aabb.position = face.n[0]->x;
1199
face_aabb.expand_to(face.n[1]->x);
1200
face_aabb.expand_to(face.n[2]->x);
1201
1202
face_aabb.grow_by(collision_margin);
1203
1204
face.leaf = face_tree.insert(face_aabb, &face);
1205
}
1206
}
1207
1208
void GodotSoftBody3D::update_face_tree(real_t p_delta) {
1209
for (const Face &face : faces) {
1210
AABB face_aabb;
1211
1212
const Node *node0 = face.n[0];
1213
face_aabb.position = node0->x;
1214
face_aabb.expand_to(node0->x + node0->v * p_delta);
1215
1216
const Node *node1 = face.n[1];
1217
face_aabb.expand_to(node1->x);
1218
face_aabb.expand_to(node1->x + node1->v * p_delta);
1219
1220
const Node *node2 = face.n[2];
1221
face_aabb.expand_to(node2->x);
1222
face_aabb.expand_to(node2->x + node2->v * p_delta);
1223
1224
face_aabb.grow_by(collision_margin);
1225
1226
face_tree.update(face.leaf, face_aabb);
1227
}
1228
}
1229
1230
void GodotSoftBody3D::initialize_shape(bool p_force_move) {
1231
if (get_shape_count() == 0) {
1232
GodotSoftBodyShape3D *soft_body_shape = memnew(GodotSoftBodyShape3D(this));
1233
add_shape(soft_body_shape);
1234
} else if (p_force_move) {
1235
GodotSoftBodyShape3D *soft_body_shape = static_cast<GodotSoftBodyShape3D *>(get_shape(0));
1236
soft_body_shape->update_bounds();
1237
}
1238
}
1239
1240
void GodotSoftBody3D::deinitialize_shape() {
1241
if (get_shape_count() > 0) {
1242
GodotShape3D *shape = get_shape(0);
1243
remove_shape(shape);
1244
memdelete(shape);
1245
}
1246
}
1247
1248
void GodotSoftBody3D::destroy() {
1249
soft_mesh = RID();
1250
1251
map_visual_to_physics.clear();
1252
1253
node_tree.clear();
1254
face_tree.clear();
1255
1256
nodes.clear();
1257
links.clear();
1258
faces.clear();
1259
1260
bounds = AABB();
1261
deinitialize_shape();
1262
}
1263
1264
void GodotSoftBodyShape3D::update_bounds() {
1265
ERR_FAIL_NULL(soft_body);
1266
1267
AABB collision_aabb = soft_body->get_bounds();
1268
collision_aabb.grow_by(soft_body->get_collision_margin());
1269
configure(collision_aabb);
1270
}
1271
1272
GodotSoftBodyShape3D::GodotSoftBodyShape3D(GodotSoftBody3D *p_soft_body) {
1273
soft_body = p_soft_body;
1274
update_bounds();
1275
}
1276
1277
struct _SoftBodyIntersectSegmentInfo {
1278
const GodotSoftBody3D *soft_body = nullptr;
1279
Vector3 from;
1280
Vector3 dir;
1281
Vector3 hit_position;
1282
uint32_t hit_face_index = -1;
1283
real_t hit_dist_sq = Math::INF;
1284
1285
static bool process_hit(uint32_t p_face_index, void *p_userdata) {
1286
_SoftBodyIntersectSegmentInfo &query_info = *(static_cast<_SoftBodyIntersectSegmentInfo *>(p_userdata));
1287
1288
Vector3 points[3];
1289
query_info.soft_body->get_face_points(p_face_index, points[0], points[1], points[2]);
1290
1291
Vector3 result;
1292
if (Geometry3D::ray_intersects_triangle(query_info.from, query_info.dir, points[0], points[1], points[2], &result)) {
1293
real_t dist_sq = query_info.from.distance_squared_to(result);
1294
if (dist_sq < query_info.hit_dist_sq) {
1295
query_info.hit_dist_sq = dist_sq;
1296
query_info.hit_position = result;
1297
query_info.hit_face_index = p_face_index;
1298
}
1299
}
1300
1301
// Continue with the query.
1302
return false;
1303
}
1304
};
1305
1306
bool GodotSoftBodyShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, int &r_face_index, bool p_hit_back_faces) const {
1307
_SoftBodyIntersectSegmentInfo query_info;
1308
query_info.soft_body = soft_body;
1309
query_info.from = p_begin;
1310
query_info.dir = (p_end - p_begin).normalized();
1311
1312
soft_body->query_ray(p_begin, p_end, _SoftBodyIntersectSegmentInfo::process_hit, &query_info);
1313
1314
if (query_info.hit_dist_sq != Math::INF) {
1315
r_result = query_info.hit_position;
1316
r_normal = soft_body->get_face_normal(query_info.hit_face_index);
1317
return true;
1318
}
1319
1320
return false;
1321
}
1322
1323
bool GodotSoftBodyShape3D::intersect_point(const Vector3 &p_point) const {
1324
return false;
1325
}
1326
1327
Vector3 GodotSoftBodyShape3D::get_closest_point_to(const Vector3 &p_point) const {
1328
ERR_FAIL_V_MSG(Vector3(), "Get closest point is not supported for soft bodies.");
1329
}
1330
1331