Newer
Older
rpg / v2 / packages / engine / src / render / __tests__ / cameraMath.test.ts
/** Тесты чистой математики камеры: направление взгляда и орбита — без WebGL. */
import { describe, expect, it } from 'vitest';
import { ISO_YAW } from '../voxelRenderer';
import { camForward, orbitPosition } from '../cameraMath';

describe('camForward (направление взгляда от yaw/pitch)', () => {
    it('pitch 0 — горизонтальный взгляд против орбит-направления', () => {
        const f = camForward(ISO_YAW, 0);
        expect(f[1]).toBeCloseTo(0); // горизонталь (−0 тоже горизонталь)
        // орбита «target → камера» при yaw π/4 — (+x,+z); взгляд — в минус
        expect(f[0]).toBeCloseTo(-Math.cos(ISO_YAW));
        expect(f[2]).toBeCloseTo(-Math.sin(ISO_YAW));
    });
    it('pitch > 0 — камера смотрит вниз (Y отрицателен, грабля «из-под земли»)', () => {
        const f = camForward(0.5, 0.5);
        expect(f[1]).toBeLessThan(0);
    });
    it('pitch < 0 — взгляд вверх; длина всегда 1', () => {
        const up = camForward(1.0, -0.3);
        expect(up[1]).toBeGreaterThan(0);
        const len = Math.hypot(...camForward(2.7, -0.8));
        expect(len).toBeCloseTo(1);
    });
});

describe('orbitPosition (переезд из modelViewer: формула та же)', () => {
    it('yaw π/4 — камера в (+x,+z) от цели, pitch поднимает по Y', () => {
        const pos = orbitPosition(Math.PI / 4, 0, 10, [1, 2, 3]);
        expect(pos[0]).toBeCloseTo(1 + 10 * Math.cos(Math.PI / 4));
        expect(pos[1]).toBeCloseTo(2);
        expect(pos[2]).toBeCloseTo(3 + 10 * Math.sin(Math.PI / 4));
        const above = orbitPosition(Math.PI / 4, 0.5, 10, [0, 0, 0]);
        expect(above[1]).toBeCloseTo(10 * Math.sin(0.5));
    });
});