00001
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #if !defined(INCLUDED_MATH_FRUSTUM_H)
00028 #define INCLUDED_MATH_FRUSTUM_H
00029
00030 #include "generic/enumeration.h"
00031 #include "math/matrix.h"
00032 #include "math/plane.h"
00033 #include "math/aabb.h"
00034 #include "math/line.h"
00035
00036 inline Matrix4 matrix4_frustum (float left, float right, float bottom, float top, float nearval, float farval)
00037 {
00038 return Matrix4(static_cast<float> ((2 * nearval) / (right - left)), 0, 0, 0, 0, static_cast<float> ((2 * nearval)
00039 / (top - bottom)), 0, 0, static_cast<float> ((right + left) / (right - left)), static_cast<float> ((top
00040 + bottom) / (top - bottom)), static_cast<float> (-(farval + nearval) / (farval - nearval)), -1, 0, 0,
00041 static_cast<float> (-(2 * farval * nearval) / (farval - nearval)), 0);
00042 }
00043
00044 typedef unsigned char ClipResult;
00045 const ClipResult c_CLIP_PASS = 0x00;
00046 const ClipResult c_CLIP_LT_X = 0x01;
00047 const ClipResult c_CLIP_GT_X = 0x02;
00048 const ClipResult c_CLIP_LT_Y = 0x04;
00049 const ClipResult c_CLIP_GT_Y = 0x08;
00050 const ClipResult c_CLIP_LT_Z = 0x10;
00051 const ClipResult c_CLIP_GT_Z = 0x20;
00052 const ClipResult c_CLIP_FAIL = 0x3F;
00053
00054 template<typename Index>
00055 class Vector4ClipLT
00056 {
00057 public:
00058 static bool compare (const Vector4& self)
00059 {
00060 return self[Index::VALUE] < self[3];
00061 }
00062 static double scale (const Vector4& self, const Vector4& other)
00063 {
00064 return (self[Index::VALUE] - self[3]) / (other[3] - other[Index::VALUE]);
00065 }
00066 };
00067
00068 template<typename Index>
00069 class Vector4ClipGT
00070 {
00071 public:
00072 static bool compare (const Vector4& self)
00073 {
00074 return self[Index::VALUE] > -self[3];
00075 }
00076 static double scale (const Vector4& self, const Vector4& other)
00077 {
00078 return (self[Index::VALUE] + self[3]) / (-other[3] - other[Index::VALUE]);
00079 }
00080 };
00081
00082 template<typename ClipPlane>
00083 class Vector4ClipPolygon
00084 {
00085 public:
00086 typedef Vector4* iterator;
00087 typedef const Vector4* const_iterator;
00088
00089 static std::size_t apply (const_iterator first, const_iterator last, iterator out)
00090 {
00091 const_iterator next = first, i = last - 1;
00092 iterator tmp(out);
00093 bool b0 = ClipPlane::compare(*i);
00094 while (next != last) {
00095 bool b1 = ClipPlane::compare(*next);
00096 if (b0 ^ b1) {
00097 *out = *next - *i;
00098
00099 double scale = ClipPlane::scale(*i, *out);
00100
00101 (*out)[0] = static_cast<float> ((*i)[0] + scale * ((*out)[0]));
00102 (*out)[1] = static_cast<float> ((*i)[1] + scale * ((*out)[1]));
00103 (*out)[2] = static_cast<float> ((*i)[2] + scale * ((*out)[2]));
00104 (*out)[3] = static_cast<float> ((*i)[3] + scale * ((*out)[3]));
00105
00106 ++out;
00107 }
00108
00109 if (b1) {
00110 *out = *next;
00111 ++out;
00112 }
00113
00114 i = next;
00115 ++next;
00116 b0 = b1;
00117 }
00118
00119 return out - tmp;
00120 }
00121 };
00122
00123 #define CLIP_X_LT_W(p) (Vector4ClipLT< IntegralConstant<0> >::compare(p))
00124 #define CLIP_X_GT_W(p) (Vector4ClipGT< IntegralConstant<0> >::compare(p))
00125 #define CLIP_Y_LT_W(p) (Vector4ClipLT< IntegralConstant<1> >::compare(p))
00126 #define CLIP_Y_GT_W(p) (Vector4ClipGT< IntegralConstant<1> >::compare(p))
00127 #define CLIP_Z_LT_W(p) (Vector4ClipLT< IntegralConstant<2> >::compare(p))
00128 #define CLIP_Z_GT_W(p) (Vector4ClipGT< IntegralConstant<2> >::compare(p))
00129
00130 inline ClipResult homogenous_clip_point (const Vector4& clipped)
00131 {
00132 ClipResult result = c_CLIP_FAIL;
00133 if (CLIP_X_LT_W(clipped))
00134 result &= ~c_CLIP_LT_X;
00135 if (CLIP_X_GT_W(clipped))
00136 result &= ~c_CLIP_GT_X;
00137 if (CLIP_Y_LT_W(clipped))
00138 result &= ~c_CLIP_LT_Y;
00139 if (CLIP_Y_GT_W(clipped))
00140 result &= ~c_CLIP_GT_Y;
00141 if (CLIP_Z_LT_W(clipped))
00142 result &= ~c_CLIP_LT_Z;
00143 if (CLIP_Z_GT_W(clipped))
00144 result &= ~c_CLIP_GT_Z;
00145 return result;
00146 }
00147
00151 inline ClipResult matrix4_clip_point (const Matrix4& self, const Vector3& point, Vector4& clipped)
00152 {
00153 clipped[0] = point[0];
00154 clipped[1] = point[1];
00155 clipped[2] = point[2];
00156 clipped[3] = 1;
00157 matrix4_transform_vector4(self, clipped);
00158 return homogenous_clip_point(clipped);
00159 }
00160
00161 inline std::size_t homogenous_clip_triangle (Vector4 clipped[9])
00162 {
00163 Vector4 buffer[9];
00164 std::size_t count = 3;
00165 count = Vector4ClipPolygon<Vector4ClipLT<IntegralConstant<0> > >::apply(clipped, clipped + count, buffer);
00166 count = Vector4ClipPolygon<Vector4ClipGT<IntegralConstant<0> > >::apply(buffer, buffer + count, clipped);
00167 count = Vector4ClipPolygon<Vector4ClipLT<IntegralConstant<1> > >::apply(clipped, clipped + count, buffer);
00168 count = Vector4ClipPolygon<Vector4ClipGT<IntegralConstant<1> > >::apply(buffer, buffer + count, clipped);
00169 count = Vector4ClipPolygon<Vector4ClipLT<IntegralConstant<2> > >::apply(clipped, clipped + count, buffer);
00170 return Vector4ClipPolygon<Vector4ClipGT<IntegralConstant<2> > >::apply(buffer, buffer + count, clipped);
00171 }
00172
00176 inline std::size_t matrix4_clip_triangle (const Matrix4& self, const Vector3& p0, const Vector3& p1, const Vector3& p2,
00177 Vector4 clipped[9])
00178 {
00179 clipped[0][0] = p0[0];
00180 clipped[0][1] = p0[1];
00181 clipped[0][2] = p0[2];
00182 clipped[0][3] = 1;
00183 clipped[1][0] = p1[0];
00184 clipped[1][1] = p1[1];
00185 clipped[1][2] = p1[2];
00186 clipped[1][3] = 1;
00187 clipped[2][0] = p2[0];
00188 clipped[2][1] = p2[1];
00189 clipped[2][2] = p2[2];
00190 clipped[2][3] = 1;
00191
00192 matrix4_transform_vector4(self, clipped[0]);
00193 matrix4_transform_vector4(self, clipped[1]);
00194 matrix4_transform_vector4(self, clipped[2]);
00195
00196 return homogenous_clip_triangle(clipped);
00197 }
00198
00199 inline std::size_t homogenous_clip_line (Vector4 clipped[2])
00200 {
00201 const Vector4& p0 = clipped[0];
00202 const Vector4& p1 = clipped[1];
00203
00204
00205 {
00206 ClipResult mask0 = homogenous_clip_point(clipped[0]);
00207 ClipResult mask1 = homogenous_clip_point(clipped[1]);
00208
00209 if ((mask0 | mask1) == c_CLIP_PASS)
00210 return 2;
00211
00212 if (mask0 & mask1)
00213 return 0;
00214 }
00215
00216 {
00217 const bool index = CLIP_X_LT_W(p0);
00218 if (index ^ CLIP_X_LT_W(p1)) {
00219 Vector4 clip(p1 - p0);
00220
00221 double scale = (p0[0] - p0[3]) / (clip[3] - clip[0]);
00222
00223 clip[0] = static_cast<float> (p0[0] + scale * clip[0]);
00224 clip[1] = static_cast<float> (p0[1] + scale * clip[1]);
00225 clip[2] = static_cast<float> (p0[2] + scale * clip[2]);
00226 clip[3] = static_cast<float> (p0[3] + scale * clip[3]);
00227
00228 clipped[index] = clip;
00229 } else if (index == 0)
00230 return 0;
00231 }
00232
00233 {
00234 const bool index = CLIP_X_GT_W(p0);
00235 if (index ^ CLIP_X_GT_W(p1)) {
00236 Vector4 clip(p1 - p0);
00237
00238 double scale = (p0[0] + p0[3]) / (-clip[3] - clip[0]);
00239
00240 clip[0] = static_cast<float> (p0[0] + scale * clip[0]);
00241 clip[1] = static_cast<float> (p0[1] + scale * clip[1]);
00242 clip[2] = static_cast<float> (p0[2] + scale * clip[2]);
00243 clip[3] = static_cast<float> (p0[3] + scale * clip[3]);
00244
00245 clipped[index] = clip;
00246 } else if (index == 0)
00247 return 0;
00248 }
00249
00250 {
00251 const bool index = CLIP_Y_LT_W(p0);
00252 if (index ^ CLIP_Y_LT_W(p1)) {
00253 Vector4 clip(p1 - p0);
00254
00255 double scale = (p0[1] - p0[3]) / (clip[3] - clip[1]);
00256
00257 clip[0] = static_cast<float> (p0[0] + scale * clip[0]);
00258 clip[1] = static_cast<float> (p0[1] + scale * clip[1]);
00259 clip[2] = static_cast<float> (p0[2] + scale * clip[2]);
00260 clip[3] = static_cast<float> (p0[3] + scale * clip[3]);
00261
00262 clipped[index] = clip;
00263 } else if (index == 0)
00264 return 0;
00265 }
00266
00267 {
00268 const bool index = CLIP_Y_GT_W(p0);
00269 if (index ^ CLIP_Y_GT_W(p1)) {
00270 Vector4 clip(p1 - p0);
00271
00272 double scale = (p0[1] + p0[3]) / (-clip[3] - clip[1]);
00273
00274 clip[0] = static_cast<float> (p0[0] + scale * clip[0]);
00275 clip[1] = static_cast<float> (p0[1] + scale * clip[1]);
00276 clip[2] = static_cast<float> (p0[2] + scale * clip[2]);
00277 clip[3] = static_cast<float> (p0[3] + scale * clip[3]);
00278
00279 clipped[index] = clip;
00280 } else if (index == 0)
00281 return 0;
00282 }
00283
00284 {
00285 const bool index = CLIP_Z_LT_W(p0);
00286 if (index ^ CLIP_Z_LT_W(p1)) {
00287 Vector4 clip(p1 - p0);
00288
00289 double scale = (p0[2] - p0[3]) / (clip[3] - clip[2]);
00290
00291 clip[0] = static_cast<float> (p0[0] + scale * clip[0]);
00292 clip[1] = static_cast<float> (p0[1] + scale * clip[1]);
00293 clip[2] = static_cast<float> (p0[2] + scale * clip[2]);
00294 clip[3] = static_cast<float> (p0[3] + scale * clip[3]);
00295
00296 clipped[index] = clip;
00297 } else if (index == 0)
00298 return 0;
00299 }
00300
00301 {
00302 const bool index = CLIP_Z_GT_W(p0);
00303 if (index ^ CLIP_Z_GT_W(p1)) {
00304 Vector4 clip(p1 - p0);
00305
00306 double scale = (p0[2] + p0[3]) / (-clip[3] - clip[2]);
00307
00308 clip[0] = static_cast<float> (p0[0] + scale * clip[0]);
00309 clip[1] = static_cast<float> (p0[1] + scale * clip[1]);
00310 clip[2] = static_cast<float> (p0[2] + scale * clip[2]);
00311 clip[3] = static_cast<float> (p0[3] + scale * clip[3]);
00312
00313 clipped[index] = clip;
00314 } else if (index == 0)
00315 return 0;
00316 }
00317
00318 return 2;
00319 }
00320
00324 inline std::size_t matrix4_clip_line (const Matrix4& self, const Vector3& p0, const Vector3& p1, Vector4 clipped[2])
00325 {
00326 clipped[0][0] = p0[0];
00327 clipped[0][1] = p0[1];
00328 clipped[0][2] = p0[2];
00329 clipped[0][3] = 1;
00330 clipped[1][0] = p1[0];
00331 clipped[1][1] = p1[1];
00332 clipped[1][2] = p1[2];
00333 clipped[1][3] = 1;
00334
00335 matrix4_transform_vector4(self, clipped[0]);
00336 matrix4_transform_vector4(self, clipped[1]);
00337
00338 return homogenous_clip_line(clipped);
00339 }
00340
00341 struct Frustum
00342 {
00343 Plane3 right, left, bottom, top, back, front;
00344
00345 Frustum ()
00346 {
00347 }
00348 Frustum (const Plane3& _right, const Plane3& _left, const Plane3& _bottom, const Plane3& _top,
00349 const Plane3& _back, const Plane3& _front) :
00350 right(_right), left(_left), bottom(_bottom), top(_top), back(_back), front(_front)
00351 {
00352 }
00353 };
00354
00355 inline Frustum frustum_transformed (const Frustum& frustum, const Matrix4& transform)
00356 {
00357 return Frustum(plane3_transformed(frustum.right, transform), plane3_transformed(frustum.left, transform),
00358 plane3_transformed(frustum.bottom, transform), plane3_transformed(frustum.top, transform),
00359 plane3_transformed(frustum.back, transform), plane3_transformed(frustum.front, transform));
00360 }
00361
00362 inline Frustum frustum_inverse_transformed (const Frustum& frustum, const Matrix4& transform)
00363 {
00364 return Frustum(plane3_inverse_transformed(frustum.right, transform), plane3_inverse_transformed(frustum.left,
00365 transform), plane3_inverse_transformed(frustum.bottom, transform), plane3_inverse_transformed(frustum.top,
00366 transform), plane3_inverse_transformed(frustum.back, transform), plane3_inverse_transformed(frustum.front,
00367 transform));
00368 }
00369
00370 inline bool viewproj_test_point (const Matrix4& viewproj, const Vector3& point)
00371 {
00372 Vector4 hpoint(matrix4_transformed_vector4(viewproj, Vector4(point, 1.0f)));
00373 if (fabs(hpoint[0]) < fabs(hpoint[3]) && fabs(hpoint[1]) < fabs(hpoint[3]) && fabs(hpoint[2]) < fabs(hpoint[3]))
00374 return true;
00375 return false;
00376 }
00377
00378 inline bool viewproj_test_transformed_point (const Matrix4& viewproj, const Vector3& point, const Matrix4& localToWorld)
00379 {
00380 return viewproj_test_point(viewproj, matrix4_transformed_point(localToWorld, point));
00381 }
00382
00383 inline Frustum frustum_from_viewproj (const Matrix4& viewproj)
00384 {
00385 return Frustum(plane3_normalised(Plane3(viewproj[3] - viewproj[0], viewproj[7] - viewproj[4], viewproj[11]
00386 - viewproj[8], viewproj[15] - viewproj[12])), plane3_normalised(Plane3(viewproj[3] + viewproj[0],
00387 viewproj[7] + viewproj[4], viewproj[11] + viewproj[8], viewproj[15] + viewproj[12])), plane3_normalised(
00388 Plane3(viewproj[3] + viewproj[1], viewproj[7] + viewproj[5], viewproj[11] + viewproj[9], viewproj[15]
00389 + viewproj[13])), plane3_normalised(Plane3(viewproj[3] - viewproj[1], viewproj[7] - viewproj[5],
00390 viewproj[11] - viewproj[9], viewproj[15] - viewproj[13])), plane3_normalised(Plane3(viewproj[3]
00391 - viewproj[2], viewproj[7] - viewproj[6], viewproj[11] - viewproj[10], viewproj[15] - viewproj[14])),
00392 plane3_normalised(Plane3(viewproj[3] + viewproj[2], viewproj[7] + viewproj[6], viewproj[11] + viewproj[10],
00393 viewproj[15] + viewproj[14])));
00394 }
00395
00396 struct VolumeIntersection
00397 {
00398 enum Value
00399 {
00400 OUTSIDE, INSIDE, PARTIAL
00401 };
00402 };
00403
00404 typedef EnumeratedValue<VolumeIntersection> VolumeIntersectionValue;
00405
00406 const VolumeIntersectionValue c_volumeOutside(VolumeIntersectionValue::OUTSIDE);
00407 const VolumeIntersectionValue c_volumeInside(VolumeIntersectionValue::INSIDE);
00408 const VolumeIntersectionValue c_volumePartial(VolumeIntersectionValue::PARTIAL);
00409
00410 inline VolumeIntersectionValue frustum_test_aabb (const Frustum& frustum, const AABB& aabb)
00411 {
00412 VolumeIntersectionValue result = c_volumeInside;
00413
00414 switch (aabb_classify_plane(aabb, frustum.right)) {
00415 case 2:
00416 return c_volumeOutside;
00417 case 1:
00418 result = c_volumePartial;
00419 }
00420
00421 switch (aabb_classify_plane(aabb, frustum.left)) {
00422 case 2:
00423 return c_volumeOutside;
00424 case 1:
00425 result = c_volumePartial;
00426 }
00427
00428 switch (aabb_classify_plane(aabb, frustum.bottom)) {
00429 case 2:
00430 return c_volumeOutside;
00431 case 1:
00432 result = c_volumePartial;
00433 }
00434
00435 switch (aabb_classify_plane(aabb, frustum.top)) {
00436 case 2:
00437 return c_volumeOutside;
00438 case 1:
00439 result = c_volumePartial;
00440 }
00441
00442 switch (aabb_classify_plane(aabb, frustum.back)) {
00443 case 2:
00444 return c_volumeOutside;
00445 case 1:
00446 result = c_volumePartial;
00447 }
00448
00449 switch (aabb_classify_plane(aabb, frustum.front)) {
00450 case 2:
00451 return c_volumeOutside;
00452 case 1:
00453 result = c_volumePartial;
00454 }
00455
00456 return result;
00457 }
00458
00459 inline double plane_distance_to_point (const Plane3& plane, const Vector3& point)
00460 {
00461 return plane.normal().dot(point) + plane.d;
00462 }
00463
00464 inline double plane_distance_to_oriented_extents (const Plane3& plane, const Vector3& extents,
00465 const Matrix4& orientation)
00466 {
00467 return fabs(extents[0] * plane.normal().dot(orientation.x().getVector3())) + fabs(extents[1] * plane.normal().dot(
00468 orientation.y().getVector3())) + fabs(extents[2] * plane.normal().dot(orientation.z().getVector3()));
00469 }
00470
00472 inline bool plane_contains_oriented_aabb (const Plane3& plane, const AABB& aabb, const Matrix4& orientation)
00473 {
00474 double dot = plane_distance_to_point(plane, aabb.origin);
00475 return !(dot > 0 || -dot < plane_distance_to_oriented_extents(plane, aabb.extents, orientation));
00476 }
00477
00478 inline VolumeIntersectionValue frustum_intersects_transformed_aabb (const Frustum& frustum, const AABB& aabb,
00479 const Matrix4& localToWorld)
00480 {
00481 AABB aabb_world(aabb);
00482 matrix4_transform_point(localToWorld, aabb_world.origin);
00483
00484 if (plane_contains_oriented_aabb(frustum.right, aabb_world, localToWorld) || plane_contains_oriented_aabb(
00485 frustum.left, aabb_world, localToWorld) || plane_contains_oriented_aabb(frustum.bottom, aabb_world,
00486 localToWorld) || plane_contains_oriented_aabb(frustum.top, aabb_world, localToWorld)
00487 || plane_contains_oriented_aabb(frustum.back, aabb_world, localToWorld) || plane_contains_oriented_aabb(
00488 frustum.front, aabb_world, localToWorld))
00489 return c_volumeOutside;
00490 return c_volumeInside;
00491 }
00492
00493 inline bool plane3_test_point (const Plane3& plane, const Vector3& point)
00494 {
00495 return point.dot(plane.normal()) + plane.dist() <= 0;
00496 }
00497
00498 inline bool plane3_test_line (const Plane3& plane, const Segment& segment)
00499 {
00500 return segment_classify_plane(segment, plane) == 2;
00501 }
00502
00503 inline bool frustum_test_point (const Frustum& frustum, const Vector3& point)
00504 {
00505 return !plane3_test_point(frustum.right, point) && !plane3_test_point(frustum.left, point) && !plane3_test_point(
00506 frustum.bottom, point) && !plane3_test_point(frustum.top, point) && !plane3_test_point(frustum.back, point)
00507 && !plane3_test_point(frustum.front, point);
00508 }
00509
00510 inline bool frustum_test_line (const Frustum& frustum, const Segment& segment)
00511 {
00512 return !plane3_test_line(frustum.right, segment) && !plane3_test_line(frustum.left, segment) && !plane3_test_line(
00513 frustum.bottom, segment) && !plane3_test_line(frustum.top, segment) && !plane3_test_line(frustum.back,
00514 segment) && !plane3_test_line(frustum.front, segment);
00515 }
00516
00517 inline bool viewer_test_plane (const Vector4& viewer, const Plane3& plane)
00518 {
00519 return ((plane.a * viewer[0]) + (plane.b * viewer[1]) + (plane.c * viewer[2]) + (plane.d * viewer[3])) > 0;
00520 }
00521
00522 inline Vector3 triangle_cross (const Vector3& p0, const Vector3& p1, const Vector3& p2)
00523 {
00524 return (p1 - p0).crossProduct(p1 - p2);
00525 }
00526
00527 inline bool viewer_test_triangle (const Vector4& viewer, const Vector3& p0, const Vector3& p1, const Vector3& p2)
00528 {
00529 Vector3 cross(triangle_cross(p0, p1, p2));
00530 return ((viewer[0] * cross[0]) + (viewer[1] * cross[1]) + (viewer[2] * cross[2]) + (viewer[3] * 0)) > 0;
00531 }
00532
00533 inline Vector4 viewer_from_transformed_viewer (const Vector4& viewer, const Matrix4& transform)
00534 {
00535 if (viewer[3] == 0) {
00536 return Vector4(matrix4_transformed_direction(transform, viewer.getVector3()), 0);
00537 } else {
00538 return Vector4(matrix4_transformed_point(transform, viewer.getVector3()), viewer[3]);
00539 }
00540 }
00541
00542 inline bool viewer_test_transformed_plane (const Vector4& viewer, const Plane3& plane, const Matrix4& localToWorld)
00543 {
00544 #if 0
00545 return viewer_test_plane(viewer_from_transformed_viewer(viewer, matrix4_affine_inverse(localToWorld)), plane);
00546 #else
00547 return viewer_test_plane(viewer, plane3_transformed(plane, localToWorld));
00548 #endif
00549 }
00550
00551 inline Vector4 viewer_from_viewproj (const Matrix4& viewproj)
00552 {
00553
00554 Vector4 viewer(matrix4_transformed_vector4(matrix4_full_inverse(viewproj), Vector4(0, 0, -1, 0)));
00555 if (viewer[3] != 0)
00556 {
00557 viewer[0] /= viewer[3];
00558 viewer[1] /= viewer[3];
00559 viewer[2] /= viewer[3];
00560 viewer[3] /= viewer[3];
00561 }
00562 return viewer;
00563 }
00564
00565 #endif