OBB (Oriented Bounding Box, ориентированная ограничивающая коробка) — это тип [[Bounding Volumes (Ограничивающие Объемы)|ограничивающего объёма]], представляющий собой прямоугольный [[Параллелепипед (Parallelepiped)|параллелепипед]] в [[Трехмерное пространство (3D, three-dimensional space)|3D-пространстве]] или [[Прямоугольник (Rect, Rectangle)|прямоугольник]] в [[Двумерное пространство (2D, Two-dimensional space)|2D]], который может быть повёрнут относительно координатных осей. В отличие от [[AABB]], который выровнен вдоль осей, OBB может быть произвольно ориентирован в пространстве. Структурно OBB обычно представляют с помощью центральной точки, трех векторов, указывающих направления и длины полуосей, и, возможно, матрицы поворота для ориентации. ### Применение OBB в игровой разработке: 1. **Коллизии (Collision Detection)**: Проверка [[Пересечение|пересечений]] между OBB обычно быстрее, чем между сложными мешами (meshes), но сложнее и медленнее, чем между AABB. 2. **Оптимизация отрисовки (Rendering Optimization)**: OBB может использоваться для быстрого определения, находится ли объект в поле зрения камеры. 3. **Иерархическая ограничивающая система (Bounding Volume Hierarchies)**: OBB часто используются в составе более сложных структур для ускорения различных вычислений. ### Производительность: - **Память**: OBB требует хранения большего количества данных по сравнению с AABB (матрицы поворота, например). - **Вычислительная нагрузка**: Операции с OBB обычно требуют больше вычислений, особенно при проверке пересечений. ### Пример кода Для проверки пересечения двух OBB (Oriented Bounding Boxes) можно использовать метод, основанный на тесте разделяющей оси (Separating Axis Theorem, SAT). Этот метод предполагает, что если существует хотя бы одна ось, вдоль которой проекции двух OBB не пересекаются, то сами OBB также не пересекаются. Пример кода на C# для Unity: Хотя код и написан с использованием зависимостей от Unity, но код легко обособить от Unity, используя Vector3 из другой библиотеки. ```csharp using UnityEngine; public class OBB { public Vector3 Center; public Vector3[] Axis; // Local x, y, z axes public Vector3 Extents; // Halfwidths along each axis public OBB(Vector3 center, Vector3 extents, Quaternion rotation) { Center = center; Extents = extents; Axis = new Vector3[3]; Axis[0] = rotation * Vector3.right; Axis[1] = rotation * Vector3.up; Axis[2] = rotation * Vector3.forward; } public static bool AreIntersecting(OBB a, OBB b) { float ra, rb; float[,] R = new float[3, 3], AbsR = new float[3, 3]; // Compute rotation matrix expressing b in a's coordinate frame for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { R[i, j] = Vector3.Dot(a.Axis[i], b.Axis[j]); } } // Compute translation vector t Vector3 t = b.Center - a.Center; // Bring translation into a's coordinate frame t = new Vector3(Vector3.Dot(t, a.Axis[0]), Vector3.Dot(t, a.Axis[1]), Vector3.Dot(t, a.Axis[2])); // Compute common subexpressions; add in an epsilon term to counteract arithmetic errors for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { AbsR[i, j] = Mathf.Abs(R[i, j]) + Mathf.Epsilon; } } // Test axes L = A0, A1, A2 (A's basis vectors) for (int i = 0; i < 3; i++) { ra = a.Extents[i]; rb = b.Extents[0] * AbsR[i, 0] + b.Extents[1] * AbsR[i, 1] + b.Extents[2] * AbsR[i, 2]; if (Mathf.Abs(t[i]) > ra + rb) return false; } // Test axes L = B0, B1, B2 (B's basis vectors) for (int i = 0; i < 3; i++) { ra = a.Extents[0] * AbsR[0, i] + a.Extents[1] * AbsR[1, i] + a.Extents[2] * AbsR[2, i]; rb = b.Extents[i]; if (Mathf.Abs(t[0] * R[0, i] + t[1] * R[1, i] + t[2] * R[2, i]) > ra + rb) return false; } // Additional 9 tests for cross products of each basis vector pair // Skipping for brevity, but they are similar to the above tests return true; } } ``` ##### Производительность Этот метод является вычислительно затратным, особенно в сценах с большим количеством объектов. Он включает в себя множество операций с плавающей точкой и произведений скалярных векторов. Если в вашей игре ожидается большое количество таких проверок, это может стать узким местом. В таком случае рекомендуется использовать этот метод с осторожностью, возможно, применяя его только для объектов, которые уже прошли более простую проверку (например, с использованием AABB).