Newer
Older
rpg / v2 / packages / engine / src / render / __tests__ / modelViewer.test.ts
import { describe, expect, it } from 'vitest';
import { orbitPosition, modelStats, modelCenter } from '../modelViewer';
import { mannequin } from '../../models/mannequin';
import { VoxelGrid } from '../../voxel/grid';
import { encodeModel } from '../../models/format';

describe('ModelViewer — чистые части (урок №3)', () => {
    it('орбита: yaw 0 — камера по +x, pitch 0 — на горизонтали', () => {
        expect(orbitPosition(0, 0, 10, [0, 4, 0])).toEqual([10, 4, 0]);
        // pitch π/2 — строго над целью
        const top = orbitPosition(0.7, Math.PI / 2, 12, [1, 2, 3]);
        expect(top[0]).toBeCloseTo(1, 6);
        expect(top[1]).toBeCloseTo(14, 6);
        expect(top[2]).toBeCloseTo(3, 6);
        // yaw π/2 — по +z; дистанция масштабирует горизонтальные составляющие
        const p = orbitPosition(Math.PI / 2, 0, 5, [0, 0, 0]);
        expect(p[0]).toBeCloseTo(0, 6);
        expect(p[2]).toBeCloseTo(5, 6);
    });

    it('статы манекена: воксели/кости/тайли считаются по сетке', () => {
        const { model, rig } = mannequin();
        const s = modelStats(model, rig);
        expect(s.size).toEqual([10, 16, 4]);
        expect(s.voxels).toBe(164);
        expect(s.bones).toBe(5);
        // 16 тайлей лица + 3 скина (трек 29)
        expect(s.tiles).toBe(19);
        // без риги — 0 костей
        expect(modelStats(model).bones).toBe(0);
    });

    it('modelCenter — центр bbox занятых вокселей, не угол сетки', () => {
        // куб 2×2×2, сдвинутый в угол сетки 10×10×10 — центр (1,1,1)
        const g = new VoxelGrid(10, 10, 10);
        for (let x = 0; x <= 1; x++) for (let y = 0; y <= 1; y++) for (let z = 0; z <= 1; z++) g.set(x, y, z, 1);
        expect(modelCenter(encodeModel(g, { 1: '#fff' }))).toEqual([1, 1, 1]);
        // асимметричная модель: занят x∈[4..5] — центр 2.5 по оси со сдвигом
        const g2 = new VoxelGrid(6, 4, 2);
        g2.set(1, 0, 0, 1);
        g2.set(2, 2, 1, 1);
        expect(modelCenter(encodeModel(g2, { 1: '#fff' }))).toEqual([2, 1.5, 1]);
        // пустая модель — центр размера сетки
        expect(modelCenter(encodeModel(new VoxelGrid(4, 6, 2), {}))).toEqual([2, 3, 1]);
    });
});