Refactor tracing to separate ray points
This commit is contained in:
parent
9daaa3b73b
commit
27f8dab8fe
|
@ -1,3 +1,4 @@
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using KeepersCompound.LGS;
|
using KeepersCompound.LGS;
|
||||||
using KeepersCompound.LGS.Database;
|
using KeepersCompound.LGS.Database;
|
||||||
|
@ -430,10 +431,31 @@ 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;
|
||||||
|
|
||||||
if (TracePixelMultisampled(
|
var softnessMode = light.QuadLit ? SoftnessMode.HighFourPoint : settings.MultiSampling;
|
||||||
settings.MultiSampling, light, pos, renderPoly.Center, plane, planeMapper, v2ds,
|
var (texU, texV) = renderPoly.TextureVectors;
|
||||||
renderPoly.TextureVectors.Item1, renderPoly.TextureVectors.Item2,
|
var (offsets, weights) = GetTraceOffsetsAndWeights(softnessMode, texU, texV,settings.MultiSamplingCenterWeight);
|
||||||
settings.MultiSamplingCenterWeight, out var strength))
|
var tracePoints = GetTracePoints(pos, offsets, renderPoly.Center, planeMapper, v2ds);
|
||||||
|
|
||||||
|
var strength = 0f;
|
||||||
|
for (var idx = 0; idx < tracePoints.Length; idx++)
|
||||||
|
{
|
||||||
|
var point = tracePoints[idx];
|
||||||
|
|
||||||
|
// If we're out of range there's no point casting a ray
|
||||||
|
// There's probably a better way to discard the entire lightmap
|
||||||
|
// if we're massively out of range
|
||||||
|
if ((point - light.Position).LengthSquared() > light.R2)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TraceRay(light.Position, point))
|
||||||
|
{
|
||||||
|
strength += weights[idx] * light.StrengthAtPoint(point, plane);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strength != 0f)
|
||||||
{
|
{
|
||||||
// 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
|
||||||
|
@ -463,126 +485,85 @@ public class LightMapper
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TracePixelMultisampled(
|
private static (Vector3[], float[]) GetTraceOffsetsAndWeights(
|
||||||
SoftnessMode mode,
|
SoftnessMode mode,
|
||||||
Light light,
|
|
||||||
Vector3 pos,
|
|
||||||
Vector3 polyCenter,
|
|
||||||
Plane plane,
|
|
||||||
MathUtils.PlanePointMapper planeMapper,
|
|
||||||
Vector2[] v2ds,
|
|
||||||
Vector3 texU,
|
Vector3 texU,
|
||||||
Vector3 texV,
|
Vector3 texV,
|
||||||
float centerWeight,
|
float centerWeight)
|
||||||
out float strength)
|
|
||||||
{
|
{
|
||||||
bool FourPoint(float offsetScale, out float strength)
|
var offsetScale = mode switch
|
||||||
{
|
{
|
||||||
var hit = false;
|
SoftnessMode.HighFourPoint or SoftnessMode.HighFivePoint or SoftnessMode.HighNinePoint => 4f,
|
||||||
var xOffset = texU / offsetScale;
|
SoftnessMode.MediumFourPoint or SoftnessMode.MediumFivePoint or SoftnessMode.MediumNinePoint => 8f,
|
||||||
var yOffset = texV / offsetScale;
|
SoftnessMode.LowFourPoint => 16f,
|
||||||
hit |= TracePixel(light, pos - xOffset - yOffset, polyCenter, plane, planeMapper, v2ds, out var strength1);
|
_ => 1f,
|
||||||
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 cw = centerWeight;
|
||||||
|
var w = 1f - cw;
|
||||||
|
texU /= offsetScale;
|
||||||
|
texV /= offsetScale;
|
||||||
|
|
||||||
|
return mode switch
|
||||||
{
|
{
|
||||||
var hit = false;
|
SoftnessMode.LowFourPoint or SoftnessMode.MediumFourPoint or SoftnessMode.HighFourPoint => (
|
||||||
hit |= TracePixel(light, pos, polyCenter, plane, planeMapper, v2ds, out var centerStrength);
|
[-texU - texV, -texU - texV, -texU + texV, texU + texV],
|
||||||
hit |= FourPoint(offsetScale, out strength);
|
[0.25f, 0.25f, 0.25f, 0.25f]),
|
||||||
strength = (1.0f - centerWeight) * strength + centerWeight * centerStrength;
|
SoftnessMode.MediumFivePoint or SoftnessMode.HighFivePoint => (
|
||||||
return hit;
|
[Vector3.Zero, -texU - texV, texU - texV, -texU + texV, texU + texV],
|
||||||
}
|
[cw, w * 0.25f, w * 0.25f, w * 0.25f, w * 0.25f]),
|
||||||
|
SoftnessMode.MediumNinePoint or SoftnessMode.HighNinePoint => (
|
||||||
bool NinePoint(float offsetScale, out float strength)
|
[Vector3.Zero, -texU - texV, texU - texV, -texU + texV, texU + texV, -texU, texU, -texV, texV],
|
||||||
{
|
[cw, w * 0.125f, w * 0.125f, w * 0.125f, w * 0.125f, w * 0.125f, w * 0.125f, w * 0.125f, w * 0.125f]),
|
||||||
var hit = false;
|
_ => (
|
||||||
var xOffset = texU / offsetScale;
|
[Vector3.Zero],
|
||||||
var yOffset = texV / offsetScale;
|
[1f]),
|
||||||
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 Vector3[] GetTracePoints(
|
||||||
Light light,
|
Vector3 basePosition,
|
||||||
Vector3 pos,
|
Vector3[] offsets,
|
||||||
Vector3 polyCenter,
|
Vector3 polyCenter,
|
||||||
Plane plane,
|
|
||||||
MathUtils.PlanePointMapper planeMapper,
|
MathUtils.PlanePointMapper planeMapper,
|
||||||
Vector2[] v2ds,
|
Vector2[] v2ds)
|
||||||
out float strength)
|
|
||||||
{
|
{
|
||||||
strength = 0f;
|
var tracePoints = new Vector3[offsets.Length];
|
||||||
|
for (var i = 0; i < offsets.Length; i++)
|
||||||
// Embree has robustness issues when hitting poly edges which
|
|
||||||
// results in false misses. To alleviate this we pre-push everything
|
|
||||||
// slightly towards the center of the poly.
|
|
||||||
var centerOffset = polyCenter - pos;
|
|
||||||
if (centerOffset.LengthSquared() > MathUtils.Epsilon)
|
|
||||||
{
|
{
|
||||||
pos += Vector3.Normalize(centerOffset) * MathUtils.Epsilon;
|
var offset = offsets[i];
|
||||||
|
var pos = basePosition + offset;
|
||||||
|
|
||||||
|
// Embree has robustness issues when hitting poly edges which
|
||||||
|
// results in false misses. To alleviate this we pre-push everything
|
||||||
|
// slightly towards the center of the poly.
|
||||||
|
var centerOffset = polyCenter - pos;
|
||||||
|
if (centerOffset.LengthSquared() > MathUtils.Epsilon)
|
||||||
|
{
|
||||||
|
pos += Vector3.Normalize(centerOffset) * MathUtils.Epsilon;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we can't see our target point from the center of the poly
|
||||||
|
// then it's outside the world. We need to clip the point to slightly
|
||||||
|
// inside the poly and retrace to avoid three problems:
|
||||||
|
// 1. Darkened spots from lightmap pixels whose center is outside
|
||||||
|
// the polygon but is partially contained in the polygon
|
||||||
|
// 2. Darkened spots from linear filtering of points outside the
|
||||||
|
// polygon which have missed
|
||||||
|
// 3. Darkened spots where centers are on the exact edge of a poly
|
||||||
|
// which can sometimes cause Embree to miss casts
|
||||||
|
var inPoly = TraceRay(polyCenter + planeMapper.Normal * 0.25f, pos);
|
||||||
|
if (!inPoly)
|
||||||
|
{
|
||||||
|
var p2d = planeMapper.MapTo2d(pos);
|
||||||
|
p2d = MathUtils.ClipPointToPoly2d(p2d, v2ds);
|
||||||
|
pos = planeMapper.MapTo3d(p2d);
|
||||||
|
}
|
||||||
|
|
||||||
|
tracePoints[i] = pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we can't see our target point from the center of the poly
|
return tracePoints;
|
||||||
// then it's outside the world. We need to clip the point to slightly
|
|
||||||
// inside the poly and retrace to avoid three problems:
|
|
||||||
// 1. Darkened spots from lightmap pixels whose center is outside
|
|
||||||
// the polygon but is partially contained in the polygon
|
|
||||||
// 2. Darkened spots from linear filtering of points outside the
|
|
||||||
// polygon which have missed
|
|
||||||
// 3. Darkened spots where centers are on the exact edge of a poly
|
|
||||||
// which can sometimes cause Embree to miss casts
|
|
||||||
var inPoly = TraceRay(polyCenter + plane.Normal * 0.25f, pos);
|
|
||||||
if (!inPoly)
|
|
||||||
{
|
|
||||||
var p2d = planeMapper.MapTo2d(pos);
|
|
||||||
p2d = MathUtils.ClipPointToPoly2d(p2d, v2ds);
|
|
||||||
pos = planeMapper.MapTo3d(p2d);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we're out of range there's no point casting a ray
|
|
||||||
// There's probably a better way to discard the entire lightmap
|
|
||||||
// if we're massively out of range
|
|
||||||
if ((pos - light.Position).LengthSquared() > light.R2)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We cast from the light to the pixel because the light has
|
|
||||||
// no mesh in the scene to hit
|
|
||||||
var hit = TraceRay(light.Position, pos);
|
|
||||||
if (hit)
|
|
||||||
{
|
|
||||||
strength += light.StrengthAtPoint(pos, plane);
|
|
||||||
}
|
|
||||||
return hit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool TraceRay(Vector3 origin, Vector3 target)
|
private bool TraceRay(Vector3 origin, Vector3 target)
|
||||||
|
|
|
@ -90,12 +90,14 @@ public static class MathUtils
|
||||||
|
|
||||||
public record PlanePointMapper
|
public record PlanePointMapper
|
||||||
{
|
{
|
||||||
|
public Vector3 Normal { get; }
|
||||||
Vector3 _origin;
|
Vector3 _origin;
|
||||||
Vector3 _xAxis;
|
Vector3 _xAxis;
|
||||||
Vector3 _yAxis;
|
Vector3 _yAxis;
|
||||||
|
|
||||||
public PlanePointMapper(Vector3 normal, Vector3 p0, Vector3 p1)
|
public PlanePointMapper(Vector3 normal, Vector3 p0, Vector3 p1)
|
||||||
{
|
{
|
||||||
|
Normal = normal;
|
||||||
_origin = p0;
|
_origin = p0;
|
||||||
_xAxis = p1 - _origin;
|
_xAxis = p1 - _origin;
|
||||||
_yAxis = Vector3.Cross(normal, _xAxis);
|
_yAxis = Vector3.Cross(normal, _xAxis);
|
||||||
|
|
Loading…
Reference in New Issue