#include "Base.h" #include "BoundingVolume.h" namespace gameplay { BoundingVolume::BoundingVolume() : radius(0.0f) { } void updateMinMax(Vector3* point, Vector3* min, Vector3* max) { // Leftmost point. if (point->x < min->x) { min->x = point->x; } // Rightmost point. if (point->x > max->x) { max->x = point->x; } // Lowest point. if (point->y < min->y) { min->y = point->y; } // Highest point. if (point->y > max->y) { max->y = point->y; } // Farthest point. if (point->z < min->z) { min->z = point->z; } // Nearest point. if (point->z > max->z) { max->z = point->z; } } void BoundingVolume::transform(const Matrix& m) { // Transform the bounding sphere m.transformPoint(center, ¢er); Vector3 translate; m.decompose(&translate, NULL, NULL); float r = radius * translate.x; r = std::max(radius, radius * translate.y); r = std::max(radius, radius * translate.z); radius = r; // Transform the bounding box Vector3 corners[8]; corners[0].set(min.x, max.y, max.z); // Left-bottom-front. corners[1].set(min.x, min.y, max.z); // Right-bottom-front. corners[2].set(max.x, min.y, max.z); // Right-top-front. corners[3].set(max.x, max.y, max.z); // Right-top-back. corners[4].set(max.x, max.y, min.z); // Right-bottom-back. corners[5].set(max.x, min.y, min.z); // Left-bottom-back. corners[6].set(min.x, min.y, min.z); // Left-top-back. corners[7].set(min.x, max.y, min.z); // Transform the corners, recalculating the min and max points along the way. m.transformPoint(corners[0], &corners[0]); Vector3 newMin = corners[0]; Vector3 newMax = corners[0]; for (int i = 1; i < 8; i++) { m.transformPoint(corners[i], &corners[i]); updateMinMax(&corners[i], &newMin, &newMax); } min = newMin; max = newMax; } void BoundingVolume::merge(const BoundingVolume& v) { // Merge the box portion min.x = std::min(min.x, v.min.x); min.y = std::min(min.y, v.min.y); min.z = std::min(min.z, v.min.z); max.x = std::max(max.x, v.max.x); max.y = std::max(max.y, v.max.y); max.z = std::max(max.z, v.max.z); // Merge the sphere portion // Calculate the distance between the two centers. float vx = center.x - v.center.x; float vy = center.y - v.center.y; float vz = center.z - v.center.z; float d = sqrt(vx * vx + vy * vy + vz * vz); // If one sphere is contained inside the other, set to the larger sphere. if (d <= (v.radius - radius)) { // Use targert volume radius = v.radius; center = v.center; } else if (d <= (radius - v.radius)) { // No change } else { // Calculate the unit vector between the two centers. float dI = 1.0f / d; vx *= dI; vy *= dI; vz *= dI; // Calculate the new radius. float r = (radius + v.radius + d) * 0.5f; // Calculate the new center. float scaleFactor = (r - v.radius); vx = vx * scaleFactor + v.center.x; vy = vy * scaleFactor + v.center.y; vz = vz * scaleFactor + v.center.z; // Set the new center and radius. center.x = vx; center.y = vy; center.z = vz; radius = r; } } }