Change entity culling to use boxes instead of spheres

This commit is contained in:
dexy 2019-12-06 22:36:11 +11:00
parent faf530c04c
commit 52f4563680
4 changed files with 159 additions and 34 deletions

View File

@ -1279,6 +1279,8 @@ namespace CodeWalker.GameFiles
public Archetype Archetype { get; set; } //cached by GameFileCache on loading...
public Vector3 BBMin;//oriented archetype AABBmin
public Vector3 BBMax;//oriented archetype AABBmax
public Vector3 BBCenter; //oriented archetype AABB center
public Vector3 BBExtent; //oriented archetype AABB extent
public Vector3 BSCenter; //oriented archetype BS center
public float BSRadius;//cached from archetype
@ -1377,20 +1379,7 @@ namespace CodeWalker.GameFiles
Archetype = arch;
if (Archetype != null)
{
float smax = Math.Max(Scale.X, Scale.Z);
BSRadius = Archetype.BSRadius * smax;
BSCenter = Orientation.Multiply(Archetype.BSCenter) * Scale;
if (Orientation == Quaternion.Identity)
{
BBMin = (Archetype.BBMin * Scale) + Position;
BBMax = (Archetype.BBMax * Scale) + Position;
}
else
{
BBMin = Position - BSRadius;
BBMax = Position + BSRadius;
////not ideal: should transform all 8 corners!
}
UpdateBB();
if (Archetype.Type == MetaName.CMloArchetypeDef)
{
@ -1415,6 +1404,13 @@ namespace CodeWalker.GameFiles
{
BSRadius = _CEntityDef.lodDist;//need something so it doesn't get culled...
}
if (BBMin == BBMax)
{
BBMin = Position - BSRadius;
BBMax = Position + BSRadius;//it's not ideal
BBCenter = (BBMax + BBMin) * 0.5f;
BBExtent = (BBMax - BBMin) * 0.5f;
}
}
else if (IsMlo) // archetype is no longer an mlo
{
@ -1465,17 +1461,32 @@ namespace CodeWalker.GameFiles
if (Archetype != null)
{
BSCenter = Orientation.Multiply(Archetype.BSCenter) * Scale;
}
if ((Archetype != null) && (Orientation == Quaternion.Identity))
{
BBMin = (Archetype.BBMin * Scale) + Position;
BBMax = (Archetype.BBMax * Scale) + Position;
}
else
{
BBMin = Position - (BSRadius);
BBMax = Position + (BSRadius);
////not ideal: should transform all 8 corners!
BSRadius = Archetype.BSRadius * Math.Max(Scale.X, Scale.Z);
if (Orientation == Quaternion.Identity)
{
BBMin = (Archetype.BBMin * Scale) + Position;
BBMax = (Archetype.BBMax * Scale) + Position;
BBCenter = (BBMax + BBMin) * 0.5f;
BBExtent = (BBMax - BBMin) * 0.5f;
BBExtent = BBExtent.Abs();
}
else
{
var mat = Matrix.Transformation(Vector3.Zero, Quaternion.Identity, Scale, Vector3.Zero, Orientation, Position);
var matabs = mat;
matabs.Column1 = mat.Column1.Abs();
matabs.Column2 = mat.Column2.Abs();
matabs.Column3 = mat.Column3.Abs();
matabs.Column4 = mat.Column4.Abs();
var bbcenter = (Archetype.BBMax + Archetype.BBMin) * 0.5f;
var bbextent = (Archetype.BBMax - Archetype.BBMin) * 0.5f;
var ncenter = Vector3.TransformCoordinate(bbcenter, mat);
var nextent = Vector3.TransformNormal(bbextent, matabs);
BBCenter = ncenter;
BBExtent = nextent;
BBMin = ncenter - nextent;
BBMax = ncenter + nextent;
}
}
}
@ -1533,11 +1544,7 @@ namespace CodeWalker.GameFiles
MloInstance.UpdateEntities();
}
if (Archetype != null)
{
BSCenter = Orientation.Multiply(Archetype.BSCenter) * Scale;
}
UpdateBB();
UpdateWidgetPosition();
UpdateWidgetOrientation();
}

View File

@ -40,6 +40,11 @@ namespace CodeWalker
}
}
public static Vector3 Abs(this Vector3 v)
{
return new Vector3(Math.Abs(v.X), Math.Abs(v.Y), Math.Abs(v.Z));
}
public static Vector4 Floor(this Vector4 v)
{

View File

@ -334,6 +334,18 @@ namespace CodeWalker.World
}
return true;
}
public bool ContainsAABBNoClip(ref Vector3 cen, ref Vector3 e)
{
var c = cen - Position;
for (int i = 0; i < 5; i++)
{
var pn = Planes[i].Normal;
var d = (c.X * pn.X) + (c.Y * pn.Y) + (c.Z * pn.Z); //Vector3.Dot(c, pn);//
var r = (e.X * (pn.X > 0 ? pn.X : -pn.X)) + (e.Y * (pn.Y > 0 ? pn.Y : -pn.Y)) + (e.Z * (pn.Z > 0 ? pn.Z : -pn.Z)); //Vector3.Dot(e, pn.Abs()); //
if ((d + r) < 0) return false;
}
return true;
}
public bool ContainsAABBNoClipNoOpt(ref Vector3 bmin, ref Vector3 bmax)
{
var c = (bmax + bmin) * 0.5f - Position;

View File

@ -82,6 +82,7 @@ namespace CodeWalker.Rendering
public bool markerdepthclip = Settings.Default.MarkerDepthClip;
private RenderLodManager LodManager = new RenderLodManager();
private List<YmapEntityDef> renderworldentities = new List<YmapEntityDef>(); //used when rendering world view.
private List<RenderableEntity> renderworldrenderables = new List<RenderableEntity>();
@ -1520,6 +1521,11 @@ namespace CodeWalker.Rendering
renderworldentities.Clear();
renderworldrenderables.Clear();
//LodManager.Update(renderworldVisibleYmapDict, ref camera.Position, currentElapsedTime);
VisibleYmaps.Clear();
foreach (var ymap in renderworldVisibleYmapDict.Values)
{
@ -1839,11 +1845,10 @@ namespace CodeWalker.Rendering
{
if (!RenderIsEntityFinalRender(ent)) return;
var bscent = ent.Position + ent.BSCenter - camera.Position;
float bsrad = ent.BSRadius;
if (!camera.ViewFrustum.ContainsSphereNoClipNoOpt(ref bscent, bsrad))
if (!camera.ViewFrustum.ContainsAABBNoClip(ref ent.BBCenter, ref ent.BBExtent))
{
return; //frustum cull
return;
}
@ -3348,5 +3353,101 @@ namespace CodeWalker.Rendering
public class RenderLodManager
{
private Dictionary<YmapEntityDef, int> EntityDict = new Dictionary<YmapEntityDef, int>(); //visible entities and their current child counts
public void Update(Dictionary<MetaHash, YmapFile> ymaps, ref Vector3 position, float elapsed)
{
EntityDict.Clear();
foreach (var ymap in ymaps.Values)
{
YmapFile pymap = ymap.Parent;
if (ymap._CMapData.parent != 0) //ensure parent references on ymaps
{
ymaps.TryGetValue(ymap._CMapData.parent, out pymap);
if (ymap.Parent != pymap)
{
ymap.Parent = pymap;
if (ymap.RootEntities != null) //parent changed or first set, make sure to link entities hierarchy
{
for (int i = 0; i < ymap.RootEntities.Length; i++)
{
var ent = ymap.RootEntities[i];
int pind = ent._CEntityDef.parentIndex;
if (pind >= 0) //connect root entities to parents if they have them..
{
YmapEntityDef p = null;
if ((pymap != null) && (pymap.AllEntities != null))
{
if ((pind < pymap.AllEntities.Length))
{
p = pymap.AllEntities[pind];
ent.Parent = p;
ent.ParentName = p._CEntityDef.archetypeName;
}
}
else
{ }//should only happen if parent ymap not loaded yet...
}
}
}
}
}
if (ymap.AllEntities != null) //add visible entities to the dict, increment entity parent child counts
{
for (int i = 0; i < ymap.AllEntities.Length; i++)
{
var ent = ymap.AllEntities[i];
//ent.BBMin
}
}
}
}
}
}