Импорт геометрии Three.js в Trimesh

Библиотека Cannon.js предоставляет эффективный физический движок для JavaScript, который позволяет моделировать столкновения, силы и гравитацию. Одной из наиболее гибких форм коллайдеров является Trimesh — трёхмерная сетка, созданная из вершин и треугольников, идеально подходящая для сложных объектов, импортированных из других движков или библиотек, таких как Three.js.


Создание Trimesh из геометрии Three.js

В основе работы с Trimesh лежит структура данных, состоящая из массива вершин и массива индексов треугольников. Для импорта геометрии из Three.js необходимо преобразовать объекты BufferGeometry в формат, понятный Cannon.js.

import * as THREE from 'three';
import * as CANNON from 'cannon-es';

// Пример: загрузка геометрии из Three.js
const loader = new THREE.GLTFLoader();
loader.load('model.gltf', (gltf) => {
    const mesh = gltf.scene.children[0]; // берем первый меш
    const geometry = mesh.geometry;

    // Получение вершин
    const vertices = geometry.attributes.position.array;

    // Формирование массива индексов треугольников
    const indices = geometry.index ? geometry.index.array : undefined;

    const cannonTrimesh = createTrimesh(vertices, indices);
});

Функция преобразования геометрии в Trimesh

Чтобы передать геометрию в Cannon.js, необходимо создать вспомогательную функцию, которая конвертирует Float32Array вершин и Uint16Array/Uint32Array индексов в формат, ожидаемый конструктором CANNON.Trimesh.

function createTrimesh(vertices, indices) {
    const verts = [];
    const faces = [];

    // Преобразование вершин
    for (let i = 0; i < vertices.length; i += 3) {
        verts.push(vertices[i], vertices[i + 1], vertices[i + 2]);
    }

    // Преобразование индексов
    if (indices) {
        for (let i = 0; i < indices.length; i += 3) {
            faces.push(indices[i], indices[i + 1], indices[i + 2]);
        }
    } else {
        // Если индексы отсутствуют, предполагается последовательная треугольная сетка
        for (let i = 0; i < verts.length / 3; i += 3) {
            faces.push(i, i + 1, i + 2);
        }
    }

    return new CANNON.Trimesh(verts, faces);
}

Особенности:

  • В Cannon.js порядок вершин критичен для корректного расчёта нормалей и столкновений.
  • Для сложных моделей с большим количеством треугольников использование Trimesh может быть производительно затратным, особенно при динамических телах. Для таких случаев предпочтительны простые коллайдеры типа Box, Sphere или ConvexPolyhedron.

Настройка физического тела с Trimesh

После создания Trimesh его можно использовать для физического тела:

const shape = cannonTrimesh;
const body = new CANNON.Body({
    mass: 0, // 0 — статическое тело
    shape: shape,
});

body.position.set(0, 0, 0);
world.addBody(body);

Для динамических объектов масса должна быть положительной, но необходимо учитывать, что динамический Trimesh менее оптимален для производительности, чем ConvexPolyhedron. Если объект движется и сталкивается с другими объектами, рекомендуется сначала использовать ConvexHull или разбить модель на несколько упрощённых Trimesh частей.


Работа с масштабированием и трансформациями

Three.js и Cannon.js используют одинаковую систему координат, но масштаб объекта должен учитываться при передаче в Trimesh:

mesh.updateMatrixWorld(); 
const scale = mesh.scale;

const scaledVertices = [];
for (let i = 0; i < vertices.length; i += 3) {
    scaledVertices.push(
        vertices[i] * scale.x,
        vertices[i + 1] * scale.y,
        vertices[i + 2] * scale.z
    );
}

const cannonTrimesh = createTrimesh(scaledVertices, indices);

Также для корректного позиционирования тел необходимо учитывать локальные преобразования меша, чтобы физическое тело совпадало с визуальным объектом.


Оптимизация и ограничения

  • Trimesh поддерживает столкновения только с другими Trimesh или ConvexPolyhedron.
  • Динамические тела с Trimesh могут «заедать» при столкновениях с другими динамическими телами.
  • Для сложных моделей целесообразно создавать упрощённые коллайдеры, используя ConvexPolyhedron или комбинацию простых примитивов.
  • Для статических объектов Trimesh идеально подходит, так как обеспечивает точное взаимодействие сложной поверхности с другими телами.

Заключение о применении Trimesh

Использование Trimesh открывает возможность точно симулировать физику сложных объектов из Three.js, таких как модели автомобилей, зданий или скульптур. Ключевым моментом является корректное преобразование вершин и индексов, учет масштаба и оптимизация для производительности, особенно при динамических телах.

Trimesh предоставляет универсальный инструмент для интеграции визуальных моделей с физическим движком, позволяя добиться реалистичного поведения объектов без необходимости вручную создавать коллизии.