Nebula
Loading...
Searching...
No Matches
bbox.h
Go to the documentation of this file.
1#pragma once
2//------------------------------------------------------------------------------
12#include "math/vec3.h"
13#include "math/vec4.h"
14#include "math/mat4.h"
15#include "math/clipstatus.h"
16#include "math/sse.h"
17#include "util/array.h"
18#include "math/line.h"
19
20//------------------------------------------------------------------------------
21namespace Math
22{
23class bbox
24{
25public:
27 enum
28 {
35 };
36
38 bbox();
40 bbox(const point& center, const vector& extents);
42 bbox(const mat4& m);
44 point center() const;
46 vector extents() const;
48 vec3 size() const;
50 scalar diagonal_size() const;
52 void set(const mat4& m);
54 void set(const point& center, const vector& extents);
56 void begin_extend();
58 void extend(const vec3& p);
60 void extend(const bbox& box);
62 void end_extend();
64 void transform(const mat4& m);
66 void affine_transform(const mat4& m);
68 bool intersects(const bbox& box) const;
70 bool intersects(const line& ray, float& t) const;
72 bool contains(const bbox& box) const;
74 bool contains(const vec3& p) const;
76 ClipStatus::Type clipstatus(const bbox& other) const;
78 ClipStatus::Type clipstatus(const mat4& viewProjection, const bool isOrtho = false) const;
80 ClipStatus::Type clipstatus(const vec4* x_columns, const vec4* y_columns, const vec4* z_columns, const vec4* w_columns, const bool isOrtho = false) const;
82 mat4 to_mat4() const;
84 point corner_point(int index) const;
86 void get_clipplanes(const mat4& viewProjection, Util::Array<vec4>& outPlanes) const;
88 template<typename T> T as() const;
90 float area() const;
91
94};
95
96//------------------------------------------------------------------------------
99inline
101 pmin(-0.5f, -0.5f, -0.5f),
102 pmax(+0.5f, +0.5f, +0.5f)
103{
104 // empty
105}
106
107//------------------------------------------------------------------------------
110inline
111bbox::bbox(const point& center, const vector& extents)
112{
113 this->pmin = center - extents;
114 this->pmax = center + extents;
115}
116
117//------------------------------------------------------------------------------
123inline void
125{
126 // get extents
127 vec3 extents = xyz( abs(m.r[0]) + abs(m.r[1]) + abs(m.r[2]) ) * 0.5f;
128 vec3 center = xyz(m.r[3]);
129 this->pmin = center - extents;
130 this->pmax = center + extents;
131}
132
133//------------------------------------------------------------------------------
136inline
138{
139 this->set(m);
140}
141
142//------------------------------------------------------------------------------
145inline point
147{
148 return this->pmin + ((this->pmax - this->pmin) * 0.5f);
149}
150
151//------------------------------------------------------------------------------
154inline vector
156{
157 return (this->pmax - this->pmin) * 0.5f;
158}
159
160//------------------------------------------------------------------------------
163inline vec3
165{
166 return this->pmax - this->pmin;
167}
168
169//------------------------------------------------------------------------------
172inline void
173bbox::set(const point& center, const vector& extents)
174{
175 this->pmin = center - extents;
176 this->pmax = center + extents;
177}
178
179//------------------------------------------------------------------------------
182inline void
184{
185 this->pmin.set(+1000000.0f, +1000000.0f, +1000000.0f);
186 this->pmax.set(-1000000.0f, -1000000.0f, -1000000.0f);
187}
188
189//------------------------------------------------------------------------------
194inline
195void
197{
198 if ((this->pmin == point(+1000000.0f, +1000000.0f, +1000000.0f)) &&
199 (this->pmax == point(-1000000.0f, -1000000.0f, -1000000.0f)))
200 {
201 this->pmin.set(0.0f, 0.0f, 0.0f);
202 this->pmax.set(0.0f, 0.0f, 0.0f);
203 }
204}
205
206//------------------------------------------------------------------------------
209inline void
211{
212 this->pmin = minimize(this->pmin, p);
213 this->pmax = maximize(this->pmax, p);
214}
215
216//------------------------------------------------------------------------------
219inline
220void
222{
223 this->pmin = minimize(this->pmin, box.pmin);
224 this->pmax = maximize(this->pmax, box.pmax);
225}
226
227//------------------------------------------------------------------------------
240inline void
242{
243 point temp;
244 point minP(1000000, 1000000,1000000);
245 point maxP(-1000000, -1000000, -1000000);
246 IndexT i;
247
248 for(i = 0; i < 8; ++i)
249 {
250 // Transform and check extents
251 point temp_f = m * corner_point(i);
252 temp = perspective_div(temp_f);
253 maxP = maximize(temp, maxP);
254 minP = minimize(temp, minP);
255 }
256
257 this->pmin = minP;
258 this->pmax = maxP;
259}
260
261//------------------------------------------------------------------------------
265inline void
267{
268 n_warn2(m.r[0].w == 0 && m.r[1].w == 0 && m.r[2].w == 0 && m.r[3].w == 1, "Matrix is not affine");
269
270 vec4 xa = m.x_axis * this->pmin.x;
271 vec4 xb = m.x_axis * this->pmax.x;
272
273 vec4 ya = m.y_axis * this->pmin.y;
274 vec4 yb = m.y_axis * this->pmax.y;
275
276 vec4 za = m.z_axis * this->pmin.z;
277 vec4 zb = m.z_axis * this->pmax.z;
278
279 this->pmin = xyz(minimize(xa, xb) + minimize(ya, yb) + minimize(za, zb) + m.position);
280 this->pmax = xyz(maximize(xa, xb) + maximize(ya, yb) + maximize(za, zb) + m.position);
281}
282
283//------------------------------------------------------------------------------
288inline bool
289bbox::intersects(const bbox& box) const
290{
291 bool lt = less_any(this->pmax, box.pmin);
292 bool gt = greater_any(this->pmin, box.pmax);
293 return !(lt || gt);
294}
295
296//------------------------------------------------------------------------------
301inline bool
302bbox::intersects(const line& ray, float& tmin) const
303{
304 tmin = 0.0f;
305 float tmax = 1e30f;
306
307 for (int i = 0; i < 3; i++)
308 {
309 if (fabs(ray.m[i]) < 0.00001f)
310 {
311 // ray is parallel to slab, no hit if start is not in slab
312 if (ray.b[i] < this->pmin[i] || ray.b[i] > this->pmax[i])
313 {
314 tmin = 1e30f;
315 return false;
316 }
317 }
318 else
319 {
320 float ood = 1.0f / ray.m[i];
321 float t1 = (this->pmin[i] - ray.b[i]) * ood;
322 float t2 = (this->pmax[i] - ray.b[i]) * ood;
323 if (t1 > t2)
324 std::swap(t1, t2);
325 if (t1 > tmin)
326 tmin = t1;
327 if (t2 < tmax)
328 tmax = t2;
329 if (tmin > tmax)
330 {
331 tmin = 1e30f;
332 return false;
333 }
334 }
335 }
336
337 return true;
338}
339
340//------------------------------------------------------------------------------
345inline bool
346bbox::contains(const bbox& box) const
347{
348 bool lt = less_all(this->pmin, box.pmin);
349 bool ge = greaterequal_all(this->pmax, box.pmax);
350 return lt && ge;
351}
352
353//------------------------------------------------------------------------------
357inline bool
358bbox::contains(const vec3& p) const
359{
360 bool lt = less_all(this->pmin, p);
361 bool ge = greaterequal_all(this->pmax, p);
362 return lt && ge;
363}
364
365//------------------------------------------------------------------------------
370inline mat4
372{
373 mat4 m = scaling(this->size());
374 point pos = this->center();
375 m.position = pos;
376 return m;
377}
378
379//------------------------------------------------------------------------------
382inline scalar
384{
385 return length(this->pmax - this->pmin);
386}
387
388//------------------------------------------------------------------------------
391__forceinline ClipStatus::Type
392bbox::clipstatus(const mat4& viewProjection, const bool isOrtho) const
393{
394 vec4 m_col_x[4];
395 vec4 m_col_y[4];
396 vec4 m_col_z[4];
397 vec4 m_col_w[4];
398
399 // splat the matrix such that all _x, _y, ... will contain the column values of x, y, ...
400 m_col_x[0] = splat_x(viewProjection.r[0]);
401 m_col_x[1] = splat_x(viewProjection.r[1]);
402 m_col_x[2] = splat_x(viewProjection.r[2]);
403 m_col_x[3] = splat_x(viewProjection.r[3]);
404
405 m_col_y[0] = splat_y(viewProjection.r[0]);
406 m_col_y[1] = splat_y(viewProjection.r[1]);
407 m_col_y[2] = splat_y(viewProjection.r[2]);
408 m_col_y[3] = splat_y(viewProjection.r[3]);
409
410 m_col_z[0] = splat_z(viewProjection.r[0]);
411 m_col_z[1] = splat_z(viewProjection.r[1]);
412 m_col_z[2] = splat_z(viewProjection.r[2]);
413 m_col_z[3] = splat_z(viewProjection.r[3]);
414
415 m_col_w[0] = splat_w(viewProjection.r[0]);
416 m_col_w[1] = splat_w(viewProjection.r[1]);
417 m_col_w[2] = splat_w(viewProjection.r[2]);
418 m_col_w[3] = splat_w(viewProjection.r[3]);
419
420 return this->clipstatus(m_col_x, m_col_y, m_col_z, m_col_w, isOrtho);
421}
422
423//------------------------------------------------------------------------------
426__forceinline ClipStatus::Type
427bbox::clipstatus(const vec4* x_columns, const vec4* y_columns, const vec4* z_columns, const vec4* w_columns, const bool isOrtho) const
428{
429 using namespace Math;
430 int andFlags = 0xffff;
431 int orFlags = 0;
432
433 vec4 xs[2];
434 vec4 ys[2];
435 vec4 zs[2];
436 vec4 ws[2];
437
438 // create vectors for each dimension of each point, xxxx, yyyy, zzzz
439 xs[0] = splat_x(this->pmin);
440 ys[0] = splat_y(this->pmin);
441 zs[0] = splat_z(this->pmin);
442 ws[0] = vec4(1.0f);
443
444 xs[1] = splat_x(this->pmax);
445 ys[1] = splat_y(this->pmax);
446 zs[1] = splat_z(this->pmax);
447 ws[1] = vec4(1.0f);
448
449 vec4 px[2];
450 vec4 py[2];
451 vec4 pz[2];
452
453 // this corresponds to the permute phase in the original function
454 /*
455 the points would be:
456
457 P1 P2 P3 P4
458 X0: x1, x1, x0, x0
459 Y0: y0, y0, y0, y0
460 Z0: z0, z1, z1, z0
461
462 P5 P6 P7 P8
463 X1: x0, x0, x1, x1
464 Y1: y1, y1, y1, y1
465 Z1: z1, z0, z0, z1
466
467 Meaning P1, P4, P6 and P7 are near plane, P2, P3, P5, P8 are far plane
468 */
469 px[0] = xs[1] * vec4(1, 1, 0, 0) + xs[0] * vec4(0, 0, 1, 1);
470 px[1] = xs[1] * vec4(0, 0, 1, 1) + xs[0] * vec4(1, 1, 0, 0);
471
472 py[0] = ys[0];
473 py[1] = ys[1];
474
475 pz[0] = zs[1] * vec4(1, 0, 0, 1) + zs[0] * vec4(0, 1, 1, 0);
476 pz[1] = zs[1] * vec4(0, 1, 1, 0) + zs[0] * vec4(1, 0, 0, 1);
477
478 vec4 res1;
479 const vec4 xLeftFlags = vec4(ClipLeft);
480 const vec4 xRightFlags = vec4(ClipRight);
481 const vec4 yBottomFlags = vec4(ClipBottom);
482 const vec4 yTopFlags = vec4(ClipTop);
483 const vec4 zFarFlags = vec4(ClipFar);
484 const vec4 zNearFlags = vec4(ClipNear);
485
486 // check two loops of points arranged as xxxx yyyy zzzz
487 IndexT i;
488 for (i = 0; i < 2; ++i)
489 {
490 // transform the x component of 4 points simultaneously
491 xs[i] =
492 multiplyadd(x_columns[2], pz[i],
493 multiplyadd(x_columns[1], py[i],
494 multiplyadd(x_columns[0], px[i], x_columns[3])));
495
496 // transform the y component of 4 points simultaneously
497 ys[i] =
498 multiplyadd(y_columns[2], pz[i],
499 multiplyadd(y_columns[1], py[i],
500 multiplyadd(y_columns[0], px[i], y_columns[3])));
501
502 // transform the z component of 4 points simultaneously
503 zs[i] =
504 multiplyadd(z_columns[2], pz[i],
505 multiplyadd(z_columns[1], py[i],
506 multiplyadd(z_columns[0], px[i], z_columns[3])));
507
508 if (isOrtho)
509 ws[i] = vec4(1);
510 else
511 {
512 // transform the w component of 4 points simultaneously
513 ws[i] =
514 multiplyadd(w_columns[2], pz[i],
515 multiplyadd(w_columns[1], py[i],
516 multiplyadd(w_columns[0], px[i], w_columns[3])));
517 }
518
519 {
520 const vec4 nws = -ws[i];
521 const vec4 pws = ws[i];
522
523 // add all flags together into one big vector of flags for all 4 points
524 res1 =
525 multiplyadd(less(xs[i], nws), xLeftFlags,
526 multiplyadd(greater(xs[i], pws), xRightFlags,
527 multiplyadd(less(ys[i], nws), yBottomFlags,
528 multiplyadd(greater(ys[i], pws), yTopFlags,
529 multiplyadd(less(zs[i], nws), zFarFlags,
530 (greater(zs[i], pws) * zNearFlags)
531 )
532 )
533 )
534 )
535 );
536 }
537
538 // read to stack and convert to uint in one swoop
539 alignas(16) uint res1_u[4];
540 __m128i result = _mm_cvttps_epi32(res1.vec);
541 _mm_storeu_si128(reinterpret_cast<__m128i*>(res1_u), result);
542
543 // update flags by or-ing and and-ing all 4 points individually
544 andFlags &= res1_u[0];
545 orFlags |= res1_u[0];
546 andFlags &= res1_u[1];
547 orFlags |= res1_u[1];
548 andFlags &= res1_u[2];
549 orFlags |= res1_u[2];
550 andFlags &= res1_u[3];
551 orFlags |= res1_u[3];
552
553 }
554 if (0 == orFlags) return ClipStatus::Inside;
555 else if (0 != andFlags) return ClipStatus::Outside;
556 else return ClipStatus::Clipped;
557}
558
559//------------------------------------------------------------------------------
562inline float
564{
565 Math::vec3 extent = this->pmax - this->pmin;
566 return extent.x * extent.y + extent.y * extent.z + extent.z * extent.x;
567}
568
569} // namespace Math
570//------------------------------------------------------------------------------
Type
Definition clipstatus.h:22
@ Outside
Definition clipstatus.h:24
@ Inside
Definition clipstatus.h:23
@ Clipped
Definition clipstatus.h:25
Nebula's bounding box class.
Definition bbox.h:24
void end_extend()
this resets the bounding box size to zero if no extend() method was called after begin_extend()
Definition bbox.h:196
vec3 size() const
get size of box
Definition bbox.h:164
vector extents() const
get extents of box
Definition bbox.h:155
point corner_point(int index) const
return one of the 8 corner points
Definition bbox.cc:38
point pmax
Definition bbox.h:93
mat4 to_mat4() const
create a matrix which transforms a unit cube to this bounding box
Definition bbox.h:371
ClipStatus::Type clipstatus(const bbox &other) const
check for intersection with other bounding box
Definition bbox.cc:17
T as() const
convert to any type
void begin_extend()
begin extending the box
Definition bbox.h:183
void extend(const vec3 &p)
extend the box
Definition bbox.h:210
point center() const
get center of box
Definition bbox.h:146
bbox()
constructor 1
Definition bbox.h:100
void transform(const mat4 &m)
transform bounding box
Definition bbox.h:241
scalar diagonal_size() const
get diagonal size of box
Definition bbox.h:383
void affine_transform(const mat4 &m)
affine transform bounding box, does not allow for projections
Definition bbox.h:266
void set(const mat4 &m)
set from mat4
Definition bbox.h:124
@ ClipTop
Definition bbox.h:32
@ ClipNear
Definition bbox.h:33
@ ClipRight
Definition bbox.h:30
@ ClipLeft
Definition bbox.h:29
@ ClipBottom
Definition bbox.h:31
@ ClipFar
Definition bbox.h:34
point pmin
Definition bbox.h:92
float area() const
calculate half-area of the surface of the box. If you need the full area, just multiply by 2.
Definition bbox.h:563
void get_clipplanes(const mat4 &viewProjection, Util::Array< vec4 > &outPlanes) const
return side planes in clip space
Definition bbox.cc:59
bool contains(const bbox &box) const
check if this box completely contains the parameter box
Definition bbox.h:346
bool intersects(const bbox &box) const
check for intersection with axis aligned bounding box
Definition bbox.h:289
A line in 3d space.
Definition line.h:22
point b
Definition line.h:55
vector m
Definition line.h:56
Nebula's dynamic array class.
Definition array.h:60
#define n_warn2(exp, msg)
Definition debug.h:55
Half precision (16 bit) float implementation.
Definition angularpfeedbackloop.h:17
__forceinline point less(const point &v0, const point &v1)
Definition point.h:501
__forceinline point maximize(const point &v0, const point &v1)
Definition point.h:368
__forceinline vec3 splat_z(const vec3 &v)
Definition vec3.h:822
__forceinline vec4 perspective_div(const vec4 &v)
Definition vec4.h:711
__forceinline vec3 splat_x(const vec3 &v)
Definition vec3.h:800
__forceinline scalar length(const quat &q)
Definition quat.h:259
__forceinline bool greaterequal_all(const point &v0, const point &v1)
Definition point.h:463
__forceinline bool greater_any(const point &v0, const point &v1)
Definition point.h:430
__forceinline mat4 scaling(scalar scale)
Definition mat4.h:1072
__forceinline bool less_any(const point &v0, const point &v1)
Definition point.h:386
__forceinline bool less_all(const point &v0, const point &v1)
Definition point.h:397
__forceinline vec3 splat_y(const vec3 &v)
Definition vec3.h:811
__forceinline point minimize(const point &v0, const point &v1)
Definition point.h:377
float scalar
Definition scalar.h:45
__forceinline point greater(const point &v0, const point &v1)
Definition point.h:510
__forceinline scalar abs(scalar a)
Definition scalar.h:432
__forceinline vec3 multiplyadd(const vec3 &v0, const vec3 &v1, const vec3 &v2)
Definition vec3.h:383
__forceinline vec3 xyz(const point &v)
Definition point.h:528
__forceinline vec4 splat_w(const vec4 &v)
Definition vec4.h:1047
Definition conversion.h:35
SSE support functions.
A 4x4 single point precision float matrix.
Definition mat4.h:47
vec4 y_axis
Definition mat4.h:114
vec4 position
Definition mat4.h:116
vec4 z_axis
Definition mat4.h:115
vec4 r[4]
as a two-dimensional array
Definition mat4.h:130
vec4 x_axis
Definition mat4.h:113
Represents a 3D point in space.
Definition point.h:22
void set(scalar x, scalar y, scalar z)
set content
Definition point.h:332
float z
Definition point.h:78
float x
Definition point.h:78
float y
Definition point.h:78
A 3D vector.
Definition vec3.h:39
float x
Definition vec3.h:93
float z
Definition vec3.h:93
float y
Definition vec3.h:93
A 4D vector.
Definition vec4.h:24
__m128 vec
Definition vec4.h:95
float w
Definition vec4.h:93
A vector is a 3D direction in space.
Definition vector.h:22
#define N_BIT(x)
Definition types.h:86
unsigned int uint
Definition types.h:31
int IndexT
Definition types.h:48