Files
mrgameeng/tests/MrGameEng.Graphics.Tests/LightmapBuilderTests.cs
T
Leonid PershinandClaude Opus 4.8 79d406a9f4
CI / build-test (push) Successful in 1m14s
Add 2D lightmap: occlusion shadows and point lights
Extend the Lighting module with a per-cell lightmap. LightmapBuilder (pure,
tested) fills an ambient base, shades occluder cells, and adds point lights
that attenuate with distance and are blocked by occluders between source and
cell (grid-traced soft shadows). Lightmap holds the grid plus a greyscale
texture (Upload) and a bilinear SampleAt for the simulation; a PointLight
component places lights in the world. LightmapSystem rebuilds the grid a few
times a second (ambient from the day/night cycle with a night floor, occluders
from a game-supplied grid, point lights from the ECS); LightmapRenderSystem
multiplies the lightmap over the world after the sprite flush and under the
HUD. Wired via scene.UseLighting(...), sampled through Lighting.SampleAt. Docs
updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 18:40:17 +03:00

70 lines
2.0 KiB
C#

using MrGameEng.Lighting;
using Xunit;
namespace MrGameEng.Lighting.Tests;
public class LightmapBuilderTests
{
private static float[] Build(
int width,
int height,
float ambient,
bool[] occluders,
params LightSample[] lights
)
{
var light = new float[width * height];
LightmapBuilder.Build(light, width, height, ambient, occluders, lights);
return light;
}
[Fact]
public void Ambient_WithoutOccluders_IsUniform()
{
var light = Build(4, 4, 0.6f, new bool[16]);
Assert.All(light, v => Assert.Equal(0.6f, v, 5));
}
[Fact]
public void OccluderCell_IsDarkerThanOpenCell()
{
var occ = new bool[9];
occ[4] = true; // centre cell shaded
var light = Build(3, 3, 0.8f, occ);
Assert.True(light[4] < light[0]);
Assert.Equal(0.8f * LightmapBuilder.OccluderShade, light[4], 5);
}
[Fact]
public void PointLight_IsBrighterNearSourceAndFadesToRadius()
{
var light = Build(7, 1, 0f, new bool[7], new LightSample(0, 0, 6f, 1f));
Assert.True(light[0] > light[2] && light[2] > light[5]);
Assert.InRange(light[6], 0f, 0.01f); // на радиусе свет угасает
}
[Fact]
public void Occluder_CastsShadowBehindIt()
{
var occ = new bool[7];
occ[3] = true; // препятствие между источником (0) и дальними клетками
var light = Build(7, 1, 0f, occ, new LightSample(0, 0, 10f, 1f));
Assert.True(light[1] > 0f); // перед препятствием — освещено
Assert.Equal(0f, light[5], 5); // за препятствием — тень
}
[Fact]
public void Values_StayWithinUnitRange()
{
var light = Build(
5,
5,
0.5f,
new bool[25],
new LightSample(2, 2, 4f, 2f) // яркий свет — проверяем клампинг
);
Assert.All(light, v => Assert.InRange(v, 0f, 1f));
}
}