auto-git:

[add] tests/domain/celestial-shadows.test.ts
This commit is contained in:
2026-04-22 14:56:45 +02:00
parent 0bd859cefd
commit f00673d3ac

View File

@@ -0,0 +1,143 @@
import {
OrthographicCamera,
PerspectiveCamera
} from "three";
import { describe, expect, it } from "vitest";
import {
fitCelestialDirectionalShadow,
resolveDominantCelestialShadowCaster
} from "../../src/rendering/celestial-shadows";
describe("celestial shadows", () => {
it("chooses one deterministic dominant celestial shadow caster", () => {
const sun = {
colorHex: "#fff1d5",
intensity: 1.6,
direction: {
x: 0.45,
y: 0.88,
z: 0.15
}
};
const moon = {
colorHex: "#99b5ff",
intensity: 0.4,
direction: {
x: -0.45,
y: 0.72,
z: -0.2
}
};
expect(resolveDominantCelestialShadowCaster(sun, moon)?.key).toBe("sun");
expect(
resolveDominantCelestialShadowCaster(
{
...sun,
intensity: 0.1
},
{
...moon,
intensity: 0.35
}
)?.key
).toBe("moon");
expect(
resolveDominantCelestialShadowCaster(
{
...sun,
intensity: 0
},
null
)
).toBeNull();
});
it("fits a bounded perspective shadow volume around the active view", () => {
const camera = new PerspectiveCamera(60, 16 / 9, 0.1, 1000);
camera.position.set(0, 12, 24);
camera.lookAt(0, 4, 0);
camera.updateMatrixWorld();
const fit = fitCelestialDirectionalShadow({
activeCamera: camera,
focusTarget: {
center: {
x: 0,
y: 4,
z: 0
},
radius: 6
},
lightDirection: {
x: 0.45,
y: 0.88,
z: 0.15
},
mapSize: 2048,
sceneBounds: {
min: {
x: -500,
y: -10,
z: -500
},
max: {
x: 500,
y: 40,
z: 500
}
}
});
expect(fit).not.toBeNull();
expect(fit?.cameraBounds.right).toBeGreaterThan(0);
expect(fit?.cameraBounds.top).toBeGreaterThan(0);
expect((fit?.cameraBounds.right ?? 0) - (fit?.cameraBounds.left ?? 0)).toBeGreaterThan(30);
expect((fit?.cameraBounds.right ?? 0) - (fit?.cameraBounds.left ?? 0)).toBeLessThan(280);
expect(fit?.cameraBounds.far).toBeGreaterThan(fit?.cameraBounds.near ?? 0);
expect(fit?.normalBias ?? 0).toBeGreaterThan(0);
});
it("fits orthographic viewport shadows without collapsing depth coverage", () => {
const camera = new OrthographicCamera(-12, 12, 10, -10, 0.1, 1000);
camera.position.set(0, 30, 0);
camera.lookAt(0, 0, 0);
camera.updateMatrixWorld();
const fit = fitCelestialDirectionalShadow({
activeCamera: camera,
focusTarget: {
center: {
x: 0,
y: 0,
z: 0
},
radius: 8
},
lightDirection: {
x: -0.25,
y: 0.92,
z: 0.3
},
mapSize: 1024,
sceneBounds: {
min: {
x: -40,
y: -2,
z: -40
},
max: {
x: 40,
y: 18,
z: 40
}
}
});
expect(fit).not.toBeNull();
expect((fit?.cameraBounds.right ?? 0) - (fit?.cameraBounds.left ?? 0)).toBeGreaterThan(20);
expect((fit?.cameraBounds.top ?? 0) - (fit?.cameraBounds.bottom ?? 0)).toBeGreaterThan(20);
expect(fit?.cameraBounds.far).toBeGreaterThan(20);
});
});