studio/src/editor/engine/OBBCollision.js
МИН 31adbf151b Initial public release: Студия Рублокса v1.0
Open-source веб-студия для создания игр Рублокса, двойная лицензия
AGPL-3.0 + Коммерческая.

Главное:
- Vite 5 + React 18 + Babylon 7.54.3 + Monaco Editor + Colyseus 0.16
- Самодостаточный движок ~28к строк (66 файлов): BlockManager,
  TerrainVoxelBuilder, ModelManager, DecoManager, PlayerController,
  ScriptSandboxWorker, MultiplayerSync, 30+ GD-гейммодов
- Главный редактор KubikonEditor (~37к строк) + панели, ScriptEditor (Monaco)
- Витрина игр (KubikonFeed, KubikonStudio, KubikonDocs, KubikonLearn)
- Geometry Dash sub-app (GdMenu, GdShop, GdRules, GdCoverArt)
- 10 admin-preview каталогов для дизайнеров (скины, музыка, порталы и т.д.)
- Конфигурируемый бэкенд через VITE_API_BASE — работает со staging
  (dev-api.rublox.pro) без настройки
- Standalone-режим (VITE_STANDALONE=true) — открыть пустой редактор без бэка
- Полная документация (на русском): README, ARCHITECTURE, CONTRIBUTING,
  SECURITY, CHANGELOG
- ESLint + Prettier + EditorConfig
- Legal: LICENSE (AGPL-3.0), LICENSE-COMMERCIAL.md, CLA.md, COPYRIGHT.md
- Issue templates: bug_report, feature_request, security_disclosure

Перед публикацией:
- Все импорты из minecraftia заменены на локальные
- Все хардкоды URL (minecraftia-school.ru) и внутренних IP убраны → env
- Admin-эндпоинты Kubikon3DService вырезаны (остаются в приватном репо)
- AdminKubikonModeration не публикуется (модерация — в team.rublox.pro)
- 93 МБ ассетов public/kubikon-assets вынесены в .gitignore
  (раздаются через release artifact)
2026-05-27 23:41:10 +03:00

115 lines
4.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* OBB (Oriented Bounding Box) — AABB пересечение через SAT.
*
* Используется для столкновения игрока (AABB) с повёрнутыми примитивами (OBB).
*
* OBB задаётся:
* - центр (cx, cy, cz)
* - полуразмеры по локальным осям (hx, hy, hz)
* - 3 ортонормированных локальных оси (axes), задающих ориентацию
*
* AABB задаётся:
* - центр (cx, cy, cz)
* - полуразмеры (hw, hh, hd) — по мировым X/Y/Z
*
* Возвращает true если есть пересечение.
*
* Алгоритм SAT (Separating Axis Theorem): два выпуклых тела не пересекаются
* тогда и только тогда, когда есть ось, на проекции которой их интервалы
* не пересекаются. Для AABB×OBB достаточно проверить 15 осей:
* - 3 оси AABB (X/Y/Z)
* - 3 оси OBB (axes[0..2])
* - 9 cross-products пар осей
*/
const EPS = 1e-6;
/**
* Построить axes для OBB с произвольным rotation (Euler XYZ).
* Возвращает 3 единичных вектора локальных осей в мировых координатах.
*/
export function buildOBBAxes(rotX, rotY, rotZ) {
const cx = Math.cos(rotX), sx = Math.sin(rotX);
const cy = Math.cos(rotY), sy = Math.sin(rotY);
const cz = Math.cos(rotZ), sz = Math.sin(rotZ);
// Babylon использует Euler XYZ: M = Rx * Ry * Rz (Right-handed Y-up).
// Локальная ось X в мире:
const axisX = [
cy * cz,
cy * sz,
-sy,
];
const axisY = [
sx * sy * cz - cx * sz,
sx * sy * sz + cx * cz,
sx * cy,
];
const axisZ = [
cx * sy * cz + sx * sz,
cx * sy * sz - sx * cz,
cx * cy,
];
return [axisX, axisY, axisZ];
}
/**
* AABB (cx,cy,cz, hw,hh,hd) пересекается с OBB (ocx,ocy,ocz, hx,hy,hz, axes).
*/
export function aabbIntersectsOBB(
cx, cy, cz, hw, hh, hd,
ocx, ocy, ocz, hx, hy, hz, axes
) {
// Вектор от центра OBB к центру AABB
const dx = cx - ocx, dy = cy - ocy, dz = cz - ocz;
// 3 оси AABB — стандартные X/Y/Z
const aabbAxes = [
[1, 0, 0],
[0, 1, 0],
[0, 0, 1],
];
// Проекция AABB на ось — это всегда hw*|ax| + hh*|ay| + hd*|az|
const projectAABB = (a) =>
hw * Math.abs(a[0]) + hh * Math.abs(a[1]) + hd * Math.abs(a[2]);
// Проекция OBB на ось — h0*|axis0·a| + h1*|axis1·a| + h2*|axis2·a|
const obbHalves = [hx, hy, hz];
const projectOBB = (a) =>
obbHalves[0] * Math.abs(dot(axes[0], a)) +
obbHalves[1] * Math.abs(dot(axes[1], a)) +
obbHalves[2] * Math.abs(dot(axes[2], a));
// Расстояние между центрами по оси
const distOnAxis = (a) => Math.abs(dx * a[0] + dy * a[1] + dz * a[2]);
// Проверяем 3 + 3 + 9 = 15 осей
const allAxes = [];
allAxes.push(aabbAxes[0], aabbAxes[1], aabbAxes[2]);
allAxes.push(axes[0], axes[1], axes[2]);
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
const c = cross(aabbAxes[i], axes[j]);
if (lenSq(c) > EPS) allAxes.push(c);
}
}
for (const ax of allAxes) {
const ra = projectAABB(ax);
const rb = projectOBB(ax);
const d = distOnAxis(ax);
if (d > ra + rb + EPS) return false; // нашли разделяющую ось
}
return true;
}
function dot(a, b) { return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; }
function cross(a, b) {
return [
a[1]*b[2] - a[2]*b[1],
a[2]*b[0] - a[0]*b[2],
a[0]*b[1] - a[1]*b[0],
];
}
function lenSq(a) { return a[0]*a[0] + a[1]*a[1] + a[2]*a[2]; }