В Cannon.js мягкие тела моделируются с использованием системы связанных между собой точек, которые ведут себя как узлы сетки пружин. Такая модель позволяет приближенно воспроизводить деформации объектов под воздействием сил, коллизий и гравитации. Каждый узел обладает массой и координатой в пространстве, а пружины обеспечивают упругую связь между узлами, регулируя жёсткость, демпфирование и длину.
Мягкое тело создается как комбинация следующих компонентов:
Для моделирования мягкого тела чаще всего используется регулярная трёхмерная сетка (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);
}
}
}
}
Регулируя эти параметры, можно моделировать разные типы мягких тел: резину, ткань, глину.
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 предоставляют гибкий инструмент для моделирования упругих объектов и тканей, позволяя контролировать поведение через простые параметры физических свойств и связи между узлами. Они хорошо подходят для игровых симуляций, анимаций и научных визуализаций.