Compare commits
5 Commits
e48393b856
...
ec9c20423d
Author | SHA1 | Date |
---|---|---|
|
ec9c20423d | |
|
f12e723056 | |
|
e93efb91f2 | |
|
13929e44a6 | |
|
54655254b9 |
|
@ -1,3 +1,4 @@
|
||||||
|
using System.Collections;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using KeepersCompound.LGS.Database.Chunks;
|
using KeepersCompound.LGS.Database.Chunks;
|
||||||
|
|
||||||
|
@ -12,9 +13,9 @@ public class PotentiallyVisibleSet
|
||||||
public readonly List<int> EdgeIndices = edgeIndices;
|
public readonly List<int> EdgeIndices = edgeIndices;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly struct Edge(int destination, Poly poly)
|
private readonly struct Edge(int mightSeeLength, int destination, Poly poly)
|
||||||
{
|
{
|
||||||
public readonly HashSet<int> MightSee = [];
|
public readonly BitArray MightSee = new(mightSeeLength);
|
||||||
public readonly int Destination = destination;
|
public readonly int Destination = destination;
|
||||||
public readonly Poly Poly = poly;
|
public readonly Poly Poly = poly;
|
||||||
|
|
||||||
|
@ -26,6 +27,8 @@ public class PotentiallyVisibleSet
|
||||||
|
|
||||||
private struct Poly
|
private struct Poly
|
||||||
{
|
{
|
||||||
|
public readonly Vector3 Center;
|
||||||
|
public readonly float Radius;
|
||||||
public List<Vector3> Vertices;
|
public List<Vector3> Vertices;
|
||||||
public readonly Plane Plane;
|
public readonly Plane Plane;
|
||||||
|
|
||||||
|
@ -33,6 +36,25 @@ public class PotentiallyVisibleSet
|
||||||
{
|
{
|
||||||
Vertices = vertices;
|
Vertices = vertices;
|
||||||
Plane = plane;
|
Plane = plane;
|
||||||
|
|
||||||
|
// Center is just taken to be the "average" of the vertices
|
||||||
|
Center = Vector3.Zero;
|
||||||
|
foreach (var v in vertices)
|
||||||
|
{
|
||||||
|
Center += v;
|
||||||
|
}
|
||||||
|
|
||||||
|
Center /= vertices.Count;
|
||||||
|
|
||||||
|
// Radius is the max vertex distance from the center
|
||||||
|
// We're actually calculating radius squared to begin with because it's faster :)
|
||||||
|
Radius = 0;
|
||||||
|
foreach (var v in vertices)
|
||||||
|
{
|
||||||
|
Radius = float.Max(Radius, (v - Center).LengthSquared());
|
||||||
|
}
|
||||||
|
|
||||||
|
Radius = MathF.Sqrt(Radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Poly(Poly other)
|
public Poly(Poly other)
|
||||||
|
@ -78,6 +100,12 @@ public class PotentiallyVisibleSet
|
||||||
_graph = new Node[cells.Length];
|
_graph = new Node[cells.Length];
|
||||||
_edges = [];
|
_edges = [];
|
||||||
|
|
||||||
|
var portalCount = 0;
|
||||||
|
foreach (var cell in cells)
|
||||||
|
{
|
||||||
|
portalCount += cell.PortalPolyCount;
|
||||||
|
}
|
||||||
|
|
||||||
for (var i = 0; i < cells.Length; i++)
|
for (var i = 0; i < cells.Length; i++)
|
||||||
{
|
{
|
||||||
var cell = cells[i];
|
var cell = cells[i];
|
||||||
|
@ -111,7 +139,7 @@ public class PotentiallyVisibleSet
|
||||||
vs.Add(cell.Vertices[cell.Indices[indicesOffset + vIdx]]);
|
vs.Add(cell.Vertices[cell.Indices[indicesOffset + vIdx]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
var edge = new Edge(poly.Destination, new Poly(vs, cell.Planes[poly.PlaneId]));
|
var edge = new Edge(portalCount, poly.Destination, new Poly(vs, cell.Planes[poly.PlaneId]));
|
||||||
edgeIndices.Add(_edges.Count);
|
edgeIndices.Add(_edges.Count);
|
||||||
_edges.Add(edge);
|
_edges.Add(edge);
|
||||||
indicesOffset += poly.VertexCount;
|
indicesOffset += poly.VertexCount;
|
||||||
|
@ -148,22 +176,32 @@ public class PotentiallyVisibleSet
|
||||||
while (unexploredCells.Count > 0)
|
while (unexploredCells.Count > 0)
|
||||||
{
|
{
|
||||||
var cellIdx = unexploredCells.Pop();
|
var cellIdx = unexploredCells.Pop();
|
||||||
|
if (source.MightSee[cellIdx])
|
||||||
if (!source.MightSee.Add(cellIdx))
|
|
||||||
{
|
{
|
||||||
continue; // target is already explored
|
continue; // target is already explored
|
||||||
}
|
}
|
||||||
|
|
||||||
|
source.MightSee[cellIdx] = true;
|
||||||
|
|
||||||
// Target must be partly behind source, source must be partly in front of target, and source and target cannot face each other
|
// Target must be partly behind source, source must be partly in front of target, and source and target cannot face each other
|
||||||
foreach (var targetEdgeIdx in _graph[cellIdx].EdgeIndices)
|
foreach (var targetEdgeIdx in _graph[cellIdx].EdgeIndices)
|
||||||
{
|
{
|
||||||
var target = _edges[targetEdgeIdx];
|
var target = _edges[targetEdgeIdx];
|
||||||
var targetPlane = target.Poly.Plane;
|
var targetPlane = target.Poly.Plane;
|
||||||
|
|
||||||
|
// If we're already visited the target, target is fully behind source, or source is fully behind target
|
||||||
|
// then we can quickly discard this portal
|
||||||
|
if (source.MightSee[target.Destination] ||
|
||||||
|
MathUtils.DistanceFromNormalizedPlane(sourcePlane, target.Poly.Center) > target.Poly.Radius ||
|
||||||
|
MathUtils.DistanceFromNormalizedPlane(targetPlane, source.Poly.Center) < -source.Poly.Radius)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
var validTarget = false;
|
var validTarget = false;
|
||||||
foreach (var v in target.Poly.Vertices)
|
foreach (var v in target.Poly.Vertices)
|
||||||
{
|
{
|
||||||
if (MathUtils.DistanceFromPlane(sourcePlane, v) < -MathUtils.Epsilon)
|
if (MathUtils.DistanceFromNormalizedPlane(sourcePlane, v) < -MathUtils.Epsilon)
|
||||||
{
|
{
|
||||||
validTarget = true;
|
validTarget = true;
|
||||||
break;
|
break;
|
||||||
|
@ -178,7 +216,7 @@ public class PotentiallyVisibleSet
|
||||||
validTarget = false;
|
validTarget = false;
|
||||||
foreach (var v in source.Poly.Vertices)
|
foreach (var v in source.Poly.Vertices)
|
||||||
{
|
{
|
||||||
if (MathUtils.DistanceFromPlane(targetPlane, v) > MathUtils.Epsilon)
|
if (MathUtils.DistanceFromNormalizedPlane(targetPlane, v) > MathUtils.Epsilon)
|
||||||
{
|
{
|
||||||
validTarget = true;
|
validTarget = true;
|
||||||
break;
|
break;
|
||||||
|
@ -212,9 +250,12 @@ public class PotentiallyVisibleSet
|
||||||
foreach (var edgeIdx in _graph[cellIdx].EdgeIndices)
|
foreach (var edgeIdx in _graph[cellIdx].EdgeIndices)
|
||||||
{
|
{
|
||||||
var edge = _edges[edgeIdx];
|
var edge = _edges[edgeIdx];
|
||||||
foreach (var mightSee in edge.MightSee)
|
for (var i = 0; i < edge.MightSee.Length; i++)
|
||||||
{
|
{
|
||||||
visible.Add(mightSee);
|
if (edge.MightSee[i])
|
||||||
|
{
|
||||||
|
visible.Add(i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -93,6 +93,11 @@ public static class MathUtils
|
||||||
return (Vector3.Dot(plane.Normal, point) + plane.D) / plane.Normal.Length();
|
return (Vector3.Dot(plane.Normal, point) + plane.D) / plane.Normal.Length();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static float DistanceFromNormalizedPlane(Plane plane, Vector3 point)
|
||||||
|
{
|
||||||
|
return Vector3.Dot(plane.Normal, point) + plane.D;
|
||||||
|
}
|
||||||
|
|
||||||
public static bool IsCoplanar(Plane p0, Plane p1)
|
public static bool IsCoplanar(Plane p0, Plane p1)
|
||||||
{
|
{
|
||||||
var m = p0.D / p1.D;
|
var m = p0.D / p1.D;
|
||||||
|
|
Loading…
Reference in New Issue