5 @maintainer Morgan McGuire, matrix@graphics3d.com
12 #include "G3D/debug.h"
13 #include "G3D/Plane.h"
14 #include "G3D/AABox.h"
15 #include "G3D/CoordinateFrame.h"
20 Sets a field on four vertices. Used by the constructor.
22 #define setMany(i0, i1, i2, i3, field, extreme) \
23 _corner[i0].field = _corner[i1].field = \
24 _corner[i2].field = _corner[i3].field = \
31 Box::Box(const AABox
& b
) {
32 init(b
.low(), b
.high());
40 init(min
.min(max
), min
.max(max
));
48 setMany(0, 1, 2, 3, z
, max
);
49 setMany(4, 5, 6, 7, z
, min
);
51 setMany(1, 2, 5, 6, x
, max
);
52 setMany(0, 3, 4, 7, x
, min
);
54 setMany(3, 2, 6, 7, y
, max
);
55 setMany(0, 1, 5, 4, y
, min
);
59 _axis
[0] = Vector3::unitX();
60 _axis
[1] = Vector3::unitY();
61 _axis
[2] = Vector3::unitZ();
63 _volume
= _extent
.x
* _extent
.y
* _extent
.z
;
65 (_extent
.x
* _extent
.y
+
66 _extent
.y
* _extent
.z
+
67 _extent
.z
* _extent
.x
);
69 _center
= (max
+ min
) / 2;
73 float Box::volume() const {
78 float Box::surfaceArea() const {
83 void Box::getLocalFrame(CoordinateFrame
& frame
) const {
85 frame
.rotation
= Matrix3(
86 _axis
[0][0], _axis
[1][0], _axis
[2][0],
87 _axis
[0][1], _axis
[1][1], _axis
[2][1],
88 _axis
[0][2], _axis
[1][2], _axis
[2][2]);
90 frame
.translation
= _center
;
94 CoordinateFrame
Box::localFrame() const {
101 void Box::getFaceCorners(int f
, Vector3
& v0
, Vector3
& v1
, Vector3
& v2
, Vector3
& v3
) const {
104 v0
= _corner
[0]; v1
= _corner
[1]; v2
= _corner
[2]; v3
= _corner
[3];
108 v0
= _corner
[1]; v1
= _corner
[5]; v2
= _corner
[6]; v3
= _corner
[2];
112 v0
= _corner
[7]; v1
= _corner
[6]; v2
= _corner
[5]; v3
= _corner
[4];
116 v0
= _corner
[2]; v1
= _corner
[6]; v2
= _corner
[7]; v3
= _corner
[3];
120 v0
= _corner
[3]; v1
= _corner
[7]; v2
= _corner
[4]; v3
= _corner
[0];
124 v0
= _corner
[1]; v1
= _corner
[0]; v2
= _corner
[4]; v3
= _corner
[5];
128 debugAssert((f
>= 0) && (f
< 6));
134 const Array
<Plane
>& plane
,
135 int& cullingPlaneIndex
,
137 uint32
& outMask
) const {
139 return culledBy(plane
.getCArray(), plane
.size(), cullingPlaneIndex
, inMask
, outMask
);
144 const Array
<Plane
>& plane
,
145 int& cullingPlaneIndex
,
146 const uint32 inMask
) const {
148 return culledBy(plane
.getCArray(), plane
.size(), cullingPlaneIndex
, inMask
);
152 int32
Box::dummy
= 0;
155 const class Plane
* plane
,
158 const uint32 _inMask
,
159 uint32
& childMask
) const {
161 uint32 inMask
= _inMask
;
162 assert(numPlanes
< 31);
166 // See if there is one plane for which all of the
167 // vertices are in the negative half space.
168 for (int p
= 0; p
< numPlanes
; p
++) {
170 // Only test planes that are not masked
171 if ((inMask
& 1) != 0) {
175 int numContained
= 0;
178 // We can early-out only if we have found one point on each
179 // side of the plane (i.e. if we are straddling). That
180 // occurs when (numContained < v) && (numContained > 0)
181 for (v
= 0; (v
< 8) && ((numContained
== v
) || (numContained
== 0)); ++v
) {
182 if (plane
[p
].halfSpaceContains(getCorner(v
))) {
187 if (numContained
== 0) {
188 // Plane p culled the box
191 // The caller should not recurse into the children,
192 // since the parent is culled. If they do recurse,
193 // make them only test against this one plane, which
194 // will immediately cull the volume.
198 } else if (numContained
< v
) {
199 // The bounding volume straddled the plane; we have
200 // to keep testing against this plane
201 childMask
|= (1 << p
);
205 // Move on to the next bit.
206 inMask
= inMask
>> 1;
209 // None of the planes could cull this box
216 const class Plane
* plane
,
219 const uint32 _inMask
) const {
221 uint32 inMask
= _inMask
;
222 assert(numPlanes
< 31);
224 // See if there is one plane for which all of the
225 // vertices are in the negative half space.
226 for (int p
= 0; p
< numPlanes
; p
++) {
228 // Only test planes that are not masked
229 if ((inMask
& 1) != 0) {
235 // Assume this plane culls all points. See if there is a point
236 // not culled by the plane... early out when at least one point
237 // is in the positive half space.
238 for (v
= 0; (v
< 8) && culled
; ++v
) {
239 culled
= ! plane
[p
].halfSpaceContains(getCorner(v
));
243 // Plane p culled the box
250 // Move on to the next bit.
251 inMask
= inMask
>> 1;
254 // None of the planes could cull this box
261 const Vector3
& point
) const {
263 // Form axes from three edges, transform the point into that
264 // space, and perform 3 interval tests
266 Vector3 u
= _corner
[4] - _corner
[0];
267 Vector3 v
= _corner
[3] - _corner
[0];
268 Vector3 w
= _corner
[1] - _corner
[0];
270 Matrix3 M
= Matrix3(u
.x
, v
.x
, w
.x
,
274 // M^-1 * (point - _corner[0]) = point in unit cube's object space
275 // compute the inverse of M
276 Vector3 osPoint
= M
.inverse() * (point
- _corner
[0]);
290 void Box::getRandomSurfacePoint(Vector3
& P
, Vector3
& N
) const {
291 float aXY
= _extent
.x
* _extent
.y
;
292 float aYZ
= _extent
.y
* _extent
.z
;
293 float aZX
= _extent
.z
* _extent
.x
;
295 float r
= (float)random(0, aXY
+ aYZ
+ aZX
);
297 // Choose evenly between positive and negative face planes
298 float d
= (random(0, 1) < 0.5f
) ? -1.0f
: 1.0f
;
300 // The probability of choosing a given face is proportional to
303 P
= _axis
[0] * (float)random(-0.5, 0.5) * _extent
.x
+
304 _axis
[1] * (float)random(-0.5, 0.5) * _extent
.y
+
305 _center
+ _axis
[2] * d
* _extent
.z
* 0.5f
;
307 } else if (r
< aYZ
) {
308 P
= _axis
[1] * (float)random(-0.5, 0.5) * _extent
.y
+
309 _axis
[2] * (float)random(-0.5, 0.5) * _extent
.z
+
310 _center
+ _axis
[0] * d
* _extent
.x
* 0.5f
;
313 P
= _axis
[2] * (float)random(-0.5, 0.5) * _extent
.z
+
314 _axis
[0] *(float) random(-0.5, 0.5) * _extent
.x
+
315 _center
+ _axis
[1] * d
* _extent
.y
* 0.5f
;
321 Vector3
Box::randomInteriorPoint() const {
322 Vector3 sum
= _center
;
324 for (int a
= 0; a
< 3; ++a
) {
325 sum
+= _axis
[a
] * (float)random(-0.5, 0.5) * _extent
[a
];
333 void Box::getBounds(class AABox
& aabb
) const {
335 Vector3 lo
= _corner
[0];
338 for (int v
= 1; v
< 8; ++v
) {
339 const Vector3
& C
= _corner
[v
];
344 aabb
= AABox(lo
, hi
);