Newer
Older
rpg / v2 / packages / engine / src / render / __tests__ / shadowIntensity.test.ts
/**
 * Тесты контраста теней: чистая функция перевода силы теней + облачности в
 * sun.shadow.intensity (three 0.186: mix(1.0, shadow, intensity) в шейдере).
 */
import { describe, expect, it } from 'vitest';
import { OVERCAST_TOP_LIGHT, SHADOW_CLOUD_FADE, shadowIntensity, zenithIntensity } from '../voxelRenderer';

describe('shadowIntensity (контраст теней)', () => {
    it('полные тени без облачности — intensity 1', () => {
        expect(shadowIntensity(1, 0)).toBe(1);
    });

    it('облачность светлит тени: 0 → 1 − FADE, монотонно', () => {
        expect(shadowIntensity(1, 1)).toBeCloseTo(1 - SHADOW_CLOUD_FADE);
        let prev = shadowIntensity(1, 0);
        for (let c = 0.1; c <= 1.001; c += 0.1) {
            const cur = shadowIntensity(1, Math.min(c, 1));
            expect(cur).toBeLessThanOrEqual(prev);
            prev = cur;
        }
    });

    it('нулевая сила — теней нет при любой облачности', () => {
        expect(shadowIntensity(0, 0)).toBe(0);
        expect(shadowIntensity(0, 1)).toBe(0);
    });

    it('клампы аргументов 0..1, результат не ниже 0', () => {
        expect(shadowIntensity(-2, 0)).toBe(0);
        expect(shadowIntensity(5, 0)).toBe(1);
        expect(shadowIntensity(5, -1)).toBe(1);
        expect(shadowIntensity(0.5, 5)).toBeCloseTo(0.5 * (1 - SHADOW_CLOUD_FADE));
    });
});

describe('zenithIntensity (пасмурная тенька сверху)', () => {
    it('ясный день — зенитного света нет', () => {
        expect(zenithIntensity(0, 0, 1)).toBe(0);
        expect(zenithIntensity(0.1, 0, 1)).toBeLessThan(OVERCAST_TOP_LIGHT / 3);
    });

    it('пасмурный полдень — максимум (OVERCAST_TOP_LIGHT)', () => {
        expect(zenithIntensity(1, 0, 1)).toBeCloseTo(OVERCAST_TOP_LIGHT);
        expect(zenithIntensity(5, -1, 5)).toBeCloseTo(OVERCAST_TOP_LIGHT); // клампы
    });

    it('ночь гасит вместе с небом, тёмный интерьер — тоже', () => {
        expect(zenithIntensity(1, 1, 1)).toBeLessThan(OVERCAST_TOP_LIGHT / 10);
        expect(zenithIntensity(1, 0, 0.2)).toBeCloseTo(OVERCAST_TOP_LIGHT * 0.2);
    });
});