Цветовое кодирование состояний тел

Oimo.js — это легковесная библиотека для физического моделирования в браузере на языке JavaScript. Она позволяет создавать динамические симуляции твердых тел, коллизий и взаимодействий объектов в 3D-пространстве. Основным строительным блоком является мир (world), который управляет всеми физическими объектами и их обновлением во времени.

const world = new OIMO.World({
    timestep: 1/60,
    iterations: 8,
    broadphase: 2, // 1 = brute force, 2 = sweep and prune
    worldscale: 1,
    random: true,
    info: false
});

Здесь ключевое значение имеет параметр timestep, определяющий шаг симуляции, и iterations, влияющий на точность расчета контактов и силы столкновений.

Физические тела и их состояния

В Oimo.js объекты представляются rigid bodies — твердыми телами, которые могут быть динамическими, статическими или кинематическими. Каждое тело имеет набор свойств:

  • position — текущие координаты тела.
  • rotation — ориентация в пространстве (Quaternion или Euler).
  • linearVelocity — линейная скорость.
  • angularVelocity — угловая скорость.
  • sleeping — состояние покоя (true, если тело находится в состоянии сна).
  • awake() / sleep() — методы управления состоянием активности.

Статус тела напрямую влияет на его поведение в симуляции. Динамическое тело участвует во всех вычислениях столкновений и движений, статическое тело служит опорой и не перемещается, кинематическое управляется напрямую, не реагируя на силы.

Цветовое кодирование состояний тел

Для визуализации физической симуляции часто используется цветовое кодирование, позволяющее сразу определить состояние тела:

  • Зеленый — тело активно и движется, вычисляются все силы и столкновения.
  • Красный — тело спит (sleeping), не участвует в расчетах до воздействия внешней силы.
  • Синий — статическое тело, неподвижное.
  • Желтый — кинематическое тело, управляемое вручную через код.

Пример применения цветового кодирования:

function getColorByBody(body) {
    if (!body.isDynamic) return 0x0000ff; // синий
    if (body.sleeping) return 0xff0000;   // красный
    return 0x00ff00;                      // зеленый
}

Каждый кадр симуляции можно обновлять, проверяя состояние тела:

world.bodies.forEach(body => {
    const color = getColorByBody(body);
    meshMap[body.id].material.color.setHex(color);
});

Управление переходами между состояниями

Состояния тела могут изменяться динамически:

  • Пробуждение (wake) — активное тело, которое раньше спало:
body.awake();
  • Усыпление (sleep) — экономия ресурсов для объектов, которые долго не двигаются:
body.sleep();
  • Статус кинематического тела — обновляется напрямую, игнорируя силы:
body.setKinematicPosition({x: 5, y: 10, z: 0});

При переходе между состояниями цветовое кодирование должно синхронизироваться с новым статусом тела.

Визуальная интеграция с Three.js

Oimo.js часто используется совместно с Three.js для рендеринга объектов. Связь между физическим телом и графическим объектом осуществляется через массив сопоставления:

const meshMap = {};
world.bodies.forEach(body => {
    const geometry = new THREE.BoxGeometry(...);
    const material = new THREE.MeshStandardMaterial({color: 0x00ff00});
    const mesh = new THREE.Mesh(geometry, material);
    meshMap[body.id] = mesh;
    scene.add(mesh);
});

При каждом обновлении физики:

world.step();
world.bodies.forEach(body => {
    const mesh = meshMap[body.id];
    mesh.position.copy(body.getPosition());
    mesh.quaternion.copy(body.getQuaternion());
    mesh.material.color.setHex(getColorByBody(body));
});

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

Оптимизация рендеринга состояний

Для крупных сцен с десятками или сотнями тел важно минимизировать количество операций обновления цвета:

  • Кэшировать последнее состояние и менять цвет только при его изменении.
  • Использовать InstancedMesh в Three.js для массового рендеринга объектов одного типа.
  • Сохранять флаг активности, чтобы избежать лишних вызовов mesh.material.color.setHex.
if (body.prevState !== body.sleeping) {
    mesh.material.color.setHex(getColorByBody(body));
    body.prevState = body.sleeping;
}

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

Дополнительные эффекты состояния

Помимо цвета, можно использовать прозрачность, масштаб или подсветку для визуализации состояния тела:

  • Прозрачность — тело спит, но все еще видно на сцене.
  • Вспышка при пробуждении — кратковременный эффект для привлечения внимания.
  • Контурная подсветка — выделение кинематических или статических тел для облегчения анализа сцены.

Эти визуальные индикаторы помогают создавать интерактивные симуляции, где физическое поведение тел сразу понятно по графическому представлению.