Heightfield: ландшафт из массива высот

Heightfield — это специальный тип формы в Cannon.js, предназначенный для моделирования неровных поверхностей, таких как террасы, горы или волнистый рельеф. Основная идея состоит в том, чтобы использовать двумерный массив чисел, где каждое значение соответствует высоте точки на сетке.

const heights = [
    [0, 1, 0],
    [1, 2, 1],
    [0, 1, 0]
];

const elementSize = 1; // расстояние между точками сетки
const heightfieldShape = new CANNON.Heightfield(heights, { elementSize });
const body = new CANNON.Body({ mass: 0 });
body.addShape(heightfieldShape);
world.addBody(body);

Здесь heights — это матрица высот, а elementSize задает размер каждого квадрата сетки.


Основные параметры Heightfield

  • matrix (array of arrays) — двумерный массив с высотами.
  • elementSize (number) — физический размер одного элемента сетки, по умолчанию равен 1.
  • maxValue (number, необязательный) — максимальное значение высоты для оптимизации расчётов столкновений.
  • minValue (number, необязательный) — минимальное значение высоты.

Создание и добавление к телу

Heightfield нельзя использовать самостоятельно. Он всегда добавляется к объекту Body.

const mass = 0; // масса 0 — объект статический
const terrainBody = new CANNON.Body({ mass });
terrainBody.addShape(heightfieldShape);
world.addBody(terrainBody);

Замечание: Статическая природа ландшафта предотвращает его смещение под воздействием сил, но объекты, взаимодействующие с ним, будут реагировать корректно.


Расчёт столкновений

Cannon.js автоматически делит Heightfield на треугольники при расчёте столкновений. Каждый квадрат сетки разбивается на два треугольника:

  1. Нижний левый треугольник.
  2. Верхний правый треугольник.

Это позволяет корректно обрабатывать столкновения с наклонными поверхностями.

Важно: Высоты в массиве должны быть числами, иначе физика может работать некорректно.


Масштабирование и повороты

Heightfield поддерживает повороты и масштабирование через тело (Body):

terrainBody.quaternion.setFromEuler(-Math.PI / 2, 0, 0);
terrainBody.position.set(0, 0, 0);
  • Поворот часто нужен, чтобы сетка была горизонтальной в сцене.
  • Положение задаётся через position.

Работа с большими массивами

При использовании больших ландшафтов рекомендуется:

  • Сегментировать массив, чтобы избежать чрезмерной нагрузки на расчёт столкновений.
  • Использовать maxValue и minValue, чтобы оптимизировать внутренние BVH-структуры Cannon.js.
  • Избегать резких перепадов высот, так как это может привести к нестабильности симуляции.

Примеры взаимодействия с объектами

const sphereShape = new CANNON.Sphere(0.5);
const sphereBody = new CANNON.Body({ mass: 1 });
sphereBody.addShape(sphereShape);
sphereBody.position.set(1, 5, 1);
world.addBody(sphereBody);

Сфера будет корректно катиться по неровностям Heightfield, а сила тяжести и столкновения с треугольниками сетки обеспечат реалистичное поведение.


Динамическое изменение высот

Heightfield позволяет обновлять высоты на лету:

heightfieldShape.heights[1][1] = 3;
heightfieldShape.updateMinMax(); // важно обновить min/max после изменений
  • updateMinMax() — пересчитывает минимальное и максимальное значение сетки для корректной работы столкновений.
  • После изменения высот физическое тело можно перезапускать, чтобы увидеть изменения.

Производительность и оптимизация

  • Высокие разрешения сетки сильно нагружают CPU.
  • Для больших ландшафтов лучше комбинировать несколько Heightfield с меньшим размером.
  • Статические тела (mass = 0) позволяют избегать лишних расчётов силы.

Итоговые рекомендации

  • Использовать Heightfield для сложных, но статичных поверхностей.
  • Для динамических рельефов или разрушений рассматривать альтернативы, например Trimesh.
  • Правильная настройка elementSize и массива высот критична для реалистичного поведения объектов.

Heightfield в Cannon.js обеспечивает эффективный способ создания реалистичных ландшафтов с простым управлением через массив высот, обеспечивая точное взаимодействие объектов с неровной поверхностью.