Мягкие тела: приближения через сетку пружин

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

Мягкое тело создается как комбинация следующих компонентов:

  • Узлы (nodes) — точки с массой и положением в пространстве.
  • Связи (springs) — упругие элементы, соединяющие узлы.
  • Фиксированные точки (anchors) — узлы, закрепленные в пространстве или привязанные к твердым телам.

Создание сетки пружин

Для моделирования мягкого тела чаще всего используется регулярная трёхмерная сетка (grid) узлов. Например, можно построить кубическую сетку узлов, где каждая точка соединена с соседями по осям X, Y и Z:

import * as CANNON from 'cannon-es';

const world = new CANNON.World();
world.gravity.set(0, -9.82, 0);

const mass = 0.1;
const nodes = [];
const springs = [];

const sizeX = 4, sizeY = 4, sizeZ = 4;
const spacing = 1;

for (let x = 0; x < sizeX; x++) {
    for (let y = 0; y < sizeY; y++) {
        for (let z = 0; z < sizeZ; z++) {
            const node = new CANNON.Body({ mass });
            node.position.set(x * spacing, y * spacing, z * spacing);
            world.addBody(node);
            nodes.push(node);
        }
    }
}

// Соединение соседних узлов пружинами
function getIndex(x, y, z) {
    return x * sizeY * sizeZ + y * sizeZ + z;
}

const stiffness = 50;
const damping = 0.1;

for (let x = 0; x < sizeX; x++) {
    for (let y = 0; y < sizeY; y++) {
        for (let z = 0; z < sizeZ; z++) {
            const idx = getIndex(x, y, z);
            const node = nodes[idx];

            // Соединяем с соседями по X
            if (x < sizeX - 1) {
                const neighbor = nodes[getIndex(x + 1, y, z)];
                const spring = new CANNON.Spring(node, neighbor, { restLength: spacing, stiffness, damping });
                springs.push(spring);
            }
            // Соединяем с соседями по Y
            if (y < sizeY - 1) {
                const neighbor = nodes[getIndex(x, y + 1, z)];
                const spring = new CANNON.Spring(node, neighbor, { restLength: spacing, stiffness, damping });
                springs.push(spring);
            }
            // Соединяем с соседями по Z
            if (z < sizeZ - 1) {
                const neighbor = nodes[getIndex(x, y, z)];
                const spring = new CANNON.Spring(node, neighbor, { restLength: spacing, stiffness, damping });
                springs.push(spring);
            }
        }
    }
}

Настройка физических свойств

  • Масса узлов влияет на инерцию тела. Большая масса делает деформации более медленными.
  • Жёсткость пружин (stiffness) определяет сопротивление растяжению и сжатию.
  • Демпфирование (damping) предотвращает сильные колебания, гасит энергию.

Регулируя эти параметры, можно моделировать разные типы мягких тел: резину, ткань, глину.

Интеграция пружин в симуляцию

Cannon.js не интегрирует пружины автоматически в основной шаг симуляции, поэтому требуется вызывать метод applyForce() через spring.applyForce() в цикле обновления:

world.step(1/60);

for (const spring of springs) {
    spring.applyForce();
}

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

Фиксация узлов и привязка к твердым телам

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

const fixedNode = new CANNON.Body({ mass: 0 });
fixedNode.position.set(0, sizeY * spacing, 0);
world.addBody(fixedNode);

const topNode = nodes[getIndex(0, sizeY - 1, 0)];
const anchorSpring = new CANNON.Spring(topNode, fixedNode, { restLength: 0, stiffness: 100, damping: 0.2 });
springs.push(anchorSpring);

Фиксация узлов позволяет управлять формой мягкого тела и предотвращает неконтролируемое падение всей сетки.

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

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

Расширенные подходы

  • Диагональные связи повышают стабильность и предотвращают сильные деформации по диагонали.
  • Мультиуровневые сетки с различным разрешением позволяют моделировать крупные объекты с внутренней структурой.
  • Взаимодействие с твердыми телами реализуется через стандартные коллизии Cannon.js, при этом мягкое тело остаётся динамическим.

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