Add sunlight casting

This commit is contained in:
Jarrod Doyle 2024-12-09 14:35:53 +00:00
parent 596ce88215
commit b34131f3b5
Signed by: Jayrude
GPG Key ID: 38B57B16E7C0ADF7
1 changed files with 72 additions and 1 deletions

View File

@ -8,13 +8,23 @@ namespace KeepersCompound.Lightmapper;
public class LightMapper
{
private class Settings
// The objcast element of sunlight is ignored, we just care if it's quadlit
private struct SunSettings
{
public bool Enabled;
public bool QuadLit;
public Vector3 Direction;
public Vector3 Color;
}
private struct Settings
{
public Vector3 AmbientLight;
public bool Hdr;
public SoftnessMode MultiSampling;
public float MultiSamplingCenterWeight;
public bool LightmappedWater;
public SunSettings Sunlight;
}
private ResourcePathManager.CampaignResources _campaign;
@ -58,6 +68,14 @@ public class LightMapper
return;
}
var sunlightSettings = new SunSettings()
{
Enabled = rendParams.useSunlight,
QuadLit = rendParams.sunlightMode is RendParams.SunlightMode.QuadUnshadowed or RendParams.SunlightMode.QuadObjcastShadows,
Direction = rendParams.sunlightDirection,
Color = Utils.HsbToRgb(rendParams.sunlightHue, rendParams.sunlightSaturation, rendParams.sunlightBrightness),
};
// TODO: lmParams LightmappedWater doesn't mean the game will actually *use* the lightmapped water hmm
var settings = new Settings
{
@ -66,6 +84,7 @@ public class LightMapper
MultiSampling = lmParams.ShadowSoftness,
MultiSamplingCenterWeight = lmParams.CenterWeight,
LightmappedWater = lmParams.LightmappedWater,
Sunlight = sunlightSettings,
};
Timing.TimeStage("Gather Lights", BuildLightList);
@ -414,6 +433,36 @@ public class LightMapper
var quadTracePoints = settings.MultiSampling == SoftnessMode.HighFourPoint
? tracePoints
: GetTracePoints(pos, quadOffsets, renderPoly.Center, planeMapper, v2ds);
// TODO: This isn't quite right yet. It seems to be too bright
if (settings.Sunlight.Enabled) {
// Check if plane normal is facing towards the light
// If it's not then we're never going to be (directly) lit by this
// light.
var sunAngle = Vector3.Dot(-settings.Sunlight.Direction, plane.Normal);
if (sunAngle > 0)
{
var strength = 0f;
var targetPoints = settings.Sunlight.QuadLit ? quadTracePoints : tracePoints;
var targetWeights = settings.Sunlight.QuadLit ? quadWeights : weights;
for (var idx = 0; idx < targetPoints.Length; idx++)
{
var point = targetPoints[idx];
if (TraceSunRay(point, -settings.Sunlight.Direction))
{
// Sunlight is a simpler lighting algorithm than normal lights so we can just
// do it here
strength += targetWeights[idx] * sunAngle;
}
}
if (strength != 0f)
{
lightmap.AddLight(0, x, y, settings.Sunlight.Color, strength, settings.Hdr);
}
}
}
foreach (var light in _lights)
{
var layer = 0;
@ -596,6 +645,28 @@ public class LightMapper
return Math.Abs(hitDistanceFromTarget) < MathUtils.Epsilon;
}
// TODO: Can this be merged with the above?
private bool TraceSunRay(Vector3 origin, Vector3 direction)
{
// Avoid self intersection
origin += direction * MathUtils.Epsilon;
var hitSurfaceType = SurfaceType.Water;
while (hitSurfaceType == SurfaceType.Water)
{
var hitResult = _scene.Trace(new Ray
{
Origin = origin,
Direction = Vector3.Normalize(direction),
});
hitSurfaceType = _triangleTypeMap[(int)hitResult.PrimId];
origin = hitResult.Position += direction * MathUtils.Epsilon;
}
return hitSurfaceType == SurfaceType.Sky;
}
private void SetAnimLightCellMaps()
{
if (!_mission.TryGetChunk<PropertyChunk<PropAnimLight>>("P$AnimLight", out var animLightChunk) ||