BoundingVolume.cpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. #include "Base.h"
  2. #include "BoundingVolume.h"
  3. namespace gameplay
  4. {
  5. BoundingVolume::BoundingVolume()
  6. : radius(0.0f)
  7. {
  8. }
  9. void updateMinMax(Vector3* point, Vector3* min, Vector3* max)
  10. {
  11. // Leftmost point.
  12. if (point->x < min->x)
  13. {
  14. min->x = point->x;
  15. }
  16. // Rightmost point.
  17. if (point->x > max->x)
  18. {
  19. max->x = point->x;
  20. }
  21. // Lowest point.
  22. if (point->y < min->y)
  23. {
  24. min->y = point->y;
  25. }
  26. // Highest point.
  27. if (point->y > max->y)
  28. {
  29. max->y = point->y;
  30. }
  31. // Farthest point.
  32. if (point->z < min->z)
  33. {
  34. min->z = point->z;
  35. }
  36. // Nearest point.
  37. if (point->z > max->z)
  38. {
  39. max->z = point->z;
  40. }
  41. }
  42. void BoundingVolume::transform(const Matrix& m)
  43. {
  44. // Transform the bounding sphere
  45. m.transformPoint(center, &center);
  46. Vector3 translate;
  47. m.decompose(&translate, NULL, NULL);
  48. float r = radius * translate.x;
  49. r = std::max(radius, radius * translate.y);
  50. r = std::max(radius, radius * translate.z);
  51. radius = r;
  52. // Transform the bounding box
  53. Vector3 corners[8];
  54. corners[0].set(min.x, max.y, max.z);
  55. // Left-bottom-front.
  56. corners[1].set(min.x, min.y, max.z);
  57. // Right-bottom-front.
  58. corners[2].set(max.x, min.y, max.z);
  59. // Right-top-front.
  60. corners[3].set(max.x, max.y, max.z);
  61. // Right-top-back.
  62. corners[4].set(max.x, max.y, min.z);
  63. // Right-bottom-back.
  64. corners[5].set(max.x, min.y, min.z);
  65. // Left-bottom-back.
  66. corners[6].set(min.x, min.y, min.z);
  67. // Left-top-back.
  68. corners[7].set(min.x, max.y, min.z);
  69. // Transform the corners, recalculating the min and max points along the way.
  70. m.transformPoint(corners[0], &corners[0]);
  71. Vector3 newMin = corners[0];
  72. Vector3 newMax = corners[0];
  73. for (int i = 1; i < 8; i++)
  74. {
  75. m.transformPoint(corners[i], &corners[i]);
  76. updateMinMax(&corners[i], &newMin, &newMax);
  77. }
  78. min = newMin;
  79. max = newMax;
  80. }
  81. void BoundingVolume::merge(const BoundingVolume& v)
  82. {
  83. // Merge the box portion
  84. min.x = std::min(min.x, v.min.x);
  85. min.y = std::min(min.y, v.min.y);
  86. min.z = std::min(min.z, v.min.z);
  87. max.x = std::max(max.x, v.max.x);
  88. max.y = std::max(max.y, v.max.y);
  89. max.z = std::max(max.z, v.max.z);
  90. // Merge the sphere portion
  91. // Calculate the distance between the two centers.
  92. float vx = center.x - v.center.x;
  93. float vy = center.y - v.center.y;
  94. float vz = center.z - v.center.z;
  95. float d = sqrt(vx * vx + vy * vy + vz * vz);
  96. // If one sphere is contained inside the other, set to the larger sphere.
  97. if (d <= (v.radius - radius))
  98. {
  99. // Use targert volume
  100. radius = v.radius;
  101. center = v.center;
  102. }
  103. else if (d <= (radius - v.radius))
  104. {
  105. // No change
  106. }
  107. else
  108. {
  109. // Calculate the unit vector between the two centers.
  110. float dI = 1.0f / d;
  111. vx *= dI;
  112. vy *= dI;
  113. vz *= dI;
  114. // Calculate the new radius.
  115. float r = (radius + v.radius + d) * 0.5f;
  116. // Calculate the new center.
  117. float scaleFactor = (r - v.radius);
  118. vx = vx * scaleFactor + v.center.x;
  119. vy = vy * scaleFactor + v.center.y;
  120. vz = vz * scaleFactor + v.center.z;
  121. // Set the new center and radius.
  122. center.x = vx;
  123. center.y = vy;
  124. center.z = vz;
  125. radius = r;
  126. }
  127. }
  128. }