2024-10-27 15:10:28 +00:00
|
|
|
using System.Numerics;
|
|
|
|
using KeepersCompound.LGS.Database.Chunks;
|
|
|
|
|
|
|
|
namespace KeepersCompound.Lightmapper;
|
|
|
|
|
|
|
|
public class Light
|
|
|
|
{
|
2024-10-27 15:12:19 +00:00
|
|
|
public Vector3 Position;
|
|
|
|
public Vector3 Color;
|
2024-12-10 16:55:22 +00:00
|
|
|
public float Brightness;
|
2024-10-27 15:12:19 +00:00
|
|
|
public float InnerRadius;
|
|
|
|
public float Radius;
|
|
|
|
public float R2;
|
2024-10-28 18:59:32 +00:00
|
|
|
public bool QuadLit;
|
2024-10-27 15:10:28 +00:00
|
|
|
|
2024-10-27 15:12:19 +00:00
|
|
|
public bool Spotlight;
|
|
|
|
public Vector3 SpotlightDir;
|
|
|
|
public float SpotlightInnerAngle;
|
|
|
|
public float SpotlightOuterAngle;
|
2024-10-27 15:10:28 +00:00
|
|
|
|
2024-10-27 15:12:19 +00:00
|
|
|
public int ObjId;
|
|
|
|
public int LightTableIndex;
|
|
|
|
public bool Anim;
|
2024-10-27 15:10:28 +00:00
|
|
|
|
|
|
|
public WorldRep.LightTable.LightData ToLightData(float lightScale)
|
|
|
|
{
|
|
|
|
return new WorldRep.LightTable.LightData
|
|
|
|
{
|
2024-10-27 15:12:19 +00:00
|
|
|
Location = Position,
|
|
|
|
Direction = SpotlightDir,
|
|
|
|
Color = Color / lightScale,
|
|
|
|
InnerAngle = SpotlightInnerAngle,
|
|
|
|
OuterAngle = SpotlightOuterAngle,
|
|
|
|
Radius = Radius == float.MaxValue ? 0 : Radius,
|
2024-10-27 15:10:28 +00:00
|
|
|
};
|
|
|
|
}
|
2024-10-27 15:15:59 +00:00
|
|
|
|
2024-12-23 17:57:36 +00:00
|
|
|
public void FixRadius()
|
|
|
|
{
|
|
|
|
if (Radius == 0)
|
|
|
|
{
|
|
|
|
Radius = float.MaxValue;
|
|
|
|
R2 = float.MaxValue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void ApplyTransforms(
|
|
|
|
Vector3 vhotLightPos,
|
|
|
|
Vector3 vhotLightDir,
|
|
|
|
Matrix4x4 translate,
|
|
|
|
Matrix4x4 rotate,
|
|
|
|
Matrix4x4 scale)
|
|
|
|
{
|
2024-12-26 13:23:07 +00:00
|
|
|
Position = Vector3.Transform(Position, rotate) + Vector3.Transform(vhotLightPos, scale * rotate * translate);
|
|
|
|
SpotlightDir = Vector3.Normalize(Vector3.Transform(vhotLightDir, scale * rotate));
|
2024-12-23 17:57:36 +00:00
|
|
|
}
|
|
|
|
|
2024-10-27 15:15:59 +00:00
|
|
|
public float StrengthAtPoint(Vector3 point, Plane plane)
|
|
|
|
{
|
|
|
|
// Calculate light strength at a given point. As far as I can tell
|
|
|
|
// this is exact to Dark (I'm a genius??). It's just an inverse distance
|
|
|
|
// falloff with diffuse angle, except we have to scale the length.
|
|
|
|
var dir = Position - point;
|
|
|
|
var angle = Vector3.Dot(Vector3.Normalize(dir), plane.Normal);
|
|
|
|
var len = dir.Length();
|
|
|
|
var slen = len / 4.0f;
|
|
|
|
var strength = (angle + 1.0f) / slen;
|
|
|
|
|
|
|
|
// Inner radius starts a linear falloff to 0 at the radius
|
|
|
|
if (InnerRadius != 0 && len > InnerRadius)
|
|
|
|
{
|
|
|
|
strength *= (Radius - len) / (Radius - InnerRadius);
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is basically the same as how inner radius works. It just applies
|
|
|
|
// a linear falloff to 0 between the inner angle and outer angle.
|
|
|
|
if (Spotlight)
|
|
|
|
{
|
|
|
|
var spotAngle = Vector3.Dot(-Vector3.Normalize(dir), SpotlightDir);
|
|
|
|
var inner = SpotlightInnerAngle;
|
|
|
|
var outer = SpotlightOuterAngle;
|
|
|
|
|
|
|
|
// In an improperly configured spotlight inner and outer angles might be the
|
|
|
|
// same. So to avoid division by zero (and some clamping) we explicitly handle
|
|
|
|
// some cases
|
|
|
|
float spotlightMultiplier;
|
|
|
|
if (spotAngle >= inner)
|
|
|
|
{
|
|
|
|
spotlightMultiplier = 1.0f;
|
|
|
|
}
|
|
|
|
else if (spotAngle <= outer)
|
|
|
|
{
|
|
|
|
spotlightMultiplier = 0.0f;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
spotlightMultiplier = (spotAngle - outer) / (inner - outer);
|
|
|
|
}
|
|
|
|
|
|
|
|
strength *= spotlightMultiplier;
|
|
|
|
}
|
|
|
|
|
|
|
|
return strength;
|
|
|
|
}
|
2024-12-10 16:55:22 +00:00
|
|
|
|
|
|
|
public float CalculateMaxRadius(float minLightCutoff)
|
|
|
|
{
|
|
|
|
// TODO: Should it be ceiling'd? Do we need to care about hdr? (I don't think so)
|
|
|
|
var radius = 8 * Brightness / minLightCutoff;
|
|
|
|
return radius;
|
|
|
|
|
|
|
|
// 2 / (x / 4.0f) = minLightCutoff;
|
|
|
|
// 2 / minLightCutOff = x / 4.0f;
|
|
|
|
// x = 8 * rgb / minLightCutOff;
|
|
|
|
}
|
2024-10-27 15:10:28 +00:00
|
|
|
}
|