Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/core/math/bvh_abb.h
9906 views
1
/**************************************************************************/
2
/* bvh_abb.h */
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
#pragma once
32
33
#include "core/math/aabb.h"
34
35
// special optimized version of axis aligned bounding box
36
template <typename BOUNDS = AABB, typename POINT = Vector3>
37
struct BVH_ABB {
38
struct ConvexHull {
39
// convex hulls (optional)
40
const Plane *planes;
41
int num_planes;
42
const Vector3 *points;
43
int num_points;
44
};
45
46
struct Segment {
47
POINT from;
48
POINT to;
49
};
50
51
enum IntersectResult {
52
IR_MISS = 0,
53
IR_PARTIAL,
54
IR_FULL,
55
};
56
57
// we store mins with a negative value in order to test them with SIMD
58
POINT min;
59
POINT neg_max;
60
61
bool operator==(const BVH_ABB &o) const { return (min == o.min) && (neg_max == o.neg_max); }
62
bool operator!=(const BVH_ABB &o) const { return (*this == o) == false; }
63
64
void set(const POINT &_min, const POINT &_max) {
65
min = _min;
66
neg_max = -_max;
67
}
68
69
// to and from standard AABB
70
void from(const BOUNDS &p_aabb) {
71
min = p_aabb.position;
72
neg_max = -(p_aabb.position + p_aabb.size);
73
}
74
75
void to(BOUNDS &r_aabb) const {
76
r_aabb.position = min;
77
r_aabb.size = calculate_size();
78
}
79
80
void merge(const BVH_ABB &p_o) {
81
for (int axis = 0; axis < POINT::AXIS_COUNT; ++axis) {
82
neg_max[axis] = MIN(neg_max[axis], p_o.neg_max[axis]);
83
min[axis] = MIN(min[axis], p_o.min[axis]);
84
}
85
}
86
87
POINT calculate_size() const {
88
return -neg_max - min;
89
}
90
91
POINT calculate_center() const {
92
return POINT((calculate_size() * 0.5) + min);
93
}
94
95
real_t get_proximity_to(const BVH_ABB &p_b) const {
96
const POINT d = (min - neg_max) - (p_b.min - p_b.neg_max);
97
real_t proximity = 0.0;
98
for (int axis = 0; axis < POINT::AXIS_COUNT; ++axis) {
99
proximity += Math::abs(d[axis]);
100
}
101
return proximity;
102
}
103
104
int select_by_proximity(const BVH_ABB &p_a, const BVH_ABB &p_b) const {
105
return (get_proximity_to(p_a) < get_proximity_to(p_b) ? 0 : 1);
106
}
107
108
uint32_t find_cutting_planes(const typename BVH_ABB::ConvexHull &p_hull, uint32_t *p_plane_ids) const {
109
uint32_t count = 0;
110
111
for (int n = 0; n < p_hull.num_planes; n++) {
112
const Plane &p = p_hull.planes[n];
113
if (intersects_plane(p)) {
114
p_plane_ids[count++] = n;
115
}
116
}
117
118
return count;
119
}
120
121
bool intersects_plane(const Plane &p_p) const {
122
Vector3 size = calculate_size();
123
Vector3 half_extents = size * 0.5;
124
Vector3 ofs = min + half_extents;
125
126
// forward side of plane?
127
Vector3 point_offset(
128
(p_p.normal.x < 0) ? -half_extents.x : half_extents.x,
129
(p_p.normal.y < 0) ? -half_extents.y : half_extents.y,
130
(p_p.normal.z < 0) ? -half_extents.z : half_extents.z);
131
Vector3 point = point_offset + ofs;
132
133
if (!p_p.is_point_over(point)) {
134
return false;
135
}
136
137
point = -point_offset + ofs;
138
if (p_p.is_point_over(point)) {
139
return false;
140
}
141
142
return true;
143
}
144
145
bool intersects_convex_optimized(const ConvexHull &p_hull, const uint32_t *p_plane_ids, uint32_t p_num_planes) const {
146
Vector3 size = calculate_size();
147
Vector3 half_extents = size * 0.5;
148
Vector3 ofs = min + half_extents;
149
150
for (unsigned int i = 0; i < p_num_planes; i++) {
151
const Plane &p = p_hull.planes[p_plane_ids[i]];
152
Vector3 point(
153
(p.normal.x > 0) ? -half_extents.x : half_extents.x,
154
(p.normal.y > 0) ? -half_extents.y : half_extents.y,
155
(p.normal.z > 0) ? -half_extents.z : half_extents.z);
156
point += ofs;
157
if (p.is_point_over(point)) {
158
return false;
159
}
160
}
161
162
return true;
163
}
164
165
bool intersects_convex_partial(const ConvexHull &p_hull) const {
166
BOUNDS bb;
167
to(bb);
168
return bb.intersects_convex_shape(p_hull.planes, p_hull.num_planes, p_hull.points, p_hull.num_points);
169
}
170
171
IntersectResult intersects_convex(const ConvexHull &p_hull) const {
172
if (intersects_convex_partial(p_hull)) {
173
// fully within? very important for tree checks
174
if (is_within_convex(p_hull)) {
175
return IR_FULL;
176
}
177
178
return IR_PARTIAL;
179
}
180
181
return IR_MISS;
182
}
183
184
bool is_within_convex(const ConvexHull &p_hull) const {
185
// use half extents routine
186
BOUNDS bb;
187
to(bb);
188
return bb.inside_convex_shape(p_hull.planes, p_hull.num_planes);
189
}
190
191
bool is_point_within_hull(const ConvexHull &p_hull, const Vector3 &p_pt) const {
192
for (int n = 0; n < p_hull.num_planes; n++) {
193
if (p_hull.planes[n].distance_to(p_pt) > 0.0f) {
194
return false;
195
}
196
}
197
return true;
198
}
199
200
bool intersects_segment(const Segment &p_s) const {
201
BOUNDS bb;
202
to(bb);
203
return bb.intersects_segment(p_s.from, p_s.to);
204
}
205
206
bool intersects_point(const POINT &p_pt) const {
207
if (_any_lessthan(-p_pt, neg_max)) {
208
return false;
209
}
210
if (_any_lessthan(p_pt, min)) {
211
return false;
212
}
213
return true;
214
}
215
216
// Very hot in profiling, make sure optimized
217
bool intersects(const BVH_ABB &p_o) const {
218
if (_any_morethan(p_o.min, -neg_max)) {
219
return false;
220
}
221
if (_any_morethan(min, -p_o.neg_max)) {
222
return false;
223
}
224
return true;
225
}
226
227
// for pre-swizzled tester (this object)
228
bool intersects_swizzled(const BVH_ABB &p_o) const {
229
if (_any_lessthan(min, p_o.min)) {
230
return false;
231
}
232
if (_any_lessthan(neg_max, p_o.neg_max)) {
233
return false;
234
}
235
return true;
236
}
237
238
bool is_other_within(const BVH_ABB &p_o) const {
239
if (_any_lessthan(p_o.neg_max, neg_max)) {
240
return false;
241
}
242
if (_any_lessthan(p_o.min, min)) {
243
return false;
244
}
245
return true;
246
}
247
248
void grow(const POINT &p_change) {
249
neg_max -= p_change;
250
min -= p_change;
251
}
252
253
void expand(real_t p_change) {
254
POINT change;
255
for (int axis = 0; axis < POINT::AXIS_COUNT; ++axis) {
256
change[axis] = p_change;
257
}
258
grow(change);
259
}
260
261
// Actually surface area metric.
262
real_t get_area() const {
263
POINT d = calculate_size();
264
return 2.0f * (d.x * d.y + d.y * d.z + d.z * d.x);
265
}
266
267
void set_to_max_opposite_extents() {
268
for (int axis = 0; axis < POINT::AXIS_COUNT; ++axis) {
269
neg_max[axis] = FLT_MAX;
270
}
271
min = neg_max;
272
}
273
274
bool _any_morethan(const POINT &p_a, const POINT &p_b) const {
275
for (int axis = 0; axis < POINT::AXIS_COUNT; ++axis) {
276
if (p_a[axis] > p_b[axis]) {
277
return true;
278
}
279
}
280
return false;
281
}
282
283
bool _any_lessthan(const POINT &p_a, const POINT &p_b) const {
284
for (int axis = 0; axis < POINT::AXIS_COUNT; ++axis) {
285
if (p_a[axis] < p_b[axis]) {
286
return true;
287
}
288
}
289
return false;
290
}
291
};
292
293