netlib.narod.ru | < Назад | Оглавление | Далее > |
Чтобы гарантировать, что все объекты сцены останутся поверх ландшафта, вам необходима возможность запрашивать высоту ландшафта в любой точке, а затем размещать объекты на ландшафте. Вы можете получить высоту вершин ландшафта из карты высот ландшафта, а затем вы можете вычислить высоту произвольного места ландшафта на основании данных вершин ландшафта.
Чтобы запросить высоту ландшафта в произвольной мировой позиции, вам сперва надо вычислить местоположение относительно решетки вершин ландшафта. Вы делаете это вычитая координаты проверяемой мировой позиции из начальной позиции ландшафта, чтобы учесть преобразования ландшафта, такие как перемещение. Затем вам необходимо узнать, в какой квадрат решетки ландшафта попадает проверяемая позиция, что делается путем деления вычисленной позиции (относительно ландшафта) на размер блока ландшафта.
Рис. 10.11 показывает объект с мировыми координатами (52, 48), чья позиция в решетке ландшафта будет (1, 1). Обратите внимание, что вы не учитываете местоположение объекта по оси Y (которая представляет его высоту над ландшафтом), поскольку ландшафт конструируется в плоскости XZ, и значения, которые вы ищете, относятся к этим осям.
Рис. 10.11. Размещение объекта относительно решетки ландшафта
Код для вычисления местоположения объекта на решетке ландшафта таков:
// Получаем местоположение относительно решетки ландшафта Vector2 positionInGrid = new Vector2( positionX - (StartPosition.X + Transformation.Translate.X), positionZ - (StartPosition.Y + Transformation.Translate.Z)); // Вычисляем местоположение в решетке Vector2 blockPosition = new Vector2( (int)(positionInGrid.X / blockScale), (int)(positionInGrid.Y / blockScale));
После того, как вы вычислили в каком квадрате решетки находится требуемая позиция, вы должны определить, в каком из треугольников блока она расположена. Для этого вычислим местоположение объекта внутри блока и проверим, больше ли его координата по оси X, чем координата по оси Z. Когда координата X объекта больше, чем координата Z, объект находится в верхнем треугольнике; иначе, если значение меньше, объект находится в нижнем треугольнике, что показано на рис. 10.12.
Рис. 10.12. Блок решетки ландшафта. Если координата X внутри блока больше, чем координата Z, объект находится в верхнем треугольнике. В противном случае объект находится в нижнем треугольнике
Определив, в каком треугольнике находится объект, вы можете получить высоту заданного местоположения внутри треугольника путем линейной интерполяции высот вершин треугольника. Используйте показанный ниже код метода GetHeight, чтобы вычислить высоту заданного местоположения ландшафта:
private float GetHeight(float positionX, float positionZ) { float height = -999999.0f; if (heightmap == null) return height; // Получаем местоположение относительно решетки ландшафта Vector2 positionInGrid = new Vector2( positionX - (StartPosition.X + Transformation.Translate.X), positionZ - (StartPosition.Y + Transformation.Translate.Z)); // Вычисляем местоположение в решетке Vector2 blockPosition = new Vector2( (int)(positionInGrid.X / blockScale), (int)(positionInGrid.Y / blockScale)); // Проверяем, находится ли объект в пределах решетки if (blockPosition.X >= 0 && blockPosition.X < (vertexCountX - 1) && blockPosition.Y >= 0 && blockPosition.Y < (vertexCountZ - 1)) { Vector2 blockOffset = new Vector2( blockPosition.X - (int)blockPosition.X, blockPosition.Y - (int)blockPosition.Y); // Получаем высоты четырех вершин блока решетки int vertexIndex = (int)blockPosition.X + (int)blockPosition.Y * vertexCountX; float height1 = heightmap[vertexIndex + 1]; float height2 = heightmap[vertexIndex]; float height3 = heightmap[vertexIndex + vertexCountX + 1]; float height4 = heightmap[vertexIndex + vertexCountX]; // Верхний треугольник float heightIncX, heightIncY; if (blockOffset.X > blockOffset.Y) { heightIncX = height1 - height2; heightIncY = height3 - height1; } // Нижний треугольник else { heightIncX = height3 - height4; heightIncY = height4 - height2; } // Линейная интерполяция для определения // высоты внутри треугольника float lerpHeight = height2 + heightIncX * blockOffset.X + heightIncY * blockOffset.Y; height = lerpHeight * heightScale; } return height; }
Заметьте, что вы используете этот метод только чтобы гарантировать, что все объекты будут размещены поверх ландшафта. Чтобы обеспечить реалистичное взаимодействие между объектами и ландшафтом вам необходимо реализовать систему обработки физики.
netlib.narod.ru | < Назад | Оглавление | Далее > |