DayNight.SunShadow returns a cell offset opposite the sun's east-west position, longest near sunrise/sunset (low sun) and zero at noon/night, tilted slightly south so shadows fall in front of occluders. LightmapBuilder gains a directional shadow pass (MaxShadowCells length cap, SunShadowStrength darkening); LightmapSystem feeds it the current sun shadow each rebuild. Tests cover SunShadow's day-arc behaviour and the builder's directional darkening.
94 lines
2.8 KiB
C#
94 lines
2.8 KiB
C#
using Microsoft.Xna.Framework;
|
|
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 SunShadow_DarkensCellsInTheShadowDirection_FadingFromTheCaster()
|
|
{
|
|
var occ = new bool[7];
|
|
occ[3] = true; // occluder in the middle
|
|
var light = new float[7];
|
|
LightmapBuilder.Build(
|
|
light,
|
|
7,
|
|
1,
|
|
1f,
|
|
occ,
|
|
[],
|
|
sunShadow: new Vector2(3f, 0f),
|
|
sunShadowStrength: 0.6f
|
|
);
|
|
|
|
Assert.Equal(1f, light[2], 5); // toward the sun (opposite the shadow) — unshadowed
|
|
Assert.Equal(LightmapBuilder.OccluderShade, light[3], 5); // occluder cell stays self-shaded
|
|
Assert.True(light[4] < 1f); // in shadow
|
|
Assert.True(light[4] < light[6]); // darker near the caster, fading along the shadow
|
|
}
|
|
|
|
[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));
|
|
}
|
|
}
|