// Returns 'true' if the OBB intersects (or is inside) the frustum, 'false' otherwise. // 'cameraRelativeOffset' can be used to intersect a world-space OBB with a camera-relative frustum. public static bool Overlap(OrientedBBox obb, Vector3 cameraRelativeOffset, Frustum frustum, int numPlanes, int numCorners) { Vector3 center = obb.center + cameraRelativeOffset; Vector3 forward = Vector3.Cross(obb.up, obb.right); bool overlap = true; // Test the OBB against frustum planes. Frustum planes have inward-facing. // The OBB is outside if it's entirely behind one of the frustum planes. // See "Real-Time Rendering", 3rd Edition, 16.10.2. for (int i = 0; overlap && i < numPlanes; i++) { Vector3 n = frustum.planes[i].normal; float d = frustum.planes[i].distance; // Max projection of the half-diagonal onto the normal (always positive). float maxHalfDiagProj = obb.extentX * Mathf.Abs(Vector3.Dot(n, obb.right)) + obb.extentY * Mathf.Abs(Vector3.Dot(n, obb.up)) + obb.extentZ * Mathf.Abs(Vector3.Dot(n, forward)); // Negative distance -> center behind the plane (outside). float centerToPlaneDist = Vector3.Dot(n, center) + d; // outside = maxHalfDiagProj < -centerToPlaneDist // outside = maxHalfDiagProj + centerToPlaneDist < 0 // overlap = overlap && !outside overlap = overlap && (maxHalfDiagProj + centerToPlaneDist >= 0); } if (numCorners == 0) { return(overlap); } // Test the frustum corners against OBB planes. The OBB planes are outward-facing. // The frustum is outside if all of its corners are entirely in front of one of the OBB planes. // See "Correct Frustum Culling" by Inigo Quilez. // We can exploit the symmetry of the box by only testing against 3 planes rather than 6. Plane[] planes = new Plane[3]; planes[0].normal = obb.right; planes[0].distance = obb.extentX; planes[1].normal = obb.up; planes[1].distance = obb.extentY; planes[2].normal = forward; planes[2].distance = obb.extentZ; for (int i = 0; overlap && i < 3; i++) { Plane plane = planes[i]; // We need a separate counter for the "box fully inside frustum" case. bool outsidePos = true; // Positive normal bool outsideNeg = true; // Reversed normal // Merge 2 loops. Continue as long as all points are outside either plane. for (int j = 0; j < numCorners; j++) { float proj = Vector3.Dot(plane.normal, frustum.corners[j] - center); outsidePos = outsidePos && (proj > plane.distance); outsideNeg = outsideNeg && (-proj > plane.distance); } overlap = overlap && !(outsidePos || outsideNeg); } return(overlap); }