Compare commits
4 Commits
ca017e3f7b
...
fe100bb938
Author | SHA1 | Date |
---|---|---|
Jarrod Doyle | fe100bb938 | |
Jarrod Doyle | f6bcce9778 | |
Jarrod Doyle | 99697180cd | |
Jarrod Doyle | ff91ad567b |
|
@ -0,0 +1,73 @@
|
||||||
|
namespace KeepersCompound.LGS.Database.Chunks;
|
||||||
|
|
||||||
|
public enum SoftnessMode
|
||||||
|
{
|
||||||
|
Standard,
|
||||||
|
HighFourPoint,
|
||||||
|
HighFivePoint,
|
||||||
|
HighNinePoint,
|
||||||
|
MediumFourPoint,
|
||||||
|
MediumFivePoint,
|
||||||
|
MediumNinePoint,
|
||||||
|
LowFourPoint,
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LmParams : IChunk
|
||||||
|
{
|
||||||
|
public enum LightingMode
|
||||||
|
{
|
||||||
|
Quick,
|
||||||
|
Raycast,
|
||||||
|
Objcast,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum DepthMode
|
||||||
|
{
|
||||||
|
Lm16,
|
||||||
|
Lm32,
|
||||||
|
Lm32x,
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChunkHeader Header { get; set; }
|
||||||
|
public float Attenuation { get; set; }
|
||||||
|
public float Saturation { get; set; }
|
||||||
|
public LightingMode ShadowType { get; set; }
|
||||||
|
public SoftnessMode ShadowSoftness { get; set; }
|
||||||
|
public float CenterWeight { get; set; }
|
||||||
|
public DepthMode ShadowDepth { get; set; }
|
||||||
|
public bool LightmappedWater { get; set; }
|
||||||
|
public int LightmapScale { get; set; }
|
||||||
|
|
||||||
|
private int _dataSize;
|
||||||
|
private uint _unknown;
|
||||||
|
|
||||||
|
public void ReadData(BinaryReader reader, DbFile.TableOfContents.Entry entry)
|
||||||
|
{
|
||||||
|
_dataSize = reader.ReadInt32();
|
||||||
|
Attenuation = reader.ReadSingle();
|
||||||
|
Saturation = reader.ReadSingle();
|
||||||
|
ShadowType = (LightingMode)reader.ReadUInt32();
|
||||||
|
ShadowSoftness = (SoftnessMode)reader.ReadUInt32();
|
||||||
|
CenterWeight = reader.ReadSingle();
|
||||||
|
ShadowDepth = (DepthMode)reader.ReadUInt32();
|
||||||
|
LightmappedWater = reader.ReadBoolean();
|
||||||
|
reader.ReadBytes(3);
|
||||||
|
LightmapScale = reader.ReadInt32();
|
||||||
|
_unknown = reader.ReadUInt32();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteData(BinaryWriter writer)
|
||||||
|
{
|
||||||
|
writer.Write(_dataSize);
|
||||||
|
writer.Write(Attenuation);
|
||||||
|
writer.Write(Saturation);
|
||||||
|
writer.Write((uint)ShadowType);
|
||||||
|
writer.Write((uint)ShadowSoftness);
|
||||||
|
writer.Write(CenterWeight);
|
||||||
|
writer.Write((uint)ShadowDepth);
|
||||||
|
writer.Write(LightmappedWater);
|
||||||
|
writer.Write(new byte[3]);
|
||||||
|
writer.Write(LightmapScale);
|
||||||
|
writer.Write(_unknown);
|
||||||
|
}
|
||||||
|
}
|
|
@ -150,6 +150,7 @@ public class DbFile
|
||||||
"TXLIST" => new TxList(),
|
"TXLIST" => new TxList(),
|
||||||
"WREXT" => new WorldRep(),
|
"WREXT" => new WorldRep(),
|
||||||
"BRLIST" => new BrList(),
|
"BRLIST" => new BrList(),
|
||||||
|
"LM_PARAM" => new LmParams(),
|
||||||
"RENDPARAMS" => new RendParams(),
|
"RENDPARAMS" => new RendParams(),
|
||||||
"P$ModelName" => new PropertyChunk<PropLabel>(),
|
"P$ModelName" => new PropertyChunk<PropLabel>(),
|
||||||
"P$Scale" => new PropertyChunk<PropVector>(),
|
"P$Scale" => new PropertyChunk<PropVector>(),
|
||||||
|
|
|
@ -10,9 +10,10 @@ public class LightMapper
|
||||||
{
|
{
|
||||||
private class Settings
|
private class Settings
|
||||||
{
|
{
|
||||||
public bool Hdr;
|
|
||||||
public bool MultiSampling;
|
|
||||||
public Vector3 AmbientLight;
|
public Vector3 AmbientLight;
|
||||||
|
public bool Hdr;
|
||||||
|
public SoftnessMode MultiSampling;
|
||||||
|
public float MultiSamplingCenterWeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ResourcePathManager.CampaignResources _campaign;
|
private ResourcePathManager.CampaignResources _campaign;
|
||||||
|
@ -36,10 +37,11 @@ public class LightMapper
|
||||||
_lights = [];
|
_lights = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Light(bool multiSampling)
|
public void Light()
|
||||||
{
|
{
|
||||||
// TODO: Throw?
|
// TODO: Throw?
|
||||||
if (!_mission.TryGetChunk<RendParams>("RENDPARAMS", out var rendParams) ||
|
if (!_mission.TryGetChunk<RendParams>("RENDPARAMS", out var rendParams) ||
|
||||||
|
!_mission.TryGetChunk<LmParams>("LM_PARAM", out var lmParams) ||
|
||||||
!_mission.TryGetChunk<WorldRep>("WREXT", out var worldRep))
|
!_mission.TryGetChunk<WorldRep>("WREXT", out var worldRep))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -49,13 +51,16 @@ public class LightMapper
|
||||||
{
|
{
|
||||||
Hdr = worldRep.DataHeader.LightmapFormat == 2,
|
Hdr = worldRep.DataHeader.LightmapFormat == 2,
|
||||||
AmbientLight = rendParams.ambientLight * 255,
|
AmbientLight = rendParams.ambientLight * 255,
|
||||||
MultiSampling = multiSampling,
|
MultiSampling = lmParams.ShadowSoftness,
|
||||||
|
MultiSamplingCenterWeight = lmParams.CenterWeight,
|
||||||
};
|
};
|
||||||
|
|
||||||
Timing.TimeStage("Gather Lights", BuildLightList);
|
Timing.TimeStage("Gather Lights", BuildLightList);
|
||||||
Timing.TimeStage("Set Light Indices", SetCellLightIndices);
|
Timing.TimeStage("Set Light Indices", SetCellLightIndices);
|
||||||
Timing.TimeStage("Trace Scene", () => TraceScene(settings));
|
Timing.TimeStage("Trace Scene", () => TraceScene(settings));
|
||||||
Timing.TimeStage("Update AnimLight Cell Mapping", SetAnimLightCellMaps);
|
Timing.TimeStage("Update AnimLight Cell Mapping", SetAnimLightCellMaps);
|
||||||
|
|
||||||
|
// lmParams.ShadowType = LmParams.LightingMode.Raycast;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Save(string missionName)
|
public void Save(string missionName)
|
||||||
|
@ -436,25 +441,10 @@ public class LightMapper
|
||||||
pos += x * 0.25f * renderPoly.TextureVectors.Item1;
|
pos += x * 0.25f * renderPoly.TextureVectors.Item1;
|
||||||
pos += y * 0.25f * renderPoly.TextureVectors.Item2;
|
pos += y * 0.25f * renderPoly.TextureVectors.Item2;
|
||||||
|
|
||||||
var hit = false;
|
if (TracePixelMultisampled(
|
||||||
var strength = 0f;
|
settings.MultiSampling, light, pos, renderPoly.Center, plane, planeMapper, v2ds,
|
||||||
|
renderPoly.TextureVectors.Item1, renderPoly.TextureVectors.Item2,
|
||||||
if (settings.MultiSampling)
|
settings.MultiSamplingCenterWeight, out var strength))
|
||||||
{
|
|
||||||
var xOffset = 0.25f * 0.25f * renderPoly.TextureVectors.Item1;
|
|
||||||
var yOffset = 0.25f * 0.25f * renderPoly.TextureVectors.Item2;
|
|
||||||
hit |= TracePixel(light, pos - xOffset - yOffset, renderPoly.Center, plane, planeMapper, v2ds, ref strength);
|
|
||||||
hit |= TracePixel(light, pos + xOffset - yOffset, renderPoly.Center, plane, planeMapper, v2ds, ref strength);
|
|
||||||
hit |= TracePixel(light, pos - xOffset + yOffset, renderPoly.Center, plane, planeMapper, v2ds, ref strength);
|
|
||||||
hit |= TracePixel(light, pos + xOffset + yOffset, renderPoly.Center, plane, planeMapper, v2ds, ref strength);
|
|
||||||
strength /= 4f;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
hit |= TracePixel(light, pos, renderPoly.Center, plane, planeMapper, v2ds, ref strength);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hit)
|
|
||||||
{
|
{
|
||||||
// If we're an anim light there's a lot of stuff we need to update
|
// If we're an anim light there's a lot of stuff we need to update
|
||||||
// Firstly we need to add the light to the cells anim light palette
|
// Firstly we need to add the light to the cells anim light palette
|
||||||
|
@ -484,6 +474,73 @@ public class LightMapper
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool TracePixelMultisampled(
|
||||||
|
SoftnessMode mode,
|
||||||
|
Light light,
|
||||||
|
Vector3 pos,
|
||||||
|
Vector3 polyCenter,
|
||||||
|
Plane plane,
|
||||||
|
MathUtils.PlanePointMapper planeMapper,
|
||||||
|
Vector2[] v2ds,
|
||||||
|
Vector3 texU,
|
||||||
|
Vector3 texV,
|
||||||
|
float centerWeight,
|
||||||
|
out float strength)
|
||||||
|
{
|
||||||
|
bool FourPoint(float offsetScale, out float strength)
|
||||||
|
{
|
||||||
|
var hit = false;
|
||||||
|
var xOffset = texU / offsetScale;
|
||||||
|
var yOffset = texV / offsetScale;
|
||||||
|
hit |= TracePixel(light, pos - xOffset - yOffset, polyCenter, plane, planeMapper, v2ds, out var strength1);
|
||||||
|
hit |= TracePixel(light, pos + xOffset - yOffset, polyCenter, plane, planeMapper, v2ds, out var strength2);
|
||||||
|
hit |= TracePixel(light, pos - xOffset + yOffset, polyCenter, plane, planeMapper, v2ds, out var strength3);
|
||||||
|
hit |= TracePixel(light, pos + xOffset + yOffset, polyCenter, plane, planeMapper, v2ds, out var strength4);
|
||||||
|
strength = (strength1 + strength2 + strength3 + strength4) / 4f;
|
||||||
|
return hit;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FivePoint(float offsetScale, out float strength)
|
||||||
|
{
|
||||||
|
var hit = false;
|
||||||
|
hit |= TracePixel(light, pos, polyCenter, plane, planeMapper, v2ds, out var centerStrength);
|
||||||
|
hit |= FourPoint(offsetScale, out strength);
|
||||||
|
strength = (1.0f - centerWeight) * strength + centerWeight * centerStrength;
|
||||||
|
return hit;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NinePoint(float offsetScale, out float strength)
|
||||||
|
{
|
||||||
|
var hit = false;
|
||||||
|
var xOffset = texU / offsetScale;
|
||||||
|
var yOffset = texV / offsetScale;
|
||||||
|
hit |= TracePixel(light, pos - xOffset - yOffset, polyCenter, plane, planeMapper, v2ds, out var s1);
|
||||||
|
hit |= TracePixel(light, pos + xOffset - yOffset, polyCenter, plane, planeMapper, v2ds, out var s2);
|
||||||
|
hit |= TracePixel(light, pos - xOffset + yOffset, polyCenter, plane, planeMapper, v2ds, out var s3);
|
||||||
|
hit |= TracePixel(light, pos + xOffset + yOffset, polyCenter, plane, planeMapper, v2ds, out var s4);
|
||||||
|
hit |= TracePixel(light, pos - xOffset, polyCenter, plane, planeMapper, v2ds, out var s5);
|
||||||
|
hit |= TracePixel(light, pos + xOffset, polyCenter, plane, planeMapper, v2ds, out var s6);
|
||||||
|
hit |= TracePixel(light, pos - yOffset, polyCenter, plane, planeMapper, v2ds, out var s7);
|
||||||
|
hit |= TracePixel(light, pos + yOffset, polyCenter, plane, planeMapper, v2ds, out var s8);
|
||||||
|
hit |= TracePixel(light, pos, polyCenter, plane, planeMapper, v2ds, out var centerStrength);
|
||||||
|
strength = (s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8) / 8f;
|
||||||
|
strength = (1.0f - centerWeight) * strength + centerWeight * centerStrength;
|
||||||
|
return hit;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mode switch {
|
||||||
|
SoftnessMode.Standard when light.QuadLit => FourPoint(4f, out strength),
|
||||||
|
SoftnessMode.HighFourPoint => FourPoint(4f, out strength),
|
||||||
|
SoftnessMode.HighFivePoint => FivePoint(4f, out strength),
|
||||||
|
SoftnessMode.HighNinePoint => NinePoint(4f, out strength),
|
||||||
|
SoftnessMode.MediumFourPoint => FourPoint(8f, out strength),
|
||||||
|
SoftnessMode.MediumFivePoint => FivePoint(8f, out strength),
|
||||||
|
SoftnessMode.MediumNinePoint => NinePoint(8f, out strength),
|
||||||
|
SoftnessMode.LowFourPoint => FourPoint(16f, out strength),
|
||||||
|
_ => TracePixel(light, pos, polyCenter, plane, planeMapper, v2ds, out strength)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private bool TracePixel(
|
private bool TracePixel(
|
||||||
Light light,
|
Light light,
|
||||||
Vector3 pos,
|
Vector3 pos,
|
||||||
|
@ -491,8 +548,10 @@ public class LightMapper
|
||||||
Plane plane,
|
Plane plane,
|
||||||
MathUtils.PlanePointMapper planeMapper,
|
MathUtils.PlanePointMapper planeMapper,
|
||||||
Vector2[] v2ds,
|
Vector2[] v2ds,
|
||||||
ref float strength)
|
out float strength)
|
||||||
{
|
{
|
||||||
|
strength = 0f;
|
||||||
|
|
||||||
// Embree has robustness issues when hitting poly edges which
|
// Embree has robustness issues when hitting poly edges which
|
||||||
// results in false misses. To alleviate this we pre-push everything
|
// results in false misses. To alleviate this we pre-push everything
|
||||||
// slightly towards the center of the poly.
|
// slightly towards the center of the poly.
|
||||||
|
|
|
@ -21,15 +21,13 @@ public class LightCommand : ICommand
|
||||||
public required string MissionName { get; init; }
|
public required string MissionName { get; init; }
|
||||||
[CommandOption("output", 'o', Description = "Name of output file excluding extension.")]
|
[CommandOption("output", 'o', Description = "Name of output file excluding extension.")]
|
||||||
public string OutputName { get; init; } = "kc_lit";
|
public string OutputName { get; init; } = "kc_lit";
|
||||||
[CommandOption("multiSampling", 'm', Description = "Enables multi-sampled shadows. Higher quality but slower.")]
|
|
||||||
public bool MultiSampling { get; init; } = false;
|
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
Timing.Reset();
|
Timing.Reset();
|
||||||
|
|
||||||
var lightMapper = new LightMapper(InstallPath, CampaignName, MissionName);
|
var lightMapper = new LightMapper(InstallPath, CampaignName, MissionName);
|
||||||
lightMapper.Light(MultiSampling);
|
lightMapper.Light();
|
||||||
lightMapper.Save(OutputName);
|
lightMapper.Save(OutputName);
|
||||||
|
|
||||||
Timing.LogAll();
|
Timing.LogAll();
|
||||||
|
|
Loading…
Reference in New Issue