/**
* Тесты мягкости теней: чистая функция перевода мягкости 0..1 в радиус
* размытия shadow map (тексели) — мировое размытие не зависит от фрустума.
*/
import { describe, expect, it } from 'vitest';
import { SHADOW_BLUR_MAX, shadowBlurTexels } from '../voxelRenderer';
describe('shadowBlurTexels (мягкость теней)', () => {
it('мягкость 0 — резкая тень (1 тексель) при любом фрустуме', () => {
expect(shadowBlurTexels(0, 165, 2048)).toBe(1);
expect(shadowBlurTexels(0, 700, 2048)).toBe(1);
});
it('мировое размытие постоянно: рост фрустума растит радиус в текселях', () => {
// тексель = 2·frustumHalf/mapSize; SHADOW_BLUR_MAX мировых юнитов
// при фрустуме 165 — это 3/(330/2048) ≈ 18.6 → 19 текселей
const noon = shadowBlurTexels(1, 165, 2048);
expect(noon).toBe(Math.round(SHADOW_BLUR_MAX / (330 / 2048)));
// низкое солнце — фрустум шире, тексель крупнее, текселей меньше,
// а мировое размытие то же
const dawn = shadowBlurTexels(1, 676, 2048);
expect(dawn).toBeLessThan(noon);
expect(dawn).toBeGreaterThanOrEqual(1);
});
it('монотонность по мягкости и кламп 0..1', () => {
let prev = shadowBlurTexels(0, 165, 2048);
for (let k = 0.1; k <= 1.001; k += 0.1) {
const cur = shadowBlurTexels(Math.min(k, 1), 165, 2048);
expect(cur).toBeGreaterThanOrEqual(prev);
prev = cur;
}
// клампы: отрицательная и >1 мягкость — крайние значения
expect(shadowBlurTexels(-2, 165, 2048)).toBe(1);
expect(shadowBlurTexels(5, 165, 2048)).toBe(shadowBlurTexels(1, 165, 2048));
});
it('дегенерат: нулевой фрустум не делит на ноль', () => {
expect(shadowBlurTexels(1, 0, 2048)).toBe(1);
expect(shadowBlurTexels(1, 165, 0)).toBeGreaterThanOrEqual(1);
});
});