frustum.cpp
上传用户:center1979
上传日期:2022-07-26
资源大小:50633k
文件大小:5k
源码类别:

OpenGL

开发平台:

Visual C++

  1. // frustum.cpp
  2. // 
  3. // Copyright (C) 2000, Chris Laurel <claurel@shatters.net>
  4. //
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the GNU General Public License
  7. // as published by the Free Software Foundation; either version 2
  8. // of the License, or (at your option) any later version.
  9. #include "frustum.h"
  10. Frustum::Frustum(float fov, float aspectRatio, float n) :
  11.     infinite(true)
  12. {
  13.     init(fov, aspectRatio, n, n);
  14. }
  15. Frustum::Frustum(float fov, float aspectRatio, float n, float f) :
  16.     infinite(false)
  17. {
  18.     init(fov, aspectRatio, n, f);
  19. }
  20. void Frustum::init(float fov, float aspectRatio, float n, float f)
  21. {
  22.     float h = (float) tan(fov / 2.0f);
  23.     float w = h * aspectRatio;
  24.     Vec3f normals[4];
  25.     normals[Bottom] = Vec3f(0, 1, -h);
  26.     normals[Top]    = Vec3f(0, -1, -h);
  27.     normals[Left]   = Vec3f(1, 0, -w);
  28.     normals[Right]  = Vec3f(-1, 0, -w);
  29.     for (int i = 0; i < 4; i++)
  30.     {
  31.         normals[i].normalize();
  32.         planes[i] = Planef(normals[i], Point3f(0, 0, 0));
  33.     }
  34.     planes[Near] = Planef(Vec3f(0, 0, -1), -n);
  35.     planes[Far] = Planef(Vec3f(0, 0, 1), f);
  36. }
  37. Frustum::Aspect Frustum::test(const Point3f& p) const
  38. {
  39.     return testSphere(p, 0);
  40. }
  41. Frustum::Aspect Frustum::testSphere(const Point3f& center, float radius) const
  42. {
  43.     int nPlanes = infinite ? 5 : 6;
  44.     int intersections = 0;
  45.     for (int i = 0; i < nPlanes; i++)
  46.     {
  47.         float distanceToPlane = planes[i].distanceTo(center);
  48.         if (distanceToPlane < -radius)
  49.             return Outside;
  50.         else if (distanceToPlane <= radius)
  51.             intersections |= (1 << i);
  52.     }
  53.     return (intersections == 0) ? Inside : Intersect;
  54. }
  55. Frustum::Aspect Frustum::testSphere(const Point3d& center, double radius) const
  56. {
  57.     int nPlanes = infinite ? 5 : 6;
  58.     int intersections = 0;
  59.     for (int i = 0; i < nPlanes; i++)
  60.     {
  61.         //TODO: Celestia should incorporate some casting operators overloading to accommodate all this kind of stuff:
  62.         Vec3f plNormal       = planes[i].normal;
  63.         Vec3d plNormalDbl(plNormal.x, plNormal.y, plNormal.z); 
  64.          
  65.         double distanceToPlane = plNormalDbl.x * center.x + plNormalDbl.y * center.y + plNormalDbl.z * center.z + planes[i].d;        
  66.         if (distanceToPlane < -radius)
  67.             return Outside;
  68.         else if (distanceToPlane <= radius)
  69.             intersections |= (1 << i);
  70.     }
  71.     return (intersections == 0) ? Inside : Intersect;
  72. }
  73. Frustum::Aspect Frustum::testCapsule(const Capsulef& capsule) const
  74. {
  75.     int nPlanes = infinite ? 5 : 6;
  76.     int intersections = 0;
  77.     float r2 = capsule.radius * capsule.radius;
  78.     
  79.     for (int i = 0; i < nPlanes; i++)
  80.     {
  81.         float signedDist0 = planes[i].normal * Vec3f(capsule.origin.x, capsule.origin.y, capsule.origin.z) + planes[i].d;
  82.         float signedDist1 = signedDist0 + planes[i].normal * capsule.axis;
  83.         if (signedDist0 * signedDist1 > r2)
  84.         {
  85.             // Endpoints of capsule are on same side of plane; test closest endpoint to see if it
  86.             // lies closer to the plane than radius
  87.             if (abs(signedDist0) <= abs(signedDist1))
  88.             {
  89.                 if (signedDist0 < -capsule.radius)
  90.                     return Outside;
  91.                 else if (signedDist0 < capsule.radius)
  92.                     intersections |= (1 << i);
  93.             }
  94.             else
  95.             {
  96.                 if (signedDist1 < -capsule.radius)
  97.                     return Outside;
  98.                 else if (signedDist1 < capsule.radius)
  99.                     intersections |= (1 << i);
  100.             }
  101.         }
  102.         else
  103.         {
  104.             // Capsule endpoints are on different sides of the plane, so we have an intersection
  105.             intersections |= (1 << i);
  106.         }
  107. #if 0        
  108.         Vec3f plNormal       = planes[i].normal;
  109.         Vec3d plNormalDbl(plNormal.x, plNormal.y, plNormal.z); 
  110.          
  111.         double distanceToPlane = planes[i].distanceToSegment(capsule.origin, capsule.axis);
  112.         if (distanceToPlane < -capsule.radius)
  113.             return Outside;
  114.         else if (distanceToPlane <= capsule.radius)
  115.             intersections |= (1 << i);
  116. #endif
  117.     }
  118.     return (intersections == 0) ? Inside : Intersect;
  119. }
  120. #if 0
  121. // See if the half space defined by the plane intersects the frustum.  For the
  122. // plane equation p(x, y, z) = ax + by + cz + d = 0, the halfspace is
  123. // contains all points p(x, y, z) < 0.
  124. Frustum::Aspect Frustum::testHalfSpace(const Planef& plane)
  125. {
  126.     return Intersect;
  127. }
  128. #endif
  129. void Frustum::transform(const Mat3f& m)
  130. {
  131.     int nPlanes = infinite ? 5 : 6;
  132.     Mat3f invTranspose = m.inverse().transpose();
  133.     for (int i = 0; i < nPlanes; i++)
  134.     {
  135.         planes[i] = planes[i] * invTranspose;
  136.         float s = 1.0f / planes[i].normal.length();
  137.         planes[i].normal = planes[i].normal * s;
  138.         planes[i].d *= s;
  139.     }
  140. }
  141. void Frustum::transform(const Mat4f& m)
  142. {
  143.     int nPlanes = infinite ? 5 : 6;
  144.     Mat4f invTranspose = m.inverse().transpose();
  145.     for (int i = 0; i < nPlanes; i++)
  146.     {
  147.         planes[i] = planes[i] * invTranspose;
  148.         float s = 1.0f / planes[i].normal.length();
  149.         planes[i].normal = planes[i].normal * s;
  150.         planes[i].d *= s;
  151.     }
  152. }