| 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 | < Назад | Оглавление | Далее > |