Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/modules/godot_physics_3d/godot_shape_3d.cpp
10277 views
1
/**************************************************************************/
2
/* godot_shape_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_shape_3d.h"
32
33
#include "core/io/image.h"
34
#include "core/math/convex_hull.h"
35
#include "core/math/geometry_3d.h"
36
#include "core/templates/sort_array.h"
37
38
// GodotHeightMapShape3D is based on Bullet btHeightfieldTerrainShape.
39
40
/*
41
Bullet Continuous Collision Detection and Physics Library
42
Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org
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
55
const double edge_support_threshold = 0.99999998;
56
const double edge_support_threshold_lower = Math::sqrt(1.0 - edge_support_threshold * edge_support_threshold);
57
// For a unit normal vector n, the horizontality condition
58
// sqrt(n.x * n.x + n.z * n.z) > edge_support_threshold
59
// is equivalent to the condition
60
// abs(n.y) < edge_support_threshold_lower,
61
// which is cheaper to test.
62
const double face_support_threshold = 0.9998;
63
64
const double cylinder_edge_support_threshold = 0.999998;
65
const double cylinder_edge_support_threshold_lower = Math::sqrt(1.0 - cylinder_edge_support_threshold * cylinder_edge_support_threshold);
66
const double cylinder_face_support_threshold = 0.999;
67
68
void GodotShape3D::configure(const AABB &p_aabb) {
69
aabb = p_aabb;
70
configured = true;
71
for (const KeyValue<GodotShapeOwner3D *, int> &E : owners) {
72
GodotShapeOwner3D *co = E.key;
73
co->_shape_changed();
74
}
75
}
76
77
Vector3 GodotShape3D::get_support(const Vector3 &p_normal) const {
78
Vector3 res;
79
int amnt;
80
FeatureType type;
81
get_supports(p_normal, 1, &res, amnt, type);
82
return res;
83
}
84
85
void GodotShape3D::add_owner(GodotShapeOwner3D *p_owner) {
86
HashMap<GodotShapeOwner3D *, int>::Iterator E = owners.find(p_owner);
87
if (E) {
88
E->value++;
89
} else {
90
owners[p_owner] = 1;
91
}
92
}
93
94
void GodotShape3D::remove_owner(GodotShapeOwner3D *p_owner) {
95
HashMap<GodotShapeOwner3D *, int>::Iterator E = owners.find(p_owner);
96
ERR_FAIL_COND(!E);
97
E->value--;
98
if (E->value == 0) {
99
owners.remove(E);
100
}
101
}
102
103
bool GodotShape3D::is_owner(GodotShapeOwner3D *p_owner) const {
104
return owners.has(p_owner);
105
}
106
107
const HashMap<GodotShapeOwner3D *, int> &GodotShape3D::get_owners() const {
108
return owners;
109
}
110
111
GodotShape3D::~GodotShape3D() {
112
ERR_FAIL_COND(owners.size());
113
}
114
115
Plane GodotWorldBoundaryShape3D::get_plane() const {
116
return plane;
117
}
118
119
void GodotWorldBoundaryShape3D::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const {
120
// gibberish, a plane is infinity
121
r_min = -1e7;
122
r_max = 1e7;
123
}
124
125
Vector3 GodotWorldBoundaryShape3D::get_support(const Vector3 &p_normal) const {
126
return p_normal * 1e15;
127
}
128
129
bool GodotWorldBoundaryShape3D::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 {
130
bool inters = plane.intersects_segment(p_begin, p_end, &r_result);
131
if (inters) {
132
r_normal = plane.normal;
133
}
134
return inters;
135
}
136
137
bool GodotWorldBoundaryShape3D::intersect_point(const Vector3 &p_point) const {
138
return plane.distance_to(p_point) < 0;
139
}
140
141
Vector3 GodotWorldBoundaryShape3D::get_closest_point_to(const Vector3 &p_point) const {
142
if (plane.is_point_over(p_point)) {
143
return plane.project(p_point);
144
} else {
145
return p_point;
146
}
147
}
148
149
Vector3 GodotWorldBoundaryShape3D::get_moment_of_inertia(real_t p_mass) const {
150
return Vector3(); // not applicable.
151
}
152
153
void GodotWorldBoundaryShape3D::_setup(const Plane &p_plane) {
154
plane = p_plane;
155
configure(AABB(Vector3(-1e15, -1e15, -1e15), Vector3(1e15 * 2, 1e15 * 2, 1e15 * 2)));
156
}
157
158
void GodotWorldBoundaryShape3D::set_data(const Variant &p_data) {
159
_setup(p_data);
160
}
161
162
Variant GodotWorldBoundaryShape3D::get_data() const {
163
return plane;
164
}
165
166
GodotWorldBoundaryShape3D::GodotWorldBoundaryShape3D() {
167
}
168
169
//
170
171
real_t GodotSeparationRayShape3D::get_length() const {
172
return length;
173
}
174
175
bool GodotSeparationRayShape3D::get_slide_on_slope() const {
176
return slide_on_slope;
177
}
178
179
void GodotSeparationRayShape3D::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const {
180
// don't think this will be even used
181
r_min = 0;
182
r_max = 1;
183
}
184
185
Vector3 GodotSeparationRayShape3D::get_support(const Vector3 &p_normal) const {
186
if (p_normal.z > 0) {
187
return Vector3(0, 0, length);
188
} else {
189
return Vector3(0, 0, 0);
190
}
191
}
192
193
void GodotSeparationRayShape3D::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const {
194
if (Math::abs(p_normal.z) < edge_support_threshold_lower) {
195
r_amount = 2;
196
r_type = FEATURE_EDGE;
197
r_supports[0] = Vector3(0, 0, 0);
198
r_supports[1] = Vector3(0, 0, length);
199
} else if (p_normal.z > 0) {
200
r_amount = 1;
201
r_type = FEATURE_POINT;
202
*r_supports = Vector3(0, 0, length);
203
} else {
204
r_amount = 1;
205
r_type = FEATURE_POINT;
206
*r_supports = Vector3(0, 0, 0);
207
}
208
}
209
210
bool GodotSeparationRayShape3D::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 {
211
return false; //simply not possible
212
}
213
214
bool GodotSeparationRayShape3D::intersect_point(const Vector3 &p_point) const {
215
return false; //simply not possible
216
}
217
218
Vector3 GodotSeparationRayShape3D::get_closest_point_to(const Vector3 &p_point) const {
219
return Geometry3D::get_closest_point_to_segment(p_point, Vector3(0, 0, 0), Vector3(0, 0, length));
220
}
221
222
Vector3 GodotSeparationRayShape3D::get_moment_of_inertia(real_t p_mass) const {
223
return Vector3();
224
}
225
226
void GodotSeparationRayShape3D::_setup(real_t p_length, bool p_slide_on_slope) {
227
length = p_length;
228
slide_on_slope = p_slide_on_slope;
229
configure(AABB(Vector3(0, 0, 0), Vector3(0.1, 0.1, length)));
230
}
231
232
void GodotSeparationRayShape3D::set_data(const Variant &p_data) {
233
Dictionary d = p_data;
234
_setup(d["length"], d["slide_on_slope"]);
235
}
236
237
Variant GodotSeparationRayShape3D::get_data() const {
238
Dictionary d;
239
d["length"] = length;
240
d["slide_on_slope"] = slide_on_slope;
241
return d;
242
}
243
244
GodotSeparationRayShape3D::GodotSeparationRayShape3D() {}
245
246
/********** SPHERE *************/
247
248
real_t GodotSphereShape3D::get_radius() const {
249
return radius;
250
}
251
252
void GodotSphereShape3D::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const {
253
real_t d = p_normal.dot(p_transform.origin);
254
255
// figure out scale at point
256
Vector3 local_normal = p_transform.basis.xform_inv(p_normal);
257
real_t scale = local_normal.length();
258
259
r_min = d - (radius)*scale;
260
r_max = d + (radius)*scale;
261
}
262
263
Vector3 GodotSphereShape3D::get_support(const Vector3 &p_normal) const {
264
return p_normal * radius;
265
}
266
267
void GodotSphereShape3D::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const {
268
*r_supports = p_normal * radius;
269
r_amount = 1;
270
r_type = FEATURE_POINT;
271
}
272
273
bool GodotSphereShape3D::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 {
274
return Geometry3D::segment_intersects_sphere(p_begin, p_end, Vector3(), radius, &r_result, &r_normal);
275
}
276
277
bool GodotSphereShape3D::intersect_point(const Vector3 &p_point) const {
278
return p_point.length() < radius;
279
}
280
281
Vector3 GodotSphereShape3D::get_closest_point_to(const Vector3 &p_point) const {
282
Vector3 p = p_point;
283
real_t l = p.length();
284
if (l < radius) {
285
return p_point;
286
}
287
return (p / l) * radius;
288
}
289
290
Vector3 GodotSphereShape3D::get_moment_of_inertia(real_t p_mass) const {
291
real_t s = 0.4 * p_mass * radius * radius;
292
return Vector3(s, s, s);
293
}
294
295
void GodotSphereShape3D::_setup(real_t p_radius) {
296
radius = p_radius;
297
configure(AABB(Vector3(-radius, -radius, -radius), Vector3(radius * 2.0, radius * 2.0, radius * 2.0)));
298
}
299
300
void GodotSphereShape3D::set_data(const Variant &p_data) {
301
_setup(p_data);
302
}
303
304
Variant GodotSphereShape3D::get_data() const {
305
return radius;
306
}
307
308
GodotSphereShape3D::GodotSphereShape3D() {}
309
310
/********** BOX *************/
311
312
void GodotBoxShape3D::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const {
313
// no matter the angle, the box is mirrored anyway
314
Vector3 local_normal = p_transform.basis.xform_inv(p_normal);
315
316
real_t length = local_normal.abs().dot(half_extents);
317
real_t distance = p_normal.dot(p_transform.origin);
318
319
r_min = distance - length;
320
r_max = distance + length;
321
}
322
323
Vector3 GodotBoxShape3D::get_support(const Vector3 &p_normal) const {
324
Vector3 point(
325
(p_normal.x < 0) ? -half_extents.x : half_extents.x,
326
(p_normal.y < 0) ? -half_extents.y : half_extents.y,
327
(p_normal.z < 0) ? -half_extents.z : half_extents.z);
328
329
return point;
330
}
331
332
void GodotBoxShape3D::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const {
333
static const int next[3] = { 1, 2, 0 };
334
static const int next2[3] = { 2, 0, 1 };
335
336
for (int i = 0; i < 3; i++) {
337
Vector3 axis;
338
axis[i] = 1.0;
339
real_t dot = p_normal.dot(axis);
340
if (Math::abs(dot) > face_support_threshold) {
341
//Vector3 axis_b;
342
343
bool neg = dot < 0;
344
r_amount = 4;
345
r_type = FEATURE_FACE;
346
347
Vector3 point;
348
point[i] = half_extents[i];
349
350
int i_n = next[i];
351
int i_n2 = next2[i];
352
353
static const real_t sign[4][2] = {
354
{ -1.0, 1.0 },
355
{ 1.0, 1.0 },
356
{ 1.0, -1.0 },
357
{ -1.0, -1.0 },
358
};
359
360
for (int j = 0; j < 4; j++) {
361
point[i_n] = sign[j][0] * half_extents[i_n];
362
point[i_n2] = sign[j][1] * half_extents[i_n2];
363
r_supports[j] = neg ? -point : point;
364
}
365
366
if (neg) {
367
SWAP(r_supports[1], r_supports[2]);
368
SWAP(r_supports[0], r_supports[3]);
369
}
370
371
return;
372
}
373
374
r_amount = 0;
375
}
376
377
for (int i = 0; i < 3; i++) {
378
Vector3 axis;
379
axis[i] = 1.0;
380
381
if (Math::abs(p_normal.dot(axis)) < edge_support_threshold_lower) {
382
r_amount = 2;
383
r_type = FEATURE_EDGE;
384
385
int i_n = next[i];
386
int i_n2 = next2[i];
387
388
Vector3 point = half_extents;
389
390
if (p_normal[i_n] < 0) {
391
point[i_n] = -point[i_n];
392
}
393
if (p_normal[i_n2] < 0) {
394
point[i_n2] = -point[i_n2];
395
}
396
397
r_supports[0] = point;
398
point[i] = -point[i];
399
r_supports[1] = point;
400
return;
401
}
402
}
403
/* USE POINT */
404
405
Vector3 point(
406
(p_normal.x < 0) ? -half_extents.x : half_extents.x,
407
(p_normal.y < 0) ? -half_extents.y : half_extents.y,
408
(p_normal.z < 0) ? -half_extents.z : half_extents.z);
409
410
r_amount = 1;
411
r_type = FEATURE_POINT;
412
r_supports[0] = point;
413
}
414
415
bool GodotBoxShape3D::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 {
416
AABB aabb_ext(-half_extents, half_extents * 2.0);
417
418
return aabb_ext.intersects_segment(p_begin, p_end, &r_result, &r_normal);
419
}
420
421
bool GodotBoxShape3D::intersect_point(const Vector3 &p_point) const {
422
return (Math::abs(p_point.x) < half_extents.x && Math::abs(p_point.y) < half_extents.y && Math::abs(p_point.z) < half_extents.z);
423
}
424
425
Vector3 GodotBoxShape3D::get_closest_point_to(const Vector3 &p_point) const {
426
int outside = 0;
427
Vector3 min_point;
428
429
for (int i = 0; i < 3; i++) {
430
if (Math::abs(p_point[i]) > half_extents[i]) {
431
outside++;
432
if (outside == 1) {
433
//use plane if only one side matches
434
Vector3 n;
435
n[i] = SIGN(p_point[i]);
436
437
Plane p(n, half_extents[i]);
438
min_point = p.project(p_point);
439
}
440
}
441
}
442
443
if (!outside) {
444
return p_point; //it's inside, don't do anything else
445
}
446
447
if (outside == 1) { //if only above one plane, this plane clearly wins
448
return min_point;
449
}
450
451
//check segments
452
real_t min_distance = 1e20;
453
const Vector3 closest_vertex = half_extents * p_point.sign();
454
for (int i = 0; i < 3; i++) {
455
Vector3 segment_b = closest_vertex;
456
segment_b[i] = -segment_b[i]; //edge
457
458
const Vector3 closest_edge = Geometry3D::get_closest_point_to_segment(p_point, closest_vertex, segment_b);
459
460
const real_t d = p_point.distance_to(closest_edge);
461
if (d < min_distance) {
462
min_point = closest_edge;
463
min_distance = d;
464
}
465
}
466
467
return min_point;
468
}
469
470
Vector3 GodotBoxShape3D::get_moment_of_inertia(real_t p_mass) const {
471
real_t lx = half_extents.x;
472
real_t ly = half_extents.y;
473
real_t lz = half_extents.z;
474
475
return Vector3((p_mass / 3.0) * (ly * ly + lz * lz), (p_mass / 3.0) * (lx * lx + lz * lz), (p_mass / 3.0) * (lx * lx + ly * ly));
476
}
477
478
void GodotBoxShape3D::_setup(const Vector3 &p_half_extents) {
479
half_extents = p_half_extents.abs();
480
481
configure(AABB(-half_extents, half_extents * 2));
482
}
483
484
void GodotBoxShape3D::set_data(const Variant &p_data) {
485
_setup(p_data);
486
}
487
488
Variant GodotBoxShape3D::get_data() const {
489
return half_extents;
490
}
491
492
GodotBoxShape3D::GodotBoxShape3D() {}
493
494
/********** CAPSULE *************/
495
496
void GodotCapsuleShape3D::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const {
497
Vector3 n = p_transform.basis.xform_inv(p_normal).normalized();
498
real_t h = height * 0.5 - radius;
499
500
n *= radius;
501
n.y += (n.y > 0) ? h : -h;
502
503
r_max = p_normal.dot(p_transform.xform(n));
504
r_min = p_normal.dot(p_transform.xform(-n));
505
}
506
507
Vector3 GodotCapsuleShape3D::get_support(const Vector3 &p_normal) const {
508
Vector3 n = p_normal;
509
510
real_t h = height * 0.5 - radius;
511
512
n *= radius;
513
n.y += (n.y > 0) ? h : -h;
514
return n;
515
}
516
517
void GodotCapsuleShape3D::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const {
518
Vector3 n = p_normal;
519
520
real_t d = n.y;
521
real_t h = height * 0.5 - radius; // half-height of the cylinder part
522
523
if (h > 0 && Math::abs(d) < edge_support_threshold_lower) {
524
// make it flat
525
n.y = 0.0;
526
n.normalize();
527
n *= radius;
528
529
r_amount = 2;
530
r_type = FEATURE_EDGE;
531
r_supports[0] = n;
532
r_supports[0].y += h;
533
r_supports[1] = n;
534
r_supports[1].y -= h;
535
} else {
536
n *= radius;
537
n.y += (d > 0) ? h : -h;
538
r_amount = 1;
539
r_type = FEATURE_POINT;
540
*r_supports = n;
541
}
542
}
543
544
bool GodotCapsuleShape3D::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 {
545
Vector3 norm = (p_end - p_begin).normalized();
546
real_t min_d = 1e20;
547
548
Vector3 res, n;
549
bool collision = false;
550
551
Vector3 auxres, auxn;
552
bool collided;
553
554
// test against cylinder and spheres :-|
555
556
collided = Geometry3D::segment_intersects_cylinder(p_begin, p_end, height - radius * 2.0, radius, &auxres, &auxn, 1);
557
558
if (collided) {
559
real_t d = norm.dot(auxres);
560
if (d < min_d) {
561
min_d = d;
562
res = auxres;
563
n = auxn;
564
collision = true;
565
}
566
}
567
568
collided = Geometry3D::segment_intersects_sphere(p_begin, p_end, Vector3(0, height * 0.5 - radius, 0), radius, &auxres, &auxn);
569
570
if (collided) {
571
real_t d = norm.dot(auxres);
572
if (d < min_d) {
573
min_d = d;
574
res = auxres;
575
n = auxn;
576
collision = true;
577
}
578
}
579
580
collided = Geometry3D::segment_intersects_sphere(p_begin, p_end, Vector3(0, height * -0.5 + radius, 0), radius, &auxres, &auxn);
581
582
if (collided) {
583
real_t d = norm.dot(auxres);
584
585
if (d < min_d) {
586
min_d = d;
587
res = auxres;
588
n = auxn;
589
collision = true;
590
}
591
}
592
593
if (collision) {
594
r_result = res;
595
r_normal = n;
596
}
597
return collision;
598
}
599
600
bool GodotCapsuleShape3D::intersect_point(const Vector3 &p_point) const {
601
if (Math::abs(p_point.y) < height * 0.5 - radius) {
602
return Vector3(p_point.x, 0, p_point.z).length() < radius;
603
} else {
604
Vector3 p = p_point;
605
p.y = Math::abs(p.y) - height * 0.5 + radius;
606
return p.length() < radius;
607
}
608
}
609
610
Vector3 GodotCapsuleShape3D::get_closest_point_to(const Vector3 &p_point) const {
611
const Vector3 segment_a = Vector3(0, -height * 0.5 + radius, 0);
612
const Vector3 segment_b = Vector3(0, height * 0.5 - radius, 0);
613
614
const Vector3 p = Geometry3D::get_closest_point_to_segment(p_point, segment_a, segment_b);
615
616
if (p.distance_to(p_point) < radius) {
617
return p_point;
618
}
619
620
return p + (p_point - p).normalized() * radius;
621
}
622
623
Vector3 GodotCapsuleShape3D::get_moment_of_inertia(real_t p_mass) const {
624
// use bad AABB approximation
625
Vector3 extents = get_aabb().size * 0.5;
626
627
return Vector3(
628
(p_mass / 3.0) * (extents.y * extents.y + extents.z * extents.z),
629
(p_mass / 3.0) * (extents.x * extents.x + extents.z * extents.z),
630
(p_mass / 3.0) * (extents.x * extents.x + extents.y * extents.y));
631
}
632
633
void GodotCapsuleShape3D::_setup(real_t p_height, real_t p_radius) {
634
height = p_height;
635
radius = p_radius;
636
configure(AABB(Vector3(-radius, -height * 0.5, -radius), Vector3(radius * 2, height, radius * 2)));
637
}
638
639
void GodotCapsuleShape3D::set_data(const Variant &p_data) {
640
Dictionary d = p_data;
641
ERR_FAIL_COND(!d.has("radius"));
642
ERR_FAIL_COND(!d.has("height"));
643
_setup(d["height"], d["radius"]);
644
}
645
646
Variant GodotCapsuleShape3D::get_data() const {
647
Dictionary d;
648
d["radius"] = radius;
649
d["height"] = height;
650
return d;
651
}
652
653
GodotCapsuleShape3D::GodotCapsuleShape3D() {}
654
655
/********** CYLINDER *************/
656
657
void GodotCylinderShape3D::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const {
658
Vector3 cylinder_axis = p_transform.basis.get_column(1).normalized();
659
real_t axis_dot = cylinder_axis.dot(p_normal);
660
661
Vector3 local_normal = p_transform.basis.xform_inv(p_normal);
662
real_t scale = local_normal.length();
663
real_t scaled_radius = radius * scale;
664
real_t scaled_height = height * scale;
665
666
real_t length;
667
if (Math::abs(axis_dot) > 1.0) {
668
length = scaled_height * 0.5;
669
} else {
670
length = Math::abs(axis_dot * scaled_height * 0.5) + scaled_radius * Math::sqrt(1.0 - axis_dot * axis_dot);
671
}
672
673
real_t distance = p_normal.dot(p_transform.origin);
674
675
r_min = distance - length;
676
r_max = distance + length;
677
}
678
679
Vector3 GodotCylinderShape3D::get_support(const Vector3 &p_normal) const {
680
Vector3 n = p_normal;
681
real_t h = (n.y > 0) ? height : -height;
682
real_t s = Math::sqrt(n.x * n.x + n.z * n.z);
683
if (Math::is_zero_approx(s)) {
684
n.x = radius;
685
n.y = h * 0.5;
686
n.z = 0.0;
687
} else {
688
real_t d = radius / s;
689
n.x = n.x * d;
690
n.y = h * 0.5;
691
n.z = n.z * d;
692
}
693
694
return n;
695
}
696
697
void GodotCylinderShape3D::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const {
698
real_t d = p_normal.y;
699
if (Math::abs(d) > cylinder_face_support_threshold) {
700
real_t h = (d > 0) ? height : -height;
701
702
Vector3 n = p_normal;
703
n.x = 0.0;
704
n.z = 0.0;
705
n.y = h * 0.5;
706
707
r_amount = 3;
708
r_type = FEATURE_CIRCLE;
709
r_supports[0] = n;
710
r_supports[1] = n;
711
r_supports[1].x += radius;
712
r_supports[2] = n;
713
r_supports[2].z += radius;
714
} else if (Math::abs(d) < cylinder_edge_support_threshold_lower) {
715
// make it flat
716
Vector3 n = p_normal;
717
n.y = 0.0;
718
n.normalize();
719
n *= radius;
720
721
r_amount = 2;
722
r_type = FEATURE_EDGE;
723
r_supports[0] = n;
724
r_supports[0].y += height * 0.5;
725
r_supports[1] = n;
726
r_supports[1].y -= height * 0.5;
727
} else {
728
r_amount = 1;
729
r_type = FEATURE_POINT;
730
r_supports[0] = get_support(p_normal);
731
}
732
}
733
734
bool GodotCylinderShape3D::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 {
735
return Geometry3D::segment_intersects_cylinder(p_begin, p_end, height, radius, &r_result, &r_normal, 1);
736
}
737
738
bool GodotCylinderShape3D::intersect_point(const Vector3 &p_point) const {
739
if (Math::abs(p_point.y) < height * 0.5) {
740
return Vector3(p_point.x, 0, p_point.z).length() < radius;
741
}
742
return false;
743
}
744
745
Vector3 GodotCylinderShape3D::get_closest_point_to(const Vector3 &p_point) const {
746
if (Math::abs(p_point.y) > height * 0.5) {
747
// Project point to top disk.
748
real_t dir = p_point.y > 0.0 ? 1.0 : -1.0;
749
Vector3 circle_pos(0.0, dir * height * 0.5, 0.0);
750
Plane circle_plane(Vector3(0.0, dir, 0.0), circle_pos);
751
Vector3 proj_point = circle_plane.project(p_point);
752
753
// Clip position.
754
Vector3 delta_point_1 = proj_point - circle_pos;
755
real_t dist_point_1 = delta_point_1.length_squared();
756
if (!Math::is_zero_approx(dist_point_1)) {
757
dist_point_1 = Math::sqrt(dist_point_1);
758
proj_point = circle_pos + delta_point_1 * MIN(dist_point_1, radius) / dist_point_1;
759
}
760
761
return proj_point;
762
} else {
763
const Vector3 segment_a = Vector3(0, -height * 0.5, 0);
764
const Vector3 segment_b = Vector3(0, height * 0.5, 0);
765
766
const Vector3 p = Geometry3D::get_closest_point_to_segment(p_point, segment_a, segment_b);
767
768
if (p.distance_to(p_point) < radius) {
769
return p_point;
770
}
771
772
return p + (p_point - p).normalized() * radius;
773
}
774
}
775
776
Vector3 GodotCylinderShape3D::get_moment_of_inertia(real_t p_mass) const {
777
// use bad AABB approximation
778
Vector3 extents = get_aabb().size * 0.5;
779
780
return Vector3(
781
(p_mass / 3.0) * (extents.y * extents.y + extents.z * extents.z),
782
(p_mass / 3.0) * (extents.x * extents.x + extents.z * extents.z),
783
(p_mass / 3.0) * (extents.x * extents.x + extents.y * extents.y));
784
}
785
786
void GodotCylinderShape3D::_setup(real_t p_height, real_t p_radius) {
787
height = p_height;
788
radius = p_radius;
789
configure(AABB(Vector3(-radius, -height * 0.5, -radius), Vector3(radius * 2.0, height, radius * 2.0)));
790
}
791
792
void GodotCylinderShape3D::set_data(const Variant &p_data) {
793
Dictionary d = p_data;
794
ERR_FAIL_COND(!d.has("radius"));
795
ERR_FAIL_COND(!d.has("height"));
796
_setup(d["height"], d["radius"]);
797
}
798
799
Variant GodotCylinderShape3D::get_data() const {
800
Dictionary d;
801
d["radius"] = radius;
802
d["height"] = height;
803
return d;
804
}
805
806
GodotCylinderShape3D::GodotCylinderShape3D() {}
807
808
/********** CONVEX POLYGON *************/
809
810
void GodotConvexPolygonShape3D::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const {
811
uint32_t vertex_count = mesh.vertices.size();
812
if (vertex_count == 0) {
813
return;
814
}
815
816
const Vector3 *vrts = &mesh.vertices[0];
817
818
if (vertex_count > 3 * extreme_vertices.size()) {
819
// For a large mesh, two calls to get_support() is faster than a full
820
// scan over all vertices.
821
822
Vector3 n = p_transform.basis.xform_inv(p_normal).normalized();
823
r_min = p_normal.dot(p_transform.xform(get_support(-n)));
824
r_max = p_normal.dot(p_transform.xform(get_support(n)));
825
} else {
826
for (uint32_t i = 0; i < vertex_count; i++) {
827
real_t d = p_normal.dot(p_transform.xform(vrts[i]));
828
829
if (i == 0 || d > r_max) {
830
r_max = d;
831
}
832
if (i == 0 || d < r_min) {
833
r_min = d;
834
}
835
}
836
}
837
}
838
839
Vector3 GodotConvexPolygonShape3D::get_support(const Vector3 &p_normal) const {
840
// Skip if there are no vertices in the mesh
841
if (mesh.vertices.is_empty()) {
842
return Vector3();
843
}
844
845
// Get the array of vertices
846
const Vector3 *const vertices_array = mesh.vertices.ptr();
847
848
// Start with an initial assumption of the first extreme vertex.
849
int best_vertex = extreme_vertices[0];
850
real_t max_support = p_normal.dot(vertices_array[best_vertex]);
851
852
// Check the remaining extreme vertices for a better vertex.
853
for (const int &vert : extreme_vertices) {
854
real_t s = p_normal.dot(vertices_array[vert]);
855
if (s > max_support) {
856
best_vertex = vert;
857
max_support = s;
858
}
859
}
860
861
// If we checked all vertices in the mesh then we're done.
862
if (extreme_vertices.size() == mesh.vertices.size()) {
863
return vertices_array[best_vertex];
864
}
865
866
// Move along the surface until we reach the true support vertex.
867
int last_vertex = -1;
868
while (true) {
869
int next_vertex = -1;
870
871
// Iterate over all the neighbors checking for a better vertex.
872
for (const int &vert : vertex_neighbors[best_vertex]) {
873
if (vert != last_vertex) {
874
real_t s = p_normal.dot(vertices_array[vert]);
875
if (s > max_support) {
876
next_vertex = vert;
877
max_support = s;
878
break;
879
}
880
}
881
}
882
883
// No better vertex found, we have the best
884
if (next_vertex == -1) {
885
return vertices_array[best_vertex];
886
}
887
888
// Move to the better vertex and try again
889
last_vertex = best_vertex;
890
best_vertex = next_vertex;
891
}
892
}
893
894
void GodotConvexPolygonShape3D::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const {
895
const Geometry3D::MeshData::Face *faces = mesh.faces.ptr();
896
int fc = mesh.faces.size();
897
898
const Geometry3D::MeshData::Edge *edges = mesh.edges.ptr();
899
int ec = mesh.edges.size();
900
901
const Vector3 *vertices = mesh.vertices.ptr();
902
int vc = mesh.vertices.size();
903
904
r_amount = 0;
905
ERR_FAIL_COND_MSG(vc == 0, "Convex polygon shape has no vertices.");
906
907
//find vertex first
908
real_t max = 0;
909
int vtx = 0;
910
911
for (int i = 0; i < vc; i++) {
912
real_t d = p_normal.dot(vertices[i]);
913
914
if (i == 0 || d > max) {
915
max = d;
916
vtx = i;
917
}
918
}
919
920
for (int i = 0; i < fc; i++) {
921
if (faces[i].plane.normal.dot(p_normal) > face_support_threshold) {
922
int ic = faces[i].indices.size();
923
const int *ind = faces[i].indices.ptr();
924
925
bool valid = false;
926
for (int j = 0; j < ic; j++) {
927
if (ind[j] == vtx) {
928
valid = true;
929
break;
930
}
931
}
932
933
if (!valid) {
934
continue;
935
}
936
937
int m = MIN(p_max, ic);
938
for (int j = 0; j < m; j++) {
939
r_supports[j] = vertices[ind[j]];
940
}
941
r_amount = m;
942
r_type = FEATURE_FACE;
943
return;
944
}
945
}
946
947
for (int i = 0; i < ec; i++) {
948
real_t dot = (vertices[edges[i].vertex_a] - vertices[edges[i].vertex_b]).normalized().dot(p_normal);
949
dot = Math::abs(dot);
950
if (dot < edge_support_threshold_lower && (edges[i].vertex_a == vtx || edges[i].vertex_b == vtx)) {
951
r_amount = 2;
952
r_type = FEATURE_EDGE;
953
r_supports[0] = vertices[edges[i].vertex_a];
954
r_supports[1] = vertices[edges[i].vertex_b];
955
return;
956
}
957
}
958
959
r_supports[0] = vertices[vtx];
960
r_amount = 1;
961
r_type = FEATURE_POINT;
962
}
963
964
bool GodotConvexPolygonShape3D::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 {
965
const Geometry3D::MeshData::Face *faces = mesh.faces.ptr();
966
int fc = mesh.faces.size();
967
968
const Vector3 *vertices = mesh.vertices.ptr();
969
970
Vector3 n = p_end - p_begin;
971
real_t min = 1e20;
972
bool col = false;
973
974
for (int i = 0; i < fc; i++) {
975
if (faces[i].plane.normal.dot(n) > 0) {
976
continue; //opposing face
977
}
978
979
int ic = faces[i].indices.size();
980
const int *ind = faces[i].indices.ptr();
981
982
for (int j = 1; j < ic - 1; j++) {
983
Face3 f(vertices[ind[0]], vertices[ind[j]], vertices[ind[j + 1]]);
984
Vector3 result;
985
if (f.intersects_segment(p_begin, p_end, &result)) {
986
real_t d = n.dot(result);
987
if (d < min) {
988
min = d;
989
r_result = result;
990
r_normal = faces[i].plane.normal;
991
col = true;
992
}
993
994
break;
995
}
996
}
997
}
998
999
return col;
1000
}
1001
1002
bool GodotConvexPolygonShape3D::intersect_point(const Vector3 &p_point) const {
1003
const Geometry3D::MeshData::Face *faces = mesh.faces.ptr();
1004
int fc = mesh.faces.size();
1005
1006
for (int i = 0; i < fc; i++) {
1007
if (faces[i].plane.distance_to(p_point) >= 0) {
1008
return false;
1009
}
1010
}
1011
1012
return true;
1013
}
1014
1015
Vector3 GodotConvexPolygonShape3D::get_closest_point_to(const Vector3 &p_point) const {
1016
const Geometry3D::MeshData::Face *faces = mesh.faces.ptr();
1017
int fc = mesh.faces.size();
1018
const Vector3 *vertices = mesh.vertices.ptr();
1019
1020
bool all_inside = true;
1021
for (int i = 0; i < fc; i++) {
1022
if (!faces[i].plane.is_point_over(p_point)) {
1023
continue;
1024
}
1025
1026
all_inside = false;
1027
bool is_inside = true;
1028
int ic = faces[i].indices.size();
1029
const int *indices = faces[i].indices.ptr();
1030
1031
for (int j = 0; j < ic; j++) {
1032
Vector3 a = vertices[indices[j]];
1033
Vector3 b = vertices[indices[(j + 1) % ic]];
1034
Vector3 n = (a - b).cross(faces[i].plane.normal).normalized();
1035
if (Plane(n, a).is_point_over(p_point)) {
1036
is_inside = false;
1037
break;
1038
}
1039
}
1040
1041
if (is_inside) {
1042
return faces[i].plane.project(p_point);
1043
}
1044
}
1045
1046
if (all_inside) {
1047
return p_point;
1048
}
1049
1050
real_t min_distance = 1e20;
1051
Vector3 min_point;
1052
1053
//check edges
1054
const Geometry3D::MeshData::Edge *edges = mesh.edges.ptr();
1055
int ec = mesh.edges.size();
1056
for (int i = 0; i < ec; i++) {
1057
const Vector3 segment_a = vertices[edges[i].vertex_a];
1058
const Vector3 segment_b = vertices[edges[i].vertex_b];
1059
1060
Vector3 closest = Geometry3D::get_closest_point_to_segment(p_point, segment_a, segment_b);
1061
real_t d = closest.distance_to(p_point);
1062
if (d < min_distance) {
1063
min_distance = d;
1064
min_point = closest;
1065
}
1066
}
1067
1068
return min_point;
1069
}
1070
1071
Vector3 GodotConvexPolygonShape3D::get_moment_of_inertia(real_t p_mass) const {
1072
// use bad AABB approximation
1073
Vector3 extents = get_aabb().size * 0.5;
1074
1075
return Vector3(
1076
(p_mass / 3.0) * (extents.y * extents.y + extents.z * extents.z),
1077
(p_mass / 3.0) * (extents.x * extents.x + extents.z * extents.z),
1078
(p_mass / 3.0) * (extents.x * extents.x + extents.y * extents.y));
1079
}
1080
1081
void GodotConvexPolygonShape3D::_setup(const Vector<Vector3> &p_vertices) {
1082
Error err = ConvexHullComputer::convex_hull(p_vertices, mesh);
1083
if (err != OK) {
1084
ERR_PRINT("Failed to build convex hull");
1085
}
1086
extreme_vertices.resize(0);
1087
vertex_neighbors.resize(0);
1088
1089
AABB _aabb;
1090
1091
for (uint32_t i = 0; i < mesh.vertices.size(); i++) {
1092
if (i == 0) {
1093
_aabb.position = mesh.vertices[i];
1094
} else {
1095
_aabb.expand_to(mesh.vertices[i]);
1096
}
1097
}
1098
1099
configure(_aabb);
1100
1101
// Pre-compute the extreme vertices in 26 directions. This will be used
1102
// to speed up get_support() by letting us quickly get a good guess for
1103
// the support vertex.
1104
1105
for (int x = -1; x < 2; x++) {
1106
for (int y = -1; y < 2; y++) {
1107
for (int z = -1; z < 2; z++) {
1108
if (x != 0 || y != 0 || z != 0) {
1109
Vector3 dir(x, y, z);
1110
dir.normalize();
1111
real_t max_support = 0.0;
1112
int best_vertex = -1;
1113
for (uint32_t i = 0; i < mesh.vertices.size(); i++) {
1114
real_t s = dir.dot(mesh.vertices[i]);
1115
if (best_vertex == -1 || s > max_support) {
1116
best_vertex = i;
1117
max_support = s;
1118
}
1119
}
1120
if (!extreme_vertices.has(best_vertex)) {
1121
extreme_vertices.push_back(best_vertex);
1122
}
1123
}
1124
}
1125
}
1126
}
1127
1128
// Record all the neighbors of each vertex. This is used in get_support().
1129
1130
if (extreme_vertices.size() < mesh.vertices.size()) {
1131
vertex_neighbors.resize(mesh.vertices.size());
1132
for (Geometry3D::MeshData::Edge &edge : mesh.edges) {
1133
vertex_neighbors[edge.vertex_a].push_back(edge.vertex_b);
1134
vertex_neighbors[edge.vertex_b].push_back(edge.vertex_a);
1135
}
1136
}
1137
}
1138
1139
void GodotConvexPolygonShape3D::set_data(const Variant &p_data) {
1140
_setup(p_data);
1141
}
1142
1143
Variant GodotConvexPolygonShape3D::get_data() const {
1144
Vector<Vector3> vertices;
1145
vertices.resize(mesh.vertices.size());
1146
for (uint32_t i = 0; i < mesh.vertices.size(); i++) {
1147
vertices.write[i] = mesh.vertices[i];
1148
}
1149
return vertices;
1150
}
1151
1152
GodotConvexPolygonShape3D::GodotConvexPolygonShape3D() {
1153
}
1154
1155
/********** FACE POLYGON *************/
1156
1157
void GodotFaceShape3D::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const {
1158
for (int i = 0; i < 3; i++) {
1159
Vector3 v = p_transform.xform(vertex[i]);
1160
real_t d = p_normal.dot(v);
1161
1162
if (i == 0 || d > r_max) {
1163
r_max = d;
1164
}
1165
1166
if (i == 0 || d < r_min) {
1167
r_min = d;
1168
}
1169
}
1170
}
1171
1172
Vector3 GodotFaceShape3D::get_support(const Vector3 &p_normal) const {
1173
int vert_support_idx = -1;
1174
real_t support_max = 0;
1175
1176
for (int i = 0; i < 3; i++) {
1177
real_t d = p_normal.dot(vertex[i]);
1178
1179
if (i == 0 || d > support_max) {
1180
support_max = d;
1181
vert_support_idx = i;
1182
}
1183
}
1184
1185
return vertex[vert_support_idx];
1186
}
1187
1188
void GodotFaceShape3D::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const {
1189
Vector3 n = p_normal;
1190
1191
/** TEST FACE AS SUPPORT **/
1192
if (Math::abs(normal.dot(n)) > face_support_threshold) {
1193
r_amount = 3;
1194
r_type = FEATURE_FACE;
1195
for (int i = 0; i < 3; i++) {
1196
r_supports[i] = vertex[i];
1197
}
1198
return;
1199
}
1200
1201
/** FIND SUPPORT VERTEX **/
1202
1203
int vert_support_idx = -1;
1204
real_t support_max = 0;
1205
1206
for (int i = 0; i < 3; i++) {
1207
real_t d = n.dot(vertex[i]);
1208
1209
if (i == 0 || d > support_max) {
1210
support_max = d;
1211
vert_support_idx = i;
1212
}
1213
}
1214
1215
/** TEST EDGES AS SUPPORT **/
1216
1217
for (int i = 0; i < 3; i++) {
1218
int nx = (i + 1) % 3;
1219
if (i != vert_support_idx && nx != vert_support_idx) {
1220
continue;
1221
}
1222
1223
// check if edge is valid as a support
1224
real_t dot = (vertex[i] - vertex[nx]).normalized().dot(n);
1225
dot = Math::abs(dot);
1226
if (dot < edge_support_threshold_lower) {
1227
r_amount = 2;
1228
r_type = FEATURE_EDGE;
1229
r_supports[0] = vertex[i];
1230
r_supports[1] = vertex[nx];
1231
return;
1232
}
1233
}
1234
1235
r_amount = 1;
1236
r_type = FEATURE_POINT;
1237
r_supports[0] = vertex[vert_support_idx];
1238
}
1239
1240
bool GodotFaceShape3D::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 {
1241
bool c = Geometry3D::segment_intersects_triangle(p_begin, p_end, vertex[0], vertex[1], vertex[2], &r_result);
1242
if (c) {
1243
r_normal = Plane(vertex[0], vertex[1], vertex[2]).normal;
1244
if (r_normal.dot(p_end - p_begin) > 0) {
1245
if (backface_collision && p_hit_back_faces) {
1246
r_normal = -r_normal;
1247
} else {
1248
c = false;
1249
}
1250
}
1251
}
1252
1253
return c;
1254
}
1255
1256
bool GodotFaceShape3D::intersect_point(const Vector3 &p_point) const {
1257
return false; //face is flat
1258
}
1259
1260
Vector3 GodotFaceShape3D::get_closest_point_to(const Vector3 &p_point) const {
1261
return Face3(vertex[0], vertex[1], vertex[2]).get_closest_point_to(p_point);
1262
}
1263
1264
Vector3 GodotFaceShape3D::get_moment_of_inertia(real_t p_mass) const {
1265
return Vector3(); // Sorry, but i don't think anyone cares, FaceShape!
1266
}
1267
1268
GodotFaceShape3D::GodotFaceShape3D() {
1269
configure(AABB());
1270
}
1271
1272
Vector<Vector3> GodotConcavePolygonShape3D::get_faces() const {
1273
Vector<Vector3> rfaces;
1274
rfaces.resize(faces.size() * 3);
1275
1276
for (int i = 0; i < faces.size(); i++) {
1277
Face f = faces.get(i);
1278
1279
for (int j = 0; j < 3; j++) {
1280
rfaces.set(i * 3 + j, vertices.get(f.indices[j]));
1281
}
1282
}
1283
1284
return rfaces;
1285
}
1286
1287
void GodotConcavePolygonShape3D::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const {
1288
int count = vertices.size();
1289
if (count == 0) {
1290
r_min = 0;
1291
r_max = 0;
1292
return;
1293
}
1294
const Vector3 *vptr = vertices.ptr();
1295
1296
for (int i = 0; i < count; i++) {
1297
real_t d = p_normal.dot(p_transform.xform(vptr[i]));
1298
1299
if (i == 0 || d > r_max) {
1300
r_max = d;
1301
}
1302
if (i == 0 || d < r_min) {
1303
r_min = d;
1304
}
1305
}
1306
}
1307
1308
Vector3 GodotConcavePolygonShape3D::get_support(const Vector3 &p_normal) const {
1309
int count = vertices.size();
1310
if (count == 0) {
1311
return Vector3();
1312
}
1313
1314
const Vector3 *vptr = vertices.ptr();
1315
1316
Vector3 n = p_normal;
1317
1318
int vert_support_idx = -1;
1319
real_t support_max = 0;
1320
1321
for (int i = 0; i < count; i++) {
1322
real_t d = n.dot(vptr[i]);
1323
1324
if (i == 0 || d > support_max) {
1325
support_max = d;
1326
vert_support_idx = i;
1327
}
1328
}
1329
1330
return vptr[vert_support_idx];
1331
}
1332
1333
void GodotConcavePolygonShape3D::_cull_segment(int p_idx, _SegmentCullParams *p_params) const {
1334
const BVH *params_bvh = &p_params->bvh[p_idx];
1335
1336
if (!params_bvh->aabb.intersects_segment(p_params->from, p_params->to)) {
1337
return;
1338
}
1339
1340
if (params_bvh->face_index >= 0) {
1341
const Face *f = &p_params->faces[params_bvh->face_index];
1342
GodotFaceShape3D *face = p_params->face;
1343
face->normal = f->normal;
1344
face->vertex[0] = p_params->vertices[f->indices[0]];
1345
face->vertex[1] = p_params->vertices[f->indices[1]];
1346
face->vertex[2] = p_params->vertices[f->indices[2]];
1347
1348
Vector3 res;
1349
Vector3 normal;
1350
int face_index = params_bvh->face_index;
1351
if (face->intersect_segment(p_params->from, p_params->to, res, normal, face_index, true)) {
1352
real_t d = p_params->dir.dot(res) - p_params->dir.dot(p_params->from);
1353
if ((d > 0) && (d < p_params->min_d)) {
1354
p_params->min_d = d;
1355
p_params->result = res;
1356
p_params->normal = normal;
1357
p_params->face_index = face_index;
1358
p_params->collisions++;
1359
}
1360
}
1361
} else {
1362
if (params_bvh->left >= 0) {
1363
_cull_segment(params_bvh->left, p_params);
1364
}
1365
if (params_bvh->right >= 0) {
1366
_cull_segment(params_bvh->right, p_params);
1367
}
1368
}
1369
}
1370
1371
bool GodotConcavePolygonShape3D::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 {
1372
if (faces.is_empty()) {
1373
return false;
1374
}
1375
1376
// unlock data
1377
const Face *fr = faces.ptr();
1378
const Vector3 *vr = vertices.ptr();
1379
const BVH *br = bvh.ptr();
1380
1381
GodotFaceShape3D face;
1382
face.backface_collision = backface_collision && p_hit_back_faces;
1383
1384
_SegmentCullParams params;
1385
params.from = p_begin;
1386
params.to = p_end;
1387
params.dir = (p_end - p_begin).normalized();
1388
1389
params.faces = fr;
1390
params.vertices = vr;
1391
params.bvh = br;
1392
1393
params.face = &face;
1394
1395
// cull
1396
_cull_segment(0, &params);
1397
1398
if (params.collisions > 0) {
1399
r_result = params.result;
1400
r_normal = params.normal;
1401
r_face_index = params.face_index;
1402
return true;
1403
} else {
1404
return false;
1405
}
1406
}
1407
1408
bool GodotConcavePolygonShape3D::intersect_point(const Vector3 &p_point) const {
1409
return false; //face is flat
1410
}
1411
1412
Vector3 GodotConcavePolygonShape3D::get_closest_point_to(const Vector3 &p_point) const {
1413
return Vector3();
1414
}
1415
1416
bool GodotConcavePolygonShape3D::_cull(int p_idx, _CullParams *p_params) const {
1417
const BVH *params_bvh = &p_params->bvh[p_idx];
1418
1419
if (!p_params->aabb.intersects(params_bvh->aabb)) {
1420
return false;
1421
}
1422
1423
if (params_bvh->face_index >= 0) {
1424
const Face *f = &p_params->faces[params_bvh->face_index];
1425
GodotFaceShape3D *face = p_params->face;
1426
face->normal = f->normal;
1427
face->vertex[0] = p_params->vertices[f->indices[0]];
1428
face->vertex[1] = p_params->vertices[f->indices[1]];
1429
face->vertex[2] = p_params->vertices[f->indices[2]];
1430
if (p_params->callback(p_params->userdata, face)) {
1431
return true;
1432
}
1433
} else {
1434
if (params_bvh->left >= 0) {
1435
if (_cull(params_bvh->left, p_params)) {
1436
return true;
1437
}
1438
}
1439
1440
if (params_bvh->right >= 0) {
1441
if (_cull(params_bvh->right, p_params)) {
1442
return true;
1443
}
1444
}
1445
}
1446
1447
return false;
1448
}
1449
1450
void GodotConcavePolygonShape3D::cull(const AABB &p_local_aabb, QueryCallback p_callback, void *p_userdata, bool p_invert_backface_collision) const {
1451
// make matrix local to concave
1452
if (faces.is_empty()) {
1453
return;
1454
}
1455
1456
AABB local_aabb = p_local_aabb;
1457
1458
// unlock data
1459
const Face *fr = faces.ptr();
1460
const Vector3 *vr = vertices.ptr();
1461
const BVH *br = bvh.ptr();
1462
1463
GodotFaceShape3D face; // use this to send in the callback
1464
face.backface_collision = backface_collision;
1465
face.invert_backface_collision = p_invert_backface_collision;
1466
1467
_CullParams params;
1468
params.aabb = local_aabb;
1469
params.face = &face;
1470
params.faces = fr;
1471
params.vertices = vr;
1472
params.bvh = br;
1473
params.callback = p_callback;
1474
params.userdata = p_userdata;
1475
1476
// cull
1477
_cull(0, &params);
1478
}
1479
1480
Vector3 GodotConcavePolygonShape3D::get_moment_of_inertia(real_t p_mass) const {
1481
// use bad AABB approximation
1482
Vector3 extents = get_aabb().size * 0.5;
1483
1484
return Vector3(
1485
(p_mass / 3.0) * (extents.y * extents.y + extents.z * extents.z),
1486
(p_mass / 3.0) * (extents.x * extents.x + extents.z * extents.z),
1487
(p_mass / 3.0) * (extents.x * extents.x + extents.y * extents.y));
1488
}
1489
1490
struct _Volume_BVH_Element {
1491
AABB aabb;
1492
Vector3 center;
1493
int face_index = 0;
1494
};
1495
1496
struct _Volume_BVH_CompareX {
1497
_FORCE_INLINE_ bool operator()(const _Volume_BVH_Element &a, const _Volume_BVH_Element &b) const {
1498
return a.center.x < b.center.x;
1499
}
1500
};
1501
1502
struct _Volume_BVH_CompareY {
1503
_FORCE_INLINE_ bool operator()(const _Volume_BVH_Element &a, const _Volume_BVH_Element &b) const {
1504
return a.center.y < b.center.y;
1505
}
1506
};
1507
1508
struct _Volume_BVH_CompareZ {
1509
_FORCE_INLINE_ bool operator()(const _Volume_BVH_Element &a, const _Volume_BVH_Element &b) const {
1510
return a.center.z < b.center.z;
1511
}
1512
};
1513
1514
struct _Volume_BVH {
1515
AABB aabb;
1516
_Volume_BVH *left = nullptr;
1517
_Volume_BVH *right = nullptr;
1518
1519
int face_index = 0;
1520
};
1521
1522
_Volume_BVH *_volume_build_bvh(_Volume_BVH_Element *p_elements, int p_size, int &count) {
1523
_Volume_BVH *bvh = memnew(_Volume_BVH);
1524
1525
if (p_size == 1) {
1526
//leaf
1527
bvh->aabb = p_elements[0].aabb;
1528
bvh->left = nullptr;
1529
bvh->right = nullptr;
1530
bvh->face_index = p_elements->face_index;
1531
count++;
1532
return bvh;
1533
} else {
1534
bvh->face_index = -1;
1535
}
1536
1537
AABB aabb;
1538
for (int i = 0; i < p_size; i++) {
1539
if (i == 0) {
1540
aabb = p_elements[i].aabb;
1541
} else {
1542
aabb.merge_with(p_elements[i].aabb);
1543
}
1544
}
1545
bvh->aabb = aabb;
1546
switch (aabb.get_longest_axis_index()) {
1547
case 0: {
1548
SortArray<_Volume_BVH_Element, _Volume_BVH_CompareX> sort_x;
1549
sort_x.sort(p_elements, p_size);
1550
1551
} break;
1552
case 1: {
1553
SortArray<_Volume_BVH_Element, _Volume_BVH_CompareY> sort_y;
1554
sort_y.sort(p_elements, p_size);
1555
} break;
1556
case 2: {
1557
SortArray<_Volume_BVH_Element, _Volume_BVH_CompareZ> sort_z;
1558
sort_z.sort(p_elements, p_size);
1559
} break;
1560
}
1561
1562
int split = p_size / 2;
1563
bvh->left = _volume_build_bvh(p_elements, split, count);
1564
bvh->right = _volume_build_bvh(&p_elements[split], p_size - split, count);
1565
1566
//printf("branch at %p - %i: %i\n",bvh,count,bvh->face_index);
1567
count++;
1568
return bvh;
1569
}
1570
1571
void GodotConcavePolygonShape3D::_fill_bvh(_Volume_BVH *p_bvh_tree, BVH *p_bvh_array, int &p_idx) {
1572
int idx = p_idx;
1573
1574
p_bvh_array[idx].aabb = p_bvh_tree->aabb;
1575
p_bvh_array[idx].face_index = p_bvh_tree->face_index;
1576
//printf("%p - %i: %i(%p) -- %p:%p\n",%p_bvh_array[idx],p_idx,p_bvh_array[i]->face_index,&p_bvh_tree->face_index,p_bvh_tree->left,p_bvh_tree->right);
1577
1578
if (p_bvh_tree->left) {
1579
p_bvh_array[idx].left = ++p_idx;
1580
_fill_bvh(p_bvh_tree->left, p_bvh_array, p_idx);
1581
1582
} else {
1583
p_bvh_array[p_idx].left = -1;
1584
}
1585
1586
if (p_bvh_tree->right) {
1587
p_bvh_array[idx].right = ++p_idx;
1588
_fill_bvh(p_bvh_tree->right, p_bvh_array, p_idx);
1589
1590
} else {
1591
p_bvh_array[p_idx].right = -1;
1592
}
1593
1594
memdelete(p_bvh_tree);
1595
}
1596
1597
void GodotConcavePolygonShape3D::_setup(const Vector<Vector3> &p_faces, bool p_backface_collision) {
1598
int src_face_count = p_faces.size();
1599
if (src_face_count == 0) {
1600
configure(AABB());
1601
return;
1602
}
1603
ERR_FAIL_COND(src_face_count % 3);
1604
src_face_count /= 3;
1605
1606
const Vector3 *facesr = p_faces.ptr();
1607
1608
Vector<_Volume_BVH_Element> bvh_array;
1609
bvh_array.resize(src_face_count);
1610
1611
_Volume_BVH_Element *bvh_arrayw = bvh_array.ptrw();
1612
1613
faces.resize(src_face_count);
1614
Face *facesw = faces.ptrw();
1615
1616
vertices.resize(src_face_count * 3);
1617
1618
Vector3 *verticesw = vertices.ptrw();
1619
1620
AABB _aabb;
1621
1622
for (int i = 0; i < src_face_count; i++) {
1623
Face3 face(facesr[i * 3 + 0], facesr[i * 3 + 1], facesr[i * 3 + 2]);
1624
1625
bvh_arrayw[i].aabb = face.get_aabb();
1626
bvh_arrayw[i].center = bvh_arrayw[i].aabb.get_center();
1627
bvh_arrayw[i].face_index = i;
1628
facesw[i].indices[0] = i * 3 + 0;
1629
facesw[i].indices[1] = i * 3 + 1;
1630
facesw[i].indices[2] = i * 3 + 2;
1631
facesw[i].normal = face.get_plane().normal;
1632
verticesw[i * 3 + 0] = face.vertex[0];
1633
verticesw[i * 3 + 1] = face.vertex[1];
1634
verticesw[i * 3 + 2] = face.vertex[2];
1635
if (i == 0) {
1636
_aabb = bvh_arrayw[i].aabb;
1637
} else {
1638
_aabb.merge_with(bvh_arrayw[i].aabb);
1639
}
1640
}
1641
1642
int count = 0;
1643
_Volume_BVH *bvh_tree = _volume_build_bvh(bvh_arrayw, src_face_count, count);
1644
1645
bvh.resize(count + 1);
1646
1647
BVH *bvh_arrayw2 = bvh.ptrw();
1648
1649
int idx = 0;
1650
_fill_bvh(bvh_tree, bvh_arrayw2, idx);
1651
1652
backface_collision = p_backface_collision;
1653
1654
configure(_aabb); // this type of shape has no margin
1655
}
1656
1657
void GodotConcavePolygonShape3D::set_data(const Variant &p_data) {
1658
Dictionary d = p_data;
1659
ERR_FAIL_COND(!d.has("faces"));
1660
1661
_setup(d["faces"], d["backface_collision"]);
1662
}
1663
1664
Variant GodotConcavePolygonShape3D::get_data() const {
1665
Dictionary d;
1666
d["faces"] = get_faces();
1667
d["backface_collision"] = backface_collision;
1668
1669
return d;
1670
}
1671
1672
GodotConcavePolygonShape3D::GodotConcavePolygonShape3D() {
1673
}
1674
1675
/* HEIGHT MAP SHAPE */
1676
1677
Vector<real_t> GodotHeightMapShape3D::get_heights() const {
1678
return heights;
1679
}
1680
1681
int GodotHeightMapShape3D::get_width() const {
1682
return width;
1683
}
1684
1685
int GodotHeightMapShape3D::get_depth() const {
1686
return depth;
1687
}
1688
1689
void GodotHeightMapShape3D::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const {
1690
//not very useful, but not very used either
1691
p_transform.xform(get_aabb()).project_range_in_plane(Plane(p_normal), r_min, r_max);
1692
}
1693
1694
Vector3 GodotHeightMapShape3D::get_support(const Vector3 &p_normal) const {
1695
//not very useful, but not very used either
1696
return get_aabb().get_support(p_normal);
1697
}
1698
1699
struct _HeightmapSegmentCullParams {
1700
Vector3 from;
1701
Vector3 to;
1702
Vector3 dir;
1703
1704
Vector3 result;
1705
Vector3 normal;
1706
1707
const GodotHeightMapShape3D *heightmap = nullptr;
1708
GodotFaceShape3D *face = nullptr;
1709
};
1710
1711
struct _HeightmapGridCullState {
1712
real_t length = 0.0;
1713
real_t length_flat = 0.0;
1714
1715
real_t dist = 0.0;
1716
real_t prev_dist = 0.0;
1717
1718
int x = 0;
1719
int z = 0;
1720
};
1721
1722
_FORCE_INLINE_ bool _heightmap_face_cull_segment(_HeightmapSegmentCullParams &p_params) {
1723
Vector3 res;
1724
Vector3 normal;
1725
int fi = -1;
1726
if (p_params.face->intersect_segment(p_params.from, p_params.to, res, normal, fi, true)) {
1727
p_params.result = res;
1728
p_params.normal = normal;
1729
1730
return true;
1731
}
1732
1733
return false;
1734
}
1735
1736
_FORCE_INLINE_ bool _heightmap_cell_cull_segment(_HeightmapSegmentCullParams &p_params, const _HeightmapGridCullState &p_state) {
1737
// First triangle.
1738
p_params.heightmap->_get_point(p_state.x, p_state.z, p_params.face->vertex[0]);
1739
p_params.heightmap->_get_point(p_state.x + 1, p_state.z, p_params.face->vertex[1]);
1740
p_params.heightmap->_get_point(p_state.x, p_state.z + 1, p_params.face->vertex[2]);
1741
p_params.face->normal = Plane(p_params.face->vertex[0], p_params.face->vertex[1], p_params.face->vertex[2]).normal;
1742
if (_heightmap_face_cull_segment(p_params)) {
1743
return true;
1744
}
1745
1746
// Second triangle.
1747
p_params.face->vertex[0] = p_params.face->vertex[1];
1748
p_params.heightmap->_get_point(p_state.x + 1, p_state.z + 1, p_params.face->vertex[1]);
1749
p_params.face->normal = Plane(p_params.face->vertex[0], p_params.face->vertex[1], p_params.face->vertex[2]).normal;
1750
if (_heightmap_face_cull_segment(p_params)) {
1751
return true;
1752
}
1753
1754
return false;
1755
}
1756
1757
_FORCE_INLINE_ bool _heightmap_chunk_cull_segment(_HeightmapSegmentCullParams &p_params, const _HeightmapGridCullState &p_state) {
1758
const GodotHeightMapShape3D::Range &chunk = p_params.heightmap->_get_bounds_chunk(p_state.x, p_state.z);
1759
1760
Vector3 enter_pos;
1761
Vector3 exit_pos;
1762
1763
if (p_state.length_flat > CMP_EPSILON) {
1764
real_t flat_to_3d = p_state.length / p_state.length_flat;
1765
real_t enter_param = p_state.prev_dist * flat_to_3d;
1766
real_t exit_param = p_state.dist * flat_to_3d;
1767
enter_pos = p_params.from + p_params.dir * enter_param;
1768
exit_pos = p_params.from + p_params.dir * exit_param;
1769
} else {
1770
// Consider the ray vertical.
1771
// (though we shouldn't reach this often because there is an early check up-front)
1772
enter_pos = p_params.from;
1773
exit_pos = p_params.to;
1774
}
1775
1776
// Transform positions to heightmap space.
1777
enter_pos *= GodotHeightMapShape3D::BOUNDS_CHUNK_SIZE;
1778
exit_pos *= GodotHeightMapShape3D::BOUNDS_CHUNK_SIZE;
1779
1780
// We did enter the flat projection of the AABB,
1781
// but we have to check if we intersect it on the vertical axis.
1782
if ((enter_pos.y > chunk.max) && (exit_pos.y > chunk.max)) {
1783
return false;
1784
}
1785
if ((enter_pos.y < chunk.min) && (exit_pos.y < chunk.min)) {
1786
return false;
1787
}
1788
1789
return p_params.heightmap->_intersect_grid_segment(_heightmap_cell_cull_segment, enter_pos, exit_pos, p_params.heightmap->width, p_params.heightmap->depth, p_params.heightmap->local_origin, p_params.result, p_params.normal);
1790
}
1791
1792
template <typename ProcessFunction>
1793
bool GodotHeightMapShape3D::_intersect_grid_segment(ProcessFunction &p_process, const Vector3 &p_begin, const Vector3 &p_end, int p_width, int p_depth, const Vector3 &offset, Vector3 &r_point, Vector3 &r_normal) const {
1794
Vector3 delta = (p_end - p_begin);
1795
real_t length = delta.length();
1796
1797
if (length < CMP_EPSILON) {
1798
return false;
1799
}
1800
1801
Vector3 local_begin = p_begin + offset;
1802
1803
GodotFaceShape3D face;
1804
face.backface_collision = false;
1805
1806
_HeightmapSegmentCullParams params;
1807
params.from = p_begin;
1808
params.to = p_end;
1809
params.dir = delta / length;
1810
params.heightmap = this;
1811
params.face = &face;
1812
1813
_HeightmapGridCullState state;
1814
1815
// Perform grid query from projected ray.
1816
Vector2 ray_dir_flat(delta.x, delta.z);
1817
state.length = length;
1818
state.length_flat = ray_dir_flat.length();
1819
1820
if (state.length_flat < CMP_EPSILON) {
1821
ray_dir_flat = Vector2();
1822
} else {
1823
ray_dir_flat /= state.length_flat;
1824
}
1825
1826
const int x_step = (ray_dir_flat.x > CMP_EPSILON) ? 1 : ((ray_dir_flat.x < -CMP_EPSILON) ? -1 : 0);
1827
const int z_step = (ray_dir_flat.y > CMP_EPSILON) ? 1 : ((ray_dir_flat.y < -CMP_EPSILON) ? -1 : 0);
1828
1829
const real_t infinite = 1e20;
1830
const real_t delta_x = (x_step != 0) ? 1.f / Math::abs(ray_dir_flat.x) : infinite;
1831
const real_t delta_z = (z_step != 0) ? 1.f / Math::abs(ray_dir_flat.y) : infinite;
1832
1833
real_t cross_x; // At which value of `param` we will cross a x-axis lane?
1834
real_t cross_z; // At which value of `param` we will cross a z-axis lane?
1835
1836
// X initialization.
1837
if (x_step != 0) {
1838
if (x_step == 1) {
1839
cross_x = (Math::ceil(local_begin.x) - local_begin.x) * delta_x;
1840
} else {
1841
cross_x = (local_begin.x - Math::floor(local_begin.x)) * delta_x;
1842
}
1843
} else {
1844
cross_x = infinite; // Will never cross on X.
1845
}
1846
1847
// Z initialization.
1848
if (z_step != 0) {
1849
if (z_step == 1) {
1850
cross_z = (Math::ceil(local_begin.z) - local_begin.z) * delta_z;
1851
} else {
1852
cross_z = (local_begin.z - Math::floor(local_begin.z)) * delta_z;
1853
}
1854
} else {
1855
cross_z = infinite; // Will never cross on Z.
1856
}
1857
1858
int x = Math::floor(local_begin.x);
1859
int z = Math::floor(local_begin.z);
1860
1861
// Workaround cases where the ray starts at an integer position.
1862
if (Math::is_zero_approx(cross_x)) {
1863
cross_x += delta_x;
1864
// If going backwards, we should ignore the position we would get by the above flooring,
1865
// because the ray is not heading in that direction.
1866
if (x_step == -1) {
1867
x -= 1;
1868
}
1869
}
1870
1871
if (Math::is_zero_approx(cross_z)) {
1872
cross_z += delta_z;
1873
if (z_step == -1) {
1874
z -= 1;
1875
}
1876
}
1877
1878
// Start inside the grid.
1879
int x_start = MAX(MIN(x, p_width - 2), 0);
1880
int z_start = MAX(MIN(z, p_depth - 2), 0);
1881
1882
// Adjust initial cross values.
1883
cross_x += delta_x * x_step * (x_start - x);
1884
cross_z += delta_z * z_step * (z_start - z);
1885
1886
x = x_start;
1887
z = z_start;
1888
1889
while (true) {
1890
state.prev_dist = state.dist;
1891
state.x = x;
1892
state.z = z;
1893
1894
if (cross_x < cross_z) {
1895
// X lane.
1896
x += x_step;
1897
// Assign before advancing the param,
1898
// to be in sync with the initialization step.
1899
state.dist = cross_x;
1900
cross_x += delta_x;
1901
} else {
1902
// Z lane.
1903
z += z_step;
1904
state.dist = cross_z;
1905
cross_z += delta_z;
1906
}
1907
1908
if (state.dist > state.length_flat) {
1909
state.dist = state.length_flat;
1910
if (p_process(params, state)) {
1911
r_point = params.result;
1912
r_normal = params.normal;
1913
return true;
1914
}
1915
break;
1916
}
1917
1918
if (p_process(params, state)) {
1919
r_point = params.result;
1920
r_normal = params.normal;
1921
return true;
1922
}
1923
1924
// Stop when outside the grid.
1925
if ((x < 0) || (z < 0) || (x >= p_width - 1) || (z >= p_depth - 1)) {
1926
break;
1927
}
1928
}
1929
1930
return false;
1931
}
1932
1933
bool GodotHeightMapShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal, int &r_face_index, bool p_hit_back_faces) const {
1934
if (heights.is_empty()) {
1935
return false;
1936
}
1937
1938
Vector3 local_begin = p_begin + local_origin;
1939
Vector3 local_end = p_end + local_origin;
1940
1941
// Quantize the ray begin/end.
1942
int begin_x = Math::floor(local_begin.x);
1943
int begin_z = Math::floor(local_begin.z);
1944
int end_x = Math::floor(local_end.x);
1945
int end_z = Math::floor(local_end.z);
1946
1947
if ((begin_x == end_x) && (begin_z == end_z)) {
1948
// Simple case for rays that don't traverse the grid horizontally.
1949
// Just perform a test on the given cell.
1950
GodotFaceShape3D face;
1951
face.backface_collision = p_hit_back_faces;
1952
1953
_HeightmapSegmentCullParams params;
1954
params.from = p_begin;
1955
params.to = p_end;
1956
params.dir = (p_end - p_begin).normalized();
1957
1958
params.heightmap = this;
1959
params.face = &face;
1960
1961
_HeightmapGridCullState state;
1962
state.x = MAX(MIN(begin_x, width - 2), 0);
1963
state.z = MAX(MIN(begin_z, depth - 2), 0);
1964
if (_heightmap_cell_cull_segment(params, state)) {
1965
r_point = params.result;
1966
r_normal = params.normal;
1967
return true;
1968
}
1969
} else if (bounds_grid.is_empty()) {
1970
// Process all cells intersecting the flat projection of the ray.
1971
return _intersect_grid_segment(_heightmap_cell_cull_segment, p_begin, p_end, width, depth, local_origin, r_point, r_normal);
1972
} else {
1973
Vector3 ray_diff = (p_end - p_begin);
1974
real_t length_flat_sqr = ray_diff.x * ray_diff.x + ray_diff.z * ray_diff.z;
1975
if (length_flat_sqr < BOUNDS_CHUNK_SIZE * BOUNDS_CHUNK_SIZE) {
1976
// Don't use chunks, the ray is too short in the plane.
1977
return _intersect_grid_segment(_heightmap_cell_cull_segment, p_begin, p_end, width, depth, local_origin, r_point, r_normal);
1978
} else {
1979
// The ray is long, run raycast on a higher-level grid.
1980
Vector3 bounds_from = p_begin / BOUNDS_CHUNK_SIZE;
1981
Vector3 bounds_to = p_end / BOUNDS_CHUNK_SIZE;
1982
Vector3 bounds_offset = local_origin / BOUNDS_CHUNK_SIZE;
1983
// Plus 1 here to width and depth of the chunk because _intersect_grid_segment() is used by cell level as well,
1984
// and in _intersect_grid_segment() the loop will exit 1 early because for cell point triangle lookup, it dose x + 1, z + 1 etc for the vertex.
1985
int bounds_width = bounds_grid_width + 1;
1986
int bounds_depth = bounds_grid_depth + 1;
1987
return _intersect_grid_segment(_heightmap_chunk_cull_segment, bounds_from, bounds_to, bounds_width, bounds_depth, bounds_offset, r_point, r_normal);
1988
}
1989
}
1990
1991
return false;
1992
}
1993
1994
bool GodotHeightMapShape3D::intersect_point(const Vector3 &p_point) const {
1995
return false;
1996
}
1997
1998
Vector3 GodotHeightMapShape3D::get_closest_point_to(const Vector3 &p_point) const {
1999
return Vector3();
2000
}
2001
2002
void GodotHeightMapShape3D::_get_cell(const Vector3 &p_point, int &r_x, int &r_y, int &r_z) const {
2003
const AABB &shape_aabb = get_aabb();
2004
2005
Vector3 pos_local = shape_aabb.position + local_origin;
2006
2007
Vector3 clamped_point(p_point);
2008
clamped_point = p_point.clamp(pos_local, pos_local + shape_aabb.size);
2009
2010
r_x = (clamped_point.x < 0.0) ? (clamped_point.x - 0.5) : (clamped_point.x + 0.5);
2011
r_y = (clamped_point.y < 0.0) ? (clamped_point.y - 0.5) : (clamped_point.y + 0.5);
2012
r_z = (clamped_point.z < 0.0) ? (clamped_point.z - 0.5) : (clamped_point.z + 0.5);
2013
}
2014
2015
void GodotHeightMapShape3D::cull(const AABB &p_local_aabb, QueryCallback p_callback, void *p_userdata, bool p_invert_backface_collision) const {
2016
if (heights.is_empty()) {
2017
return;
2018
}
2019
2020
AABB local_aabb = p_local_aabb;
2021
local_aabb.position += local_origin;
2022
2023
// Quantize the aabb, and adjust the start/end ranges.
2024
int aabb_min[3];
2025
int aabb_max[3];
2026
_get_cell(local_aabb.position, aabb_min[0], aabb_min[1], aabb_min[2]);
2027
_get_cell(local_aabb.position + local_aabb.size, aabb_max[0], aabb_max[1], aabb_max[2]);
2028
2029
// Expand the min/max quantized values.
2030
// This is to catch the case where the input aabb falls between grid points.
2031
for (int i = 0; i < 3; ++i) {
2032
aabb_min[i]--;
2033
aabb_max[i]++;
2034
}
2035
2036
int start_x = MAX(0, aabb_min[0]);
2037
int end_x = MIN(width - 1, aabb_max[0]);
2038
int start_z = MAX(0, aabb_min[2]);
2039
int end_z = MIN(depth - 1, aabb_max[2]);
2040
2041
GodotFaceShape3D face;
2042
face.backface_collision = !p_invert_backface_collision;
2043
face.invert_backface_collision = p_invert_backface_collision;
2044
2045
for (int z = start_z; z < end_z; z++) {
2046
for (int x = start_x; x < end_x; x++) {
2047
// First triangle.
2048
_get_point(x, z, face.vertex[0]);
2049
_get_point(x + 1, z, face.vertex[1]);
2050
_get_point(x, z + 1, face.vertex[2]);
2051
face.normal = Plane(face.vertex[0], face.vertex[1], face.vertex[2]).normal;
2052
if (p_callback(p_userdata, &face)) {
2053
return;
2054
}
2055
2056
// Second triangle.
2057
face.vertex[0] = face.vertex[1];
2058
_get_point(x + 1, z + 1, face.vertex[1]);
2059
face.normal = Plane(face.vertex[0], face.vertex[1], face.vertex[2]).normal;
2060
if (p_callback(p_userdata, &face)) {
2061
return;
2062
}
2063
}
2064
}
2065
}
2066
2067
Vector3 GodotHeightMapShape3D::get_moment_of_inertia(real_t p_mass) const {
2068
// use bad AABB approximation
2069
Vector3 extents = get_aabb().size * 0.5;
2070
2071
return Vector3(
2072
(p_mass / 3.0) * (extents.y * extents.y + extents.z * extents.z),
2073
(p_mass / 3.0) * (extents.x * extents.x + extents.z * extents.z),
2074
(p_mass / 3.0) * (extents.x * extents.x + extents.y * extents.y));
2075
}
2076
2077
void GodotHeightMapShape3D::_build_accelerator() {
2078
bounds_grid.clear();
2079
2080
bounds_grid_width = width / BOUNDS_CHUNK_SIZE;
2081
bounds_grid_depth = depth / BOUNDS_CHUNK_SIZE;
2082
2083
if (width % BOUNDS_CHUNK_SIZE > 0) {
2084
++bounds_grid_width; // In case terrain size isn't dividable by chunk size.
2085
}
2086
2087
if (depth % BOUNDS_CHUNK_SIZE > 0) {
2088
++bounds_grid_depth;
2089
}
2090
2091
uint32_t bound_grid_size = (uint32_t)(bounds_grid_width * bounds_grid_depth);
2092
2093
if (bound_grid_size < 2) {
2094
// Grid is empty or just one chunk.
2095
return;
2096
}
2097
2098
bounds_grid.resize(bound_grid_size);
2099
2100
// Compute min and max height for all chunks.
2101
for (int cz = 0; cz < bounds_grid_depth; ++cz) {
2102
int z0 = cz * BOUNDS_CHUNK_SIZE;
2103
2104
for (int cx = 0; cx < bounds_grid_width; ++cx) {
2105
int x0 = cx * BOUNDS_CHUNK_SIZE;
2106
2107
Range r;
2108
2109
r.min = _get_height(x0, z0);
2110
r.max = r.min;
2111
2112
// Compute min and max height for this chunk.
2113
// We have to include one extra cell to account for neighbors.
2114
// Here is why:
2115
// Say we have a flat terrain, and a plateau that fits a chunk perfectly.
2116
//
2117
// Left Right
2118
// 0---0---0---1---1---1
2119
// | | | | | |
2120
// 0---0---0---1---1---1
2121
// | | | | | |
2122
// 0---0---0---1---1---1
2123
// x
2124
//
2125
// If the AABB for the Left chunk did not share vertices with the Right,
2126
// then we would fail collision tests at x due to a gap.
2127
//
2128
int z_max = MIN(z0 + BOUNDS_CHUNK_SIZE + 1, depth);
2129
int x_max = MIN(x0 + BOUNDS_CHUNK_SIZE + 1, width);
2130
for (int z = z0; z < z_max; ++z) {
2131
for (int x = x0; x < x_max; ++x) {
2132
real_t height = _get_height(x, z);
2133
if (height < r.min) {
2134
r.min = height;
2135
} else if (height > r.max) {
2136
r.max = height;
2137
}
2138
}
2139
}
2140
2141
bounds_grid[cx + cz * bounds_grid_width] = r;
2142
}
2143
}
2144
}
2145
2146
void GodotHeightMapShape3D::_setup(const Vector<real_t> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height) {
2147
heights = p_heights;
2148
width = p_width;
2149
depth = p_depth;
2150
2151
// Initialize aabb.
2152
AABB aabb_new;
2153
aabb_new.position = Vector3(0.0, p_min_height, 0.0);
2154
aabb_new.size = Vector3(p_width - 1, p_max_height - p_min_height, p_depth - 1);
2155
2156
// Initialize origin as the aabb center.
2157
local_origin = aabb_new.position + 0.5 * aabb_new.size;
2158
local_origin.y = 0.0;
2159
2160
aabb_new.position -= local_origin;
2161
2162
_build_accelerator();
2163
2164
configure(aabb_new);
2165
}
2166
2167
void GodotHeightMapShape3D::set_data(const Variant &p_data) {
2168
ERR_FAIL_COND(p_data.get_type() != Variant::DICTIONARY);
2169
2170
Dictionary d = p_data;
2171
ERR_FAIL_COND(!d.has("width"));
2172
ERR_FAIL_COND(!d.has("depth"));
2173
ERR_FAIL_COND(!d.has("heights"));
2174
2175
int width_new = d["width"];
2176
int depth_new = d["depth"];
2177
2178
ERR_FAIL_COND(width_new <= 0.0);
2179
ERR_FAIL_COND(depth_new <= 0.0);
2180
2181
Variant heights_variant = d["heights"];
2182
Vector<real_t> heights_buffer;
2183
#ifdef REAL_T_IS_DOUBLE
2184
if (heights_variant.get_type() == Variant::PACKED_FLOAT64_ARRAY) {
2185
#else
2186
if (heights_variant.get_type() == Variant::PACKED_FLOAT32_ARRAY) {
2187
#endif
2188
// Ready-to-use heights can be passed.
2189
heights_buffer = heights_variant;
2190
} else if (heights_variant.get_type() == Variant::OBJECT) {
2191
// If an image is passed, we have to convert it.
2192
// This would be expensive to do with a script, so it's nice to have it here.
2193
Ref<Image> image = heights_variant;
2194
ERR_FAIL_COND(image.is_null());
2195
ERR_FAIL_COND(image->get_format() != Image::FORMAT_RF);
2196
2197
PackedByteArray im_data = image->get_data();
2198
heights_buffer.resize(image->get_width() * image->get_height());
2199
2200
real_t *w = heights_buffer.ptrw();
2201
real_t *rp = (real_t *)im_data.ptr();
2202
for (int i = 0; i < heights_buffer.size(); ++i) {
2203
w[i] = rp[i];
2204
}
2205
} else {
2206
#ifdef REAL_T_IS_DOUBLE
2207
ERR_FAIL_MSG("Expected PackedFloat64Array or float Image.");
2208
#else
2209
ERR_FAIL_MSG("Expected PackedFloat32Array or float Image.");
2210
#endif
2211
}
2212
2213
// Compute min and max heights or use precomputed values.
2214
real_t min_height = 0.0;
2215
real_t max_height = 0.0;
2216
if (d.has("min_height") && d.has("max_height")) {
2217
min_height = d["min_height"];
2218
max_height = d["max_height"];
2219
} else {
2220
int heights_size = heights.size();
2221
for (int i = 0; i < heights_size; ++i) {
2222
real_t h = heights[i];
2223
if (h < min_height) {
2224
min_height = h;
2225
} else if (h > max_height) {
2226
max_height = h;
2227
}
2228
}
2229
}
2230
2231
ERR_FAIL_COND(min_height > max_height);
2232
2233
ERR_FAIL_COND(heights_buffer.size() != (width_new * depth_new));
2234
2235
// If specified, min and max height will be used as precomputed values.
2236
_setup(heights_buffer, width_new, depth_new, min_height, max_height);
2237
}
2238
2239
Variant GodotHeightMapShape3D::get_data() const {
2240
Dictionary d;
2241
d["width"] = width;
2242
d["depth"] = depth;
2243
2244
const AABB &shape_aabb = get_aabb();
2245
d["min_height"] = shape_aabb.position.y;
2246
d["max_height"] = shape_aabb.position.y + shape_aabb.size.y;
2247
2248
d["heights"] = heights;
2249
2250
return d;
2251
}
2252
2253
GodotHeightMapShape3D::GodotHeightMapShape3D() {
2254
}
2255
2256