2026-04-07 11:07:19 +02:00
|
|
|
import { BackSide, ShaderMaterial } from "three";
|
|
|
|
|
import { describe, expect, it } from "vitest";
|
|
|
|
|
|
|
|
|
|
import { createFogQualityMaterial } from "../../src/rendering/fog-material";
|
|
|
|
|
|
|
|
|
|
describe("fog quality material", () => {
|
|
|
|
|
it("builds a raymarched volumetric shader that stays animated through a shared time uniform", () => {
|
|
|
|
|
const result = createFogQualityMaterial({
|
|
|
|
|
colorHex: "#99aac4",
|
|
|
|
|
density: 0.55,
|
|
|
|
|
padding: 0.25,
|
|
|
|
|
time: 1.5,
|
|
|
|
|
halfSize: {
|
|
|
|
|
x: 2,
|
|
|
|
|
y: 1.5,
|
|
|
|
|
z: 1
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
expect(result.material).toBeInstanceOf(ShaderMaterial);
|
|
|
|
|
|
|
|
|
|
const material = result.material as ShaderMaterial;
|
|
|
|
|
expect(material.transparent).toBe(true);
|
|
|
|
|
expect(material.depthWrite).toBe(false);
|
|
|
|
|
expect(material.fog).toBe(true);
|
|
|
|
|
expect(material.side).toBe(BackSide);
|
|
|
|
|
expect(material.uniforms["volumeFogDensity"]?.value).toBe(0.55);
|
|
|
|
|
expect(material.uniforms["volumePadding"]?.value).toBeCloseTo(0.25, 5);
|
|
|
|
|
expect(material.uniforms["volumeHalfSize"]?.value).toMatchObject({ x: 2, y: 1.5, z: 1 });
|
2026-04-07 11:19:30 +02:00
|
|
|
expect(material.uniforms["localCameraPosition"]?.value).toMatchObject({ x: 0, y: 0, z: 0 });
|
2026-04-07 11:07:19 +02:00
|
|
|
expect(material.fragmentShader).toContain("intersectBox");
|
|
|
|
|
expect(material.fragmentShader).toContain("sampleVolumeDensity");
|
2026-04-07 11:34:04 +02:00
|
|
|
expect(material.fragmentShader).toContain("FOG_STEPS 10");
|
2026-04-07 11:19:30 +02:00
|
|
|
expect(material.fragmentShader).toContain("uniform vec3 localCameraPosition");
|
2026-04-07 11:07:19 +02:00
|
|
|
expect(result.animationUniform).toBe(material.uniforms["time"]);
|
|
|
|
|
|
|
|
|
|
result.animationUniform.value = 3.25;
|
|
|
|
|
expect(material.uniforms["time"]?.value).toBe(3.25);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("clamps oversized padding and exposes viewport emphasis controls", () => {
|
|
|
|
|
const result = createFogQualityMaterial({
|
|
|
|
|
colorHex: "#c2d8f4",
|
|
|
|
|
density: 0.4,
|
|
|
|
|
padding: 10,
|
|
|
|
|
time: 0,
|
|
|
|
|
halfSize: {
|
|
|
|
|
x: 1,
|
|
|
|
|
y: 0.5,
|
|
|
|
|
z: 0.75
|
|
|
|
|
},
|
|
|
|
|
opacityMultiplier: 1.3,
|
|
|
|
|
colorLift: 0.2
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const material = result.material as ShaderMaterial;
|
|
|
|
|
expect(material.uniforms["volumePadding"]?.value).toBeCloseTo(0.41, 5);
|
|
|
|
|
expect(material.uniforms["opacityMultiplier"]?.value).toBe(1.3);
|
|
|
|
|
expect(material.uniforms["colorLift"]?.value).toBe(0.2);
|
|
|
|
|
expect(material.vertexShader).toContain("vLocalPosition");
|
|
|
|
|
});
|
|
|
|
|
});
|