netlib.narod.ru | < Назад | Оглавление | Далее > |
Чтобы обнаружить случаи, когда объект в сцене пересекается с частью ландшафта, вам необходимо создать какие-нибудь методы проверки столкновений. Одна из полезных проверок столкновений — между лучом и ландшафтом. Например, если объект перемещается в сцене, вы можете отследить луч, идущий в направлении перемещения объекта, и получить расстояние между ним и ландшафтом.
Чтобы проверить пересечение луча и ландшафта вы выполняете проверку столкновений между лучом и картой высот ландшафта, вместо того, чтобы проверять пересечение луча и сетки ландшафта (множества треугольников). Проверка столкновений делится на две части. В первой части вы выполняете линейный поиск по направлению луча, пока не найдете одну точку вне (над) и другую внутри (под) ландшафта. Затем вы выполняете бинарный поиск между этими двумя точками, чтобы найти точное местоположение точки столкновения с ландшафтом. На рис. 10.13 показан процесс линейного поиска, где найдены ближайшие точки вне и внутри ландшафта.
Рис. 10.13. Линейный поиск используется для обнаружения одной точки вне ландшафта, и другой внутри него
Для выполнения линейного поиска воспользуйтесь следующим кодом:
// Хорошей величиной шага является половина // размера блока blockScale Vector3 rayStep = ray.Direction * blockScale * 0.5f; Vector3 rayStartPosition = ray.Position; // Линейный поиск - цикл, пока не найдены точки // вне и внутри ландшафта Vector3 lastRayPosition = ray.Position; ray.Position += rayStep; float height = GetHeight(ray.Position); while (ray.Position.Y > height && height >= 0) { lastRayPosition = ray.Position; ray.Position += rayStep; height = GetHeight(ray.Position); }
После линейного поиска переменная lastRayPosition хранит местоположение вне ландшафта, а переменная ray хранит местоположение внутри ландшафта. Теперь вам необходимо выполнить бинарный поиск между этими двумя точками, чтобы найти точку, ближайшую к поверхности ландшафта. Вы выполняете поиск с фиксированным количеством шагов, и 32 шага достаточно, чтобы обеспечить приемлемый уровень точности. Код для бинарного поиска таков:
Vector3 startPosition = lastRayPosition; Vector3 endPosition = ray.Position; // Бинарный поиск с 32 шагами. // Пробуем найти точное место пересечения for (int i = 0; i < 32; i++) { // Проход бинарного поиска Vector3 middlePoint = (startPosition + endPosition) * 0.5f; if (middlePoint.Y < height) endPosition = middlePoint; else startPosition = middlePoint; } Vector3 collisionPoint = (startPosition + endPosition) * 0.5f;
Теперь создадим метод Intersect, для проверки пересечения луча и ландшафта. Метод Intersect возвращает расстояние между начальной точкой луча и точкой пересечения с ландшафтом, а если пересечение с ландшафтом отсутствует, метод возвратит null. Ниже показан код метода Intersect класса Terrain:
public float? Intersects(Ray ray) { float? collisionDistance = null; Vector3 rayStep = ray.Direction * blockScale * 0.5f; Vector3 rayStartPosition = ray.Position; // Линейный поиск - цикл, пока не найдены точки // вне и внутри ландшафта Vector3 lastRayPosition = ray.Position; ray.Position += rayStep; float height = GetHeight(ray.Position); while (ray.Position.Y > height && height >= 0) { lastRayPosition = ray.Position; ray.Position += rayStep; height = GetHeight(ray.Position); } // Если луч пересекается с ландшафтом if (height >= 0) { Vector3 startPosition = lastRayPosition; Vector3 endPosition = ray.Position; // Бинарный поиск. Ищем точное место пересечения for (int i = 0; i < 32; i++) { // Проход бинарного поиска Vector3 middlePoint = (startPosition + endPosition) * 0.5f; if (middlePoint.Y < height) endPosition = middlePoint; else startPosition = middlePoint; } Vector3 collisionPoint = (startPosition + endPosition) * 0.5f; collisionDistance = Vector3.Distance(rayStartPosition, collisionPoint); } return collisionDistance; }
netlib.narod.ru | < Назад | Оглавление | Далее > |