feat(render): implement Campaign AR and terrain fidelity
This commit is contained in:
parent
99cf26e00c
commit
7a5f96ede5
368 changed files with 50611 additions and 950 deletions
|
|
@ -0,0 +1,214 @@
|
|||
using System.Numerics;
|
||||
using AcDream.App.Rendering;
|
||||
using AcDream.App.Rendering.Packs;
|
||||
using AcDream.Core.World;
|
||||
|
||||
namespace AcDream.App.Tests.Rendering;
|
||||
|
||||
public sealed class DirectionalShadowEnvironmentGateTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(false, false, false, DirectionalShadowGateReason.PackDisabled)]
|
||||
[InlineData(true, true, false, DirectionalShadowGateReason.PortalOrLoginCover)]
|
||||
[InlineData(true, false, true, DirectionalShadowGateReason.Indoor)]
|
||||
internal void NonWorldGates_DisableWithoutCreatingCelestialWork(
|
||||
bool enabled,
|
||||
bool cover,
|
||||
bool indoor,
|
||||
DirectionalShadowGateReason expected)
|
||||
{
|
||||
DirectionalShadowEnvironmentInput input = new(
|
||||
enabled,
|
||||
cover,
|
||||
indoor,
|
||||
Celestial(AuthoredCelestialShadowSourceKind.SecondaryMoon, 35f),
|
||||
Atmosphere(WeatherKind.Clear));
|
||||
|
||||
DirectionalShadowEnvironmentState result =
|
||||
DirectionalShadowEnvironmentGate.Evaluate(
|
||||
in input,
|
||||
DirectionalShadowAtmospherePolicy.BuiltIn);
|
||||
|
||||
Assert.False(result.ShouldRender);
|
||||
Assert.Equal(expected, result.Reason);
|
||||
Assert.Equal(0f, result.Strength);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SelectedCelestialBelowHorizon_DisablesAndPreservesSourceIdentity()
|
||||
{
|
||||
AuthoredCelestialShadowSource source = Celestial(
|
||||
AuthoredCelestialShadowSourceKind.SecondaryMoon,
|
||||
-2f);
|
||||
DirectionalShadowEnvironmentInput input = new(
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
source,
|
||||
Atmosphere(WeatherKind.Clear));
|
||||
|
||||
DirectionalShadowEnvironmentState result =
|
||||
DirectionalShadowEnvironmentGate.Evaluate(
|
||||
in input,
|
||||
DirectionalShadowAtmospherePolicy.BuiltIn);
|
||||
|
||||
Assert.False(result.ShouldRender);
|
||||
Assert.Equal(
|
||||
DirectionalShadowGateReason.SelectedLightBelowHorizon,
|
||||
result.Reason);
|
||||
Assert.Equal(source.SurfaceToLightDirection, result.SurfaceToLightDirection);
|
||||
Assert.Equal(source.Kind, result.SourceKind);
|
||||
Assert.Equal(source.ObjectIndex, result.SourceObjectIndex);
|
||||
Assert.Equal(source.GfxObjId, result.SourceGfxObjId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NoVisibleCelestial_DisablesBeforeAtmosphereMapping()
|
||||
{
|
||||
DirectionalShadowEnvironmentInput input = new(
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
AuthoredCelestialShadowSource.None(authoredEnergy: 1f),
|
||||
Atmosphere(WeatherKind.Clear));
|
||||
|
||||
DirectionalShadowEnvironmentState result =
|
||||
DirectionalShadowEnvironmentGate.Evaluate(
|
||||
in input,
|
||||
DirectionalShadowAtmospherePolicy.BuiltIn);
|
||||
|
||||
Assert.False(result.ShouldRender);
|
||||
Assert.Equal(DirectionalShadowGateReason.NoVisibleCelestial, result.Reason);
|
||||
Assert.Equal(AuthoredCelestialShadowSourceKind.None, result.SourceKind);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SelectedCelestialWithoutAuthoredEnergy_DisablesAndPreservesSourceIdentity()
|
||||
{
|
||||
AuthoredCelestialShadowSource source = Celestial(
|
||||
AuthoredCelestialShadowSourceKind.DominantMoon,
|
||||
35f,
|
||||
energy: 0f);
|
||||
DirectionalShadowEnvironmentInput input = new(
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
source,
|
||||
Atmosphere(WeatherKind.Clear));
|
||||
|
||||
DirectionalShadowEnvironmentState result =
|
||||
DirectionalShadowEnvironmentGate.Evaluate(
|
||||
in input,
|
||||
DirectionalShadowAtmospherePolicy.BuiltIn);
|
||||
|
||||
Assert.False(result.ShouldRender);
|
||||
Assert.Equal(
|
||||
DirectionalShadowGateReason.SelectedLightHasNoEnergy,
|
||||
result.Reason);
|
||||
Assert.Equal(source.SurfaceToLightDirection, result.SurfaceToLightDirection);
|
||||
Assert.Equal(source.Kind, result.SourceKind);
|
||||
Assert.Equal(source.ObjectIndex, result.SourceObjectIndex);
|
||||
Assert.Equal(source.GfxObjId, result.SourceGfxObjId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AuthoredWeatherAndDayGroup_SoftenAndReduceButDoNotReplaceSelectedCelestial()
|
||||
{
|
||||
AuthoredCelestialShadowSource source = Celestial(
|
||||
AuthoredCelestialShadowSourceKind.DominantMoon,
|
||||
35f);
|
||||
DirectionalShadowEnvironmentInput clearInput = new(
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
source,
|
||||
Atmosphere(WeatherKind.Clear),
|
||||
ActiveDayGroupMultiplier: 1f);
|
||||
DirectionalShadowEnvironmentInput rainInput = clearInput with
|
||||
{
|
||||
Atmosphere = Atmosphere(WeatherKind.Rain),
|
||||
ActiveDayGroupMultiplier = 0.8f,
|
||||
};
|
||||
|
||||
DirectionalShadowEnvironmentState clear =
|
||||
DirectionalShadowEnvironmentGate.Evaluate(
|
||||
in clearInput,
|
||||
DirectionalShadowAtmospherePolicy.BuiltIn);
|
||||
DirectionalShadowEnvironmentState rain =
|
||||
DirectionalShadowEnvironmentGate.Evaluate(
|
||||
in rainInput,
|
||||
DirectionalShadowAtmospherePolicy.BuiltIn);
|
||||
|
||||
Assert.True(clear.ShouldRender);
|
||||
Assert.True(rain.ShouldRender);
|
||||
Assert.Equal(source.SurfaceToLightDirection, clear.SurfaceToLightDirection);
|
||||
Assert.Equal(clear.SurfaceToLightDirection, rain.SurfaceToLightDirection);
|
||||
Assert.Equal(AuthoredCelestialShadowSourceKind.DominantMoon, clear.SourceKind);
|
||||
Assert.Equal(clear.SourceKind, rain.SourceKind);
|
||||
Assert.Equal(source.ObjectIndex, rain.SourceObjectIndex);
|
||||
Assert.Equal(source.GfxObjId, rain.SourceGfxObjId);
|
||||
Assert.True(rain.Strength < clear.Strength);
|
||||
Assert.True(rain.SoftnessMultiplier > clear.SoftnessMultiplier);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ZeroDayGroupPolicy_DisablesThroughExplicitAtmosphereMapping()
|
||||
{
|
||||
DirectionalShadowEnvironmentInput input = new(
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
Celestial(AuthoredCelestialShadowSourceKind.Sun, 35f),
|
||||
Atmosphere(WeatherKind.Clear),
|
||||
ActiveDayGroupMultiplier: 0f);
|
||||
|
||||
DirectionalShadowEnvironmentState result =
|
||||
DirectionalShadowEnvironmentGate.Evaluate(
|
||||
in input,
|
||||
DirectionalShadowAtmospherePolicy.BuiltIn);
|
||||
|
||||
Assert.Equal(DirectionalShadowGateReason.AtmosphereSuppressed, result.Reason);
|
||||
Assert.False(result.ShouldRender);
|
||||
}
|
||||
|
||||
private static AuthoredCelestialShadowSource Celestial(
|
||||
AuthoredCelestialShadowSourceKind kind,
|
||||
float elevationDegrees,
|
||||
float energy = 1f)
|
||||
{
|
||||
float elevation = elevationDegrees * MathF.PI / 180f;
|
||||
const float heading = 120f * MathF.PI / 180f;
|
||||
float horizontal = MathF.Cos(elevation);
|
||||
Vector3 direction = new(
|
||||
horizontal * MathF.Cos(heading),
|
||||
horizontal * MathF.Sin(heading),
|
||||
MathF.Sin(elevation));
|
||||
uint gfxObjId = kind switch
|
||||
{
|
||||
AuthoredCelestialShadowSourceKind.Sun =>
|
||||
AuthoredCelestialShadowSourceResolver.SunGfxObjId,
|
||||
AuthoredCelestialShadowSourceKind.DominantMoon =>
|
||||
AuthoredCelestialShadowSourceResolver.DominantMoonGfxObjId,
|
||||
AuthoredCelestialShadowSourceKind.SecondaryMoon =>
|
||||
AuthoredCelestialShadowSourceResolver.SecondaryMoonGfxObjId,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(kind), kind, null),
|
||||
};
|
||||
return new AuthoredCelestialShadowSource(
|
||||
Kind: kind,
|
||||
ObjectIndex: 4,
|
||||
GfxObjId: gfxObjId,
|
||||
SurfaceToLightDirection: direction,
|
||||
ElevationSin: direction.Z,
|
||||
AuthoredEnergy: energy);
|
||||
}
|
||||
|
||||
private static AtmosphereSnapshot Atmosphere(WeatherKind weather) => new(
|
||||
weather,
|
||||
Intensity: 1f,
|
||||
FogColor: new Vector3(0.4f),
|
||||
FogStart: 80f,
|
||||
FogEnd: 350f,
|
||||
FogMode.Linear,
|
||||
LightningFlash: 0f,
|
||||
EnvironOverride.None);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue