Mat4
Матрица 4×4 в column-major (по столбцам) — тип преобразований/проекций в SDK. Тот же контракт,
что у Vec3 / Quat: все методы чистые (каждый
возвращает новый Mat4; мутируют только set / copy), а везде, где принимается матрица, подойдёт
и сырой массив на 16 элементов или Float32Array (Mat4Like).
В отличие от векторов, внутреннее хранилище открыто: .m — это сырой number[] в column-major
(длина 16), его можно читать и писать напрямую.
Обзор
const world = Mat4.compose([0, 1, -3], Quat.fromEuler(0, 45, 0), 1.5) // T · R · S
const p = world.transformPoint([0, 0, -1]) // локальная точка → мир
const { position, rotation, scale } = world.decompose()
const view = Mat4.lookAt([0, 2, 5], [0, 0, 0]) // камера в (0,2,5) смотрит в начало координат
const proj = Mat4.perspective(60 * DEG2RAD, w / h, 0.1, 100)
const mvp = proj.mul(view).mul(world) // справа налево: world, затем view, затем projСырой массив: .m
mat.m: number[] // длина 16, column-major; перенос лежит в m[12..14]
mat.m[12] += vx * dt // прямая правка чисел — .m открыт намеренно
mat.toFloat32Array() // выгрузить копию как Float32Array для хоста/GPUТекучие методы никогда не меняют .m — они возвращают новый Mat4, — поэтому запись в .m это
единственный способ изменить матрицу на месте помимо set / copy.
Создание
new Mat4() // единичная
new Mat4(src: Mat4Like) // копирует src (Mat4, его .m или сырой массив на 16)
Mat4.identity(): Mat4
Mat4.from(src: Mat4Like): Mat4
Mat4.compose(position, rotation, scale? /* 1 */): Mat4 // T · R · S; scale: вектор или скаляр
Mat4.fromTranslation(v): Mat4
Mat4.fromScale(v /* vector or scalar */): Mat4
Mat4.fromQuat(q): Mat4
Mat4.fromEuler(x, y, z, order? /* "YXZ" */): Mat4 // углы в ГРАДУСАХКомпозиция
a.mul(b): Mat4 // a · b — применяет b ПЕРВЫМ, затем a (справа налево, как в glsl)
a.premul(b): Mat4 // b · a — с другой стороны
a.invert(): Mat4 // вырожденные матрицы возвращают единичную
a.transpose(): Mat4
a.determinant(): number
a.equals(b, eps? /* 1e-6 */): booleanПостроение преобразований (локальное пространство, пост-умножение)
m.translate(v): Mat4 // m · T(v)
m.rotate(rad, axis): Mat4 // m · R(axis, rad) — угол в РАДИАНАХ, ось нормализуется за тебя
m.rotateX(rad) m.rotateY(rad) m.rotateZ(rad)
m.scale(v /* vector or scalar */): Mat4Каждый применяет своё преобразование в локальном пространстве матрицы (пост-умножение), поэтому
цепочка читается как спуск по графу сцены: Mat4.fromTranslation(pos).rotateY(a).scale(2).
Преобразование векторов
m.transformPoint(v): Vec3 // полное преобразование: перенос + перспективное деление
m.transformDirection(v): Vec3 // только поворот/масштаб — без переноса и деленияVec3.transform(m) — это transformPoint со стороны вектора.
Разложение
m.position: Vec3 // геттер — столбец переноса (m[12..14])
m.scaling: Vec3 // масштаб по осям (длины базисных векторов)
m.rotation: Quat // поворот с вычтенным масштабом
m.eulerAngles: Vec3 // ГРАДУСЫ, порядок "YXZ"
m.toEuler(order? /* "YXZ" */): Vec3
m.decompose(): { position: Vec3, rotation: Quat, scale: Vec3 }
m.basisX / m.basisY / m.basisZ: Vec3 // локальные оси в мировом пространстве (столбцы 0/1/2)Все геттеры возвращают свежие значения — изменение m.position не записывается обратно в матрицу
(для этого пиши прямо в m.m[12..14]).
Камеры и проекция
Mat4.lookAt(eye, center, up? /* Vec3.up */): Mat4 // матрица ВИДА (мир → камера)
Mat4.targetTo(eye, target, up? /* Vec3.up */): Mat4 // МИРОВАЯ матрица: помещает объект в eye,
// ориентируя его лицом к target
Mat4.perspective(fovy, aspect, near, far): Mat4 // fovy в РАДИАНАХ; far может быть Infinity
Mat4.ortho(left, right, bottom, top, near, far): Mat4проекции используют clip-конвенцию WebGL/OpenGL (NDC z ∈ [−1, 1]). lookAt против targetTo —
классическая ловушка: lookAt строит обратную матрицу (вида); чтобы развернуть узел к чему-то,
нужен targetTo (или Quat.lookRotation).
Совместимость
m.set(values: ArrayLike<number>): this // единственные мутаторы (помимо записи в .m)
m.copy(src: Mat4Like): this
m.clone(): Mat4
m.toArray(): number[] // копия .m
m.toFloat32Array(): Float32ArrayПодводные камни
// ✗ градусы в rotate/perspective — аргументы-«сырые углы» это радианы
m.rotateY(90); Mat4.perspective(60, aspect, 0.1, 100)
m.rotateY(90 * DEG2RAD); Mat4.perspective(60 * DEG2RAD, aspect, 0.1, 100) // ✓
// ✗ считать .m row-major — он column-major; перенос это m[12], m[13], m[14]
m.m[3] = x
m.m[12] = x // ✓Смотрите также
- Vec2 и Vec3 —
Vec3.transform(m), направления базиса. - Quat —
Quat.fromEuler/lookRotation;mat.rotationсовместим сMat4.fromQuatв обе стороны. - Соглашения — градусы против радианов, −Z вперёд, Y вверх.