Oimo.js — это легковесная физическая библиотека для
JavaScript, предназначенная для моделирования жестких тел и их
взаимодействий. Одной из важных возможностей является визуализация сцены
через DebugDraw, что позволяет наблюдать физические
объекты, их столкновения и ограничения без необходимости полного
рендеринга.
DebugDraw в Oimo.js не является готовым графическим движком. Он предоставляет структуру для передачи геометрии и состояния тел в любой рендерер, будь то Canvas, WebGL или Three.js. Реализация собственного рендерера требует обработки данных от мира Oimo, таких как позиции тел, ориентации и коллайдеров.
Рендерер для DebugDraw строится вокруг обработки объектов
RigidBody и их Shape. Для начала создаётся
класс рендерера с методами для добавления и обновления объектов:
class DebugRenderer {
constructor() {
this.shapes = [];
}
addShape(shape) {
this.shapes.push(shape);
}
clear() {
this.shapes.length = 0;
}
update(world) {
for (let i = 0; i < world.rigidBodies.length; i++) {
const body = world.rigidBodies[i];
for (let j = 0; j < body.shapes.length; j++) {
const shape = body.shapes[j];
this.renderShape(shape, body);
}
}
}
renderShape(shape, body) {
// Здесь будет логика отображения фигуры
}
}
Ключевой момент: RigidBody может
содержать несколько Shape (коллайдеров). Каждая Shape имеет
тип (box, sphere, capsule,
cylinder, mesh) и параметры, определяющие
размеры.
Каждый тип Shape требует отдельной логики для отрисовки:
renderBox(shape, position, rotation) {
const size = shape.halfExtents; // {x, y, z}
// Преобразовать позицию и ориентацию тела
// Нарисовать куб через WebGL/Three.js/Canvas
}
renderSphere(shape, position) {
const radius = shape.radius;
// Нарисовать сферу
}
Капсула состоит из цилиндра с полусферами на концах. В рендерере важно учитывать ориентацию вдоль локальной оси тела.
renderCapsule(shape, position, rotation) {
const radius = shape.radius;
const height = shape.height;
// Построение цилиндра и сферических концов
}
Mesh требует обхода вершин и треугольников. В DebugDraw обычно используют wireframe, чтобы не перегружать сцену.
RigidBody хранит ориентацию в виде кватерниона. Для рендеринга его нужно преобразовать в матрицу поворота или использовать API графического движка напрямую:
function quaternionToMatrix(q) {
const x = q.x, y = q.y, z = q.z, w = q.w;
return [
1 - 2*y*y - 2*z*z, 2*x*y - 2*z*w, 2*x*z + 2*y*w, 0,
2*x*y + 2*z*w, 1 - 2*x*x - 2*z*z, 2*y*z - 2*x*w, 0,
2*x*z - 2*y*w, 2*y*z + 2*x*w, 1 - 2*x*x - 2*y*y, 0,
0, 0, 0, 1
];
}
Эта матрица используется для трансформации вершин перед отрисовкой.
DebugDraw позволяет не только отображать объекты, но и видеть контакты и ограничения:
hinge или slider можно добавить
стрелки, показывающие направление оси движения.Пример функции для отрисовки контактов:
renderContacts(world) {
const contacts = world.contacts;
for (let i = 0; i < contacts.length; i++) {
const c = contacts[i];
this.drawSphere(c.position, 0.05, 0xff0000); // красная точка
}
}
Для плавного обновления рендерера используется цикл
requestAnimationFrame:
function animate() {
world.step(); // шаг физики
renderer.clear();
renderer.update(world);
requestAnimationFrame(animate);
}
animate();
Так обеспечивается синхронизация между физическим состоянием и визуализацией.
Эта структура позволяет построить мощный, настраиваемый рендерер DebugDraw для Oimo.js, обеспечивающий полное наблюдение за физической сценой без зависимости от конкретного графического движка.