Handle skinned boundings better (may improve shadows and culling performance)

This commit is contained in:
KillzXGaming 2021-06-05 18:06:24 -04:00
parent 15dca5a055
commit 06e835fd3d
2 changed files with 79 additions and 12 deletions

View file

@ -769,7 +769,6 @@ namespace Bfres.Structs
shape.BoneIndex = 0; shape.BoneIndex = 0;
shape.Text = obj.ObjectName; shape.Text = obj.ObjectName;
shape.lodMeshes = obj.lodMeshes; shape.lodMeshes = obj.lodMeshes;
shape.CreateNewBoundingBoxes();
shape.CreateBoneList(obj, this, ForceSkinInfluence, ForceSkinInfluenceMax); shape.CreateBoneList(obj, this, ForceSkinInfluence, ForceSkinInfluenceMax);
shape.CreateIndexList(obj, this); shape.CreateIndexList(obj, this);
shape.ApplyImportSettings(csvsettings, GetMaterial(shape.MaterialIndex)); shape.ApplyImportSettings(csvsettings, GetMaterial(shape.MaterialIndex));
@ -793,6 +792,7 @@ namespace Bfres.Structs
shape.BoneIndex = boneIndex; shape.BoneIndex = boneIndex;
} }
shape.CreateNewBoundingBoxes(Skeleton);
shape.OptmizeAttributeFormats(); shape.OptmizeAttributeFormats();
shape.SaveShape(IsWiiU); shape.SaveShape(IsWiiU);
shape.SaveVertexBuffer(IsWiiU); shape.SaveVertexBuffer(IsWiiU);
@ -1303,7 +1303,6 @@ namespace Bfres.Structs
shape.MaterialIndex = 0; shape.MaterialIndex = 0;
shape.lodMeshes = obj.lodMeshes; shape.lodMeshes = obj.lodMeshes;
shape.CreateNewBoundingBoxes();
shape.CreateBoneList(obj, this, ForceSkinInfluence, ForceSkinInfluenceMax); shape.CreateBoneList(obj, this, ForceSkinInfluence, ForceSkinInfluenceMax);
shape.CreateIndexList(obj, this, ForceSkinInfluence, ForceSkinInfluenceMax); shape.CreateIndexList(obj, this, ForceSkinInfluence, ForceSkinInfluenceMax);
shape.ApplyImportSettings(settings, GetMaterial(shape.MaterialIndex)); shape.ApplyImportSettings(settings, GetMaterial(shape.MaterialIndex));
@ -1329,6 +1328,7 @@ namespace Bfres.Structs
shape.BoneIndex = boneIndex; shape.BoneIndex = boneIndex;
} }
shape.CreateNewBoundingBoxes(Skeleton);
shape.OptmizeAttributeFormats(); shape.OptmizeAttributeFormats();
shape.SaveShape(IsWiiU); shape.SaveShape(IsWiiU);
shape.SaveVertexBuffer(IsWiiU); shape.SaveVertexBuffer(IsWiiU);

View file

@ -355,7 +355,7 @@ namespace Bfres.Structs
private void GenerateBoundingBoxes(object sender, EventArgs args) private void GenerateBoundingBoxes(object sender, EventArgs args)
{ {
Cursor.Current = Cursors.WaitCursor; Cursor.Current = Cursors.WaitCursor;
CreateNewBoundingBoxes(); CreateNewBoundingBoxes(GetParentModel().Skeleton);
SaveShape(GetResFileU() != null); SaveShape(GetResFileU() != null);
UpdateVertexData(); UpdateVertexData();
Cursor.Current = Cursors.Default; Cursor.Current = Cursors.Default;
@ -390,7 +390,7 @@ namespace Bfres.Structs
lod.subMeshes.Add(subMesh); lod.subMeshes.Add(subMesh);
} }
CreateNewBoundingBoxes(); CreateNewBoundingBoxes(GetParentModel().Skeleton);
} }
private void GenerateLODMeshes(object sender, EventArgs args) private void GenerateLODMeshes(object sender, EventArgs args)
@ -399,7 +399,7 @@ namespace Bfres.Structs
//Todo add lod generating //Todo add lod generating
CreateNewBoundingBoxes(); CreateNewBoundingBoxes(GetParentModel().Skeleton);
SaveShape(GetResFileU() != null); SaveShape(GetResFileU() != null);
UpdateVertexData(); UpdateVertexData();
GenerateBoundingNodes(); GenerateBoundingNodes();
@ -421,7 +421,7 @@ namespace Bfres.Structs
lodMeshes.Remove(meshes[i]); lodMeshes.Remove(meshes[i]);
} }
CreateNewBoundingBoxes(); CreateNewBoundingBoxes(GetParentModel().Skeleton);
SaveShape(GetResFileU() != null); SaveShape(GetResFileU() != null);
UpdateVertexData(); UpdateVertexData();
GenerateBoundingNodes(); GenerateBoundingNodes();
@ -970,13 +970,13 @@ namespace Bfres.Structs
VertexSkinCount = obj.GetMaxSkinInfluenceCount(); VertexSkinCount = obj.GetMaxSkinInfluenceCount();
lodMeshes = obj.lodMeshes; lodMeshes = obj.lodMeshes;
CreateNewBoundingBoxes();
CreateBoneList(obj, (FMDL)Parent.Parent, settings.LimitSkinCount, ForceSkinInfluenceMax); CreateBoneList(obj, (FMDL)Parent.Parent, settings.LimitSkinCount, ForceSkinInfluenceMax);
CreateIndexList(obj, (FMDL)Parent.Parent, settings.LimitSkinCount, ForceSkinInfluenceMax); CreateIndexList(obj, (FMDL)Parent.Parent, settings.LimitSkinCount, ForceSkinInfluenceMax);
BoneIndices = GetIndices(GetParentModel().Skeleton); BoneIndices = GetIndices(GetParentModel().Skeleton);
ApplyImportSettings(settings, GetFMAT()); ApplyImportSettings(settings, GetFMAT());
CreateNewBoundingBoxes(GetParentModel().Skeleton);
OptmizeAttributeFormats(); OptmizeAttributeFormats();
SaveShape(IsWiiU); SaveShape(IsWiiU);
SaveVertexBuffer(IsWiiU); SaveVertexBuffer(IsWiiU);
@ -1178,23 +1178,53 @@ namespace Bfres.Structs
} }
} }
public void CreateNewBoundingBoxes() public void CreateNewBoundingBoxes(STSkeleton skeleton)
{ {
boundingBoxes.Clear(); boundingBoxes.Clear();
boundingRadius.Clear(); boundingRadius.Clear();
foreach (LOD_Mesh mesh in lodMeshes) foreach (LOD_Mesh mesh in lodMeshes)
{ {
BoundingBox box = CalculateBoundingBox(); BoundingBox box = CalculateBoundingBox(skeleton);
boundingBoxes.Add(box); boundingBoxes.Add(box);
boundingRadius.Add(box.Radius); boundingRadius.Add(box.Radius);
foreach (LOD_Mesh.SubMesh sub in mesh.subMeshes) foreach (LOD_Mesh.SubMesh sub in mesh.subMeshes)
boundingBoxes.Add(box); boundingBoxes.Add(box);
} }
} }
private BoundingBox CalculateBoundingBox()
private BoundingBox CalculateBoundingBox(STSkeleton skeleton)
{ {
Vector3 min = CalculateBBMin(vertices); Vector3 min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
Vector3 max = CalculateBBMax(vertices); Vector3 max = new Vector3(float.MinValue, float.MinValue, float.MinValue);
if (VertexSkinCount > 0)
{
var aabb = CalculateSkinnedBoundings(skeleton, vertices);
//Failed to get bounding data for some reason, calculate normally
//This shouldn't happen but it's a fail safe option.
if (aabb.Count == 0)
{
min = CalculateBBMin(vertices);
max = CalculateBBMax(vertices);
}
//Get the largest values in local space to create the largest bounding box
foreach (var bounding in aabb)
{
min.X = Math.Min(min.X, bounding.Min.X);
min.Y = Math.Min(min.Y, bounding.Min.Y);
min.Z = Math.Min(min.Z, bounding.Min.Z);
max.X = Math.Max(max.X, bounding.Max.X);
max.Y = Math.Max(max.Y, bounding.Max.Y);
max.Z = Math.Max(max.Z, bounding.Max.Z);
}
}
else
{
min = CalculateBBMin(vertices);
max = CalculateBBMax(vertices);
}
Vector3 center = max + min; Vector3 center = max + min;
float xxMax = GetExtent(max.X, min.X); float xxMax = GetExtent(max.X, min.X);
@ -1207,6 +1237,43 @@ namespace Bfres.Structs
return new BoundingBox() { Radius = radius, Center = center, Extend = extend }; return new BoundingBox() { Radius = radius, Center = center, Extend = extend };
} }
private List<AABB> CalculateSkinnedBoundings(STSkeleton skeleton, List<Vertex> vertices)
{
Dictionary<int, AABB> skinnedBoundings = new Dictionary<int, AABB>();
for (int i = 0; i < vertices.Count; i++)
{
foreach (var boneID in vertices[i].boneIds)
{
if (!skinnedBoundings.ContainsKey(boneID))
skinnedBoundings.Add(boneID, new AABB());
//Get the skinned bone transform
var transform = skeleton.bones[boneID].Transform;
var inverted = transform.Inverted();
//Get the position in local coordinates
var position = vertices[i].pos;
position = OpenTK.Vector3.TransformPosition(position, inverted);
var bounding = skinnedBoundings[boneID];
//Set the min and max values
bounding.Min.X = Math.Min(bounding.Min.X, position.X);
bounding.Min.Y = Math.Min(bounding.Min.Y, position.Y);
bounding.Min.Z = Math.Min(bounding.Min.Z, position.Z);
bounding.Max.X = Math.Max(bounding.Max.X, position.X);
bounding.Max.Y = Math.Max(bounding.Max.Y, position.Y);
bounding.Max.Z = Math.Max(bounding.Max.Z, position.Z);
}
}
return skinnedBoundings.Values.ToList();
}
class AABB
{
public Vector3 Min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
public Vector3 Max = new Vector3(float.MinValue, float.MinValue, float.MinValue);
}
private float CalculateBoundingRadius(Vector3 min, Vector3 max) private float CalculateBoundingRadius(Vector3 min, Vector3 max)
{ {
Vector3 length = max - min; Vector3 length = max - min;