2025-04-22 17:16:40 +08:00

403 lines
16 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using NUnit.Framework;
using UnityEngine.TestTools;
using Unity.HLODSystem.SpaceManager;
using Unity.HLODSystem.Utils;
using System.Linq;
using System.Reflection;
namespace Unity.HLODSystem.EditorTests
{
[TestFixture]
public class SpaceSplitterTests
{
GameObject m_hlodRootGameObject;
HLOD m_hlodComponent;
GameObject m_prefab;
GameObject m_prefabMesh;
List<GameObject> m_includeObjects = new List<GameObject>();
List<GameObject> m_excludeObjects = new List<GameObject>();
delegate DisposableList<HLODBuildInfo> CreateBuildInfoFunc(SpaceNode root, float minObjectSize);
MethodInfo m_buildInfoFunc;
[SetUp]
public void Setup()
{
m_prefab = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/TestAssets/Prefabs/RinNumber.prefab");
m_prefabMesh = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/TestAssets/Prefabs/RinNumber_LOD3.prefab");
m_buildInfoFunc = typeof(HLODCreator).GetMethod("CreateBuildInfo", BindingFlags.Static | BindingFlags.NonPublic);
m_hlodRootGameObject = new GameObject();
m_hlodComponent = m_hlodRootGameObject.AddComponent<HLOD>();
var obj1 = GameObject.Instantiate(m_prefab);
obj1.transform.SetParent(m_hlodRootGameObject.transform);
obj1.transform.position = new Vector3(0.0f, 0.0f, 0.0f);
m_includeObjects.Add(obj1);
var obj2 = GameObject.Instantiate(m_prefab);
obj2.transform.SetParent(m_hlodRootGameObject.transform);
obj2.transform.position = new Vector3(10.0f, 0.0f, -10.0f);
m_includeObjects.Add(obj2);
var obj3 = GameObject.Instantiate(m_prefab);
obj3.transform.SetParent(m_hlodRootGameObject.transform);
obj3.transform.position = new Vector3(-10.0f, 0.0f, -10.0f);
m_includeObjects.Add(obj3);
var obj4 = GameObject.Instantiate(m_prefab);
obj4.transform.SetParent(m_hlodRootGameObject.transform);
obj4.transform.position = new Vector3(10.0f, 0.0f, 10.0f);
m_includeObjects.Add(obj4);
var obj5 = GameObject.Instantiate(m_prefab);
obj5.transform.SetParent(m_hlodRootGameObject.transform);
obj5.transform.position = new Vector3(-10.0f, 0.0f, 10.0f);
m_includeObjects.Add(obj5);
var obj6 = GameObject.Instantiate(m_prefabMesh);
obj6.transform.SetParent(m_hlodRootGameObject.transform);
obj6.transform.position = new Vector3(-5.0f, 0.0f, -5.0f);
obj6.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f);
m_includeObjects.Add(obj6);
var obj7 = GameObject.Instantiate(m_prefabMesh);
obj7.transform.SetParent(m_hlodRootGameObject.transform);
obj7.transform.position = new Vector3(-5.0f, 0.0f, 5.0f);
obj7.transform.localScale = new Vector3(0.3f, 0.3f, 0.3f);
m_includeObjects.Add(obj7);
var obj8 = GameObject.Instantiate(m_prefabMesh);
obj8.transform.SetParent(m_hlodRootGameObject.transform);
obj8.transform.position = new Vector3( 5.0f, 0.0f, -5.0f);
obj8.transform.localScale = new Vector3(2.0f, 2.0f, 2.0f);
m_includeObjects.Add(obj8);
var obj9 = GameObject.Instantiate(m_prefabMesh);
obj9.transform.SetParent(m_hlodRootGameObject.transform);
obj9.transform.position = new Vector3( 5.0f, 0.0f, 5.0f);
obj9.transform.localScale = new Vector3(5.0f, 5.0f, 5.0f);
m_includeObjects.Add(obj9);
//this should be exclude.
var obj10 = new GameObject();
obj10.transform.SetParent(m_hlodRootGameObject.transform);
obj10.transform.position = new Vector3(40.0f, 0.0f, 40.0f);
m_excludeObjects.Add(obj10);
var obj11 = new GameObject();
obj11.transform.SetParent(m_hlodRootGameObject.transform);
obj11.transform.position = new Vector3(-40.0f, 0.0f, -40.0f);
m_excludeObjects.Add(obj11);
}
[TearDown]
public void Cleanup()
{
GameObject.DestroyImmediate(m_hlodRootGameObject);
}
[Test]
public void BoundsTest()
{
const float EPSILON = 0.001f; // error should less than 0.1%.
var bounds1 = m_hlodComponent.GetBounds();
Assert.LessOrEqual((bounds1.center - new Vector3(0.0f, 5.0f, 0.0f)).magnitude, EPSILON);
Assert.LessOrEqual((bounds1.min - new Vector3(-10.5f, -5.5f, -10.5f)).magnitude, EPSILON);
Assert.LessOrEqual((bounds1.max - new Vector3( 10.5f, 15.5f, 10.5f)).magnitude, EPSILON);
//add new object to outside of area
var addObj1 = GameObject.Instantiate(m_prefab);
addObj1.transform.SetParent(m_hlodRootGameObject.transform);
addObj1.transform.position = new Vector3(20.0f, 0.0f, 0.0f);
var bounds2 = m_hlodComponent.GetBounds();
Assert.LessOrEqual((bounds2.center - new Vector3(5.0f, 5.0f, 0.0f)).magnitude, EPSILON);
Assert.LessOrEqual((bounds2.min - new Vector3(-10.5f, -10.5f, -15.5f)).magnitude, EPSILON);
Assert.LessOrEqual((bounds2.max - new Vector3(20.5f, 20.5f, 15.5f)).magnitude, EPSILON);
//add new object to inside of area
var addObj3 = GameObject.Instantiate(m_prefab);
addObj3.transform.SetParent(m_hlodRootGameObject.transform);
addObj3.transform.position = new Vector3(5.0f, 0.0f, 5.0f);
var bounds3 = m_hlodComponent.GetBounds();
Assert.LessOrEqual((bounds3.center - new Vector3(5.0f, 5.0f, 0.0f)).magnitude, EPSILON);
Assert.LessOrEqual((bounds3.min - new Vector3(-10.5f, -10.5f, -15.5f)).magnitude, EPSILON);
Assert.LessOrEqual((bounds3.max - new Vector3(20.5f, 20.5f, 15.5f)).magnitude, EPSILON);
//add new empty object to ouside of area.
//the bounds must not changed.
var addObj4 = new GameObject();
addObj4.transform.SetParent(m_hlodRootGameObject.transform);
addObj4.transform.position = new Vector3(5.0f, 0.0f, 5.0f);
var bounds4 = m_hlodComponent.GetBounds();
Assert.LessOrEqual((bounds4.center - new Vector3(5.0f, 5.0f, 0.0f)).magnitude, EPSILON);
Assert.LessOrEqual((bounds4.min - new Vector3(-10.5f, -10.5f, -15.5f)).magnitude, EPSILON);
Assert.LessOrEqual((bounds4.max - new Vector3(20.5f, 20.5f, 15.5f)).magnitude, EPSILON);
}
[Test]
public void HLODTargetsTest()
{
List<GameObject> hlodTargets = ObjectUtils.HLODTargets(m_hlodComponent.gameObject);
Assert.AreEqual(hlodTargets.Count, 9);
for ( int i = 0; i < hlodTargets.Count; ++i )
{
Assert.True(m_includeObjects.Contains(hlodTargets[i]));
}
for (int i = 0; i < m_excludeObjects.Count; ++i)
{
Assert.False(hlodTargets.Contains(m_excludeObjects[i]));
}
}
[Test]
public void SpaceSplitTestSize5()
{
List<GameObject> hlodTargets = ObjectUtils.HLODTargets(m_hlodComponent.gameObject);
ISpaceSplitter spliter = new QuadTreeSpaceSplitter(null);
List<SpaceNode> rootNodes = spliter.CreateSpaceTree(m_hlodComponent.GetBounds(), 5.0f, m_hlodComponent.transform, hlodTargets, null);
Assert.AreEqual(1, rootNodes.Count);
Assert.AreEqual(CalcLevel(rootNodes[0]), 4);
Assert.AreEqual(GetTargetCount(rootNodes[0]), 9);
}
[Test]
public void SpaceSplitTestSize10()
{
List<GameObject> hlodTargets = ObjectUtils.HLODTargets(m_hlodComponent.gameObject);
ISpaceSplitter spliter = new QuadTreeSpaceSplitter(null);
List<SpaceNode> rootNodes = spliter.CreateSpaceTree(m_hlodComponent.GetBounds(), 10.0f, m_hlodComponent.transform, hlodTargets, null);
Assert.AreEqual(1, rootNodes.Count);
Assert.AreEqual(CalcLevel(rootNodes[0]), 3);
Assert.AreEqual(GetTargetCount(rootNodes[0]), 9);
}
[Test]
public void SpaceSplitSubTreeTestSize5()
{
List<GameObject> hlodTargets = ObjectUtils.HLODTargets(m_hlodComponent.gameObject);
var options = QuadTreeSpaceSplitter.CreateOptions(true, 5.0f, true, 20);
ISpaceSplitter spliter = new QuadTreeSpaceSplitter(options);
List<SpaceNode> rootNodes = spliter.CreateSpaceTree(m_hlodComponent.GetBounds(), 5.0f, m_hlodComponent.transform, hlodTargets, null);
Assert.AreEqual(4, rootNodes.Count);
Assert.AreEqual(3, CalcLevel(rootNodes[0]));
Assert.AreEqual(3, GetTargetCount(rootNodes[0]));
Assert.AreEqual(3, CalcLevel(rootNodes[1]));
Assert.AreEqual(2, GetTargetCount(rootNodes[1]));
Assert.AreEqual(3, CalcLevel(rootNodes[2]));
Assert.AreEqual(2, GetTargetCount(rootNodes[2]));
Assert.AreEqual(3, CalcLevel(rootNodes[3]));
Assert.AreEqual(2, GetTargetCount(rootNodes[3]));
}
[Test]
public void SpaceSplitSubTreeTestSize10()
{
List<GameObject> hlodTargets = ObjectUtils.HLODTargets(m_hlodComponent.gameObject);
var options = QuadTreeSpaceSplitter.CreateOptions(true, 5.0f, true, 20);
ISpaceSplitter spliter = new QuadTreeSpaceSplitter(options);
List<SpaceNode> rootNodes = spliter.CreateSpaceTree(m_hlodComponent.GetBounds(), 10.0f, m_hlodComponent.transform, hlodTargets, null);
Assert.AreEqual(4, rootNodes.Count);
Assert.AreEqual(2, CalcLevel(rootNodes[0]));
Assert.AreEqual(3, GetTargetCount(rootNodes[0]));
Assert.AreEqual(2, CalcLevel(rootNodes[1]));
Assert.AreEqual(2, GetTargetCount(rootNodes[1]));
Assert.AreEqual(2, CalcLevel(rootNodes[2]));
Assert.AreEqual(2, GetTargetCount(rootNodes[2]));
Assert.AreEqual(2, CalcLevel(rootNodes[3]));
Assert.AreEqual(2, GetTargetCount(rootNodes[3]));
}
[Test]
public void CreateBuildInfoTest()
{
List<GameObject> hlodTargets = ObjectUtils.HLODTargets(m_hlodComponent.gameObject);
ISpaceSplitter spliter = new QuadTreeSpaceSplitter(null);
List<SpaceNode> rootNodes = spliter.CreateSpaceTree(m_hlodComponent.GetBounds(), 5.0f, m_hlodComponent.transform, hlodTargets, null);
Assert.AreEqual(1, rootNodes.Count);
using (DisposableList<HLODBuildInfo> ret = (DisposableList<HLODBuildInfo>)m_buildInfoFunc.Invoke(null, new object[] { null, rootNodes[0], 0.0f }))
{
//only exists nodes are creating info.
Assert.AreEqual(ret.Count, 11);
Assert.AreEqual(ret[0].Name, "");
Assert.AreEqual(ret[0].WorkingObjects.Count, 9);
Assert.AreEqual(ret[1].Name, "_1");
Assert.AreEqual(ret[1].WorkingObjects.Count, 2);
Assert.AreEqual(ret[2].Name, "_2");
Assert.AreEqual(ret[2].WorkingObjects.Count, 2);
Assert.AreEqual(ret[3].Name, "_3");
Assert.AreEqual(ret[3].WorkingObjects.Count, 2);
Assert.AreEqual(ret[4].Name, "_4");
Assert.AreEqual(ret[4].WorkingObjects.Count, 2);
Assert.AreEqual(ret[5].Name, "_1_1");
Assert.AreEqual(ret[5].WorkingObjects.Count, 1);
Assert.AreEqual(ret[6].Name, "_1_4");
Assert.AreEqual(ret[6].WorkingObjects.Count, 1);
Assert.AreEqual(ret[7].Name, "_2_2");
Assert.AreEqual(ret[7].WorkingObjects.Count, 1);
Assert.AreEqual(ret[8].Name, "_2_3");
Assert.AreEqual(ret[8].WorkingObjects.Count, 1);
Assert.AreEqual(ret[9].Name, "_3_3");
Assert.AreEqual(ret[9].WorkingObjects.Count, 1);
Assert.AreEqual(ret[10].Name, "_4_4");
Assert.AreEqual(ret[10].WorkingObjects.Count, 1);
}
//exclude object smaller than 0.5.
using (DisposableList<HLODBuildInfo> ret = (DisposableList<HLODBuildInfo>)m_buildInfoFunc.Invoke(null, new object[] { null, rootNodes[0], 0.5f }))
{
//only exists nodes are creating info.
Assert.AreEqual(ret.Count, 10);
Assert.AreEqual(ret[0].Name, "");
Assert.AreEqual(ret[0].WorkingObjects.Count, 8);
Assert.AreEqual(ret[1].Name, "_1");
Assert.AreEqual(ret[1].WorkingObjects.Count, 1);
Assert.AreEqual(ret[2].Name, "_2");
Assert.AreEqual(ret[2].WorkingObjects.Count, 2);
Assert.AreEqual(ret[3].Name, "_3");
Assert.AreEqual(ret[3].WorkingObjects.Count, 2);
Assert.AreEqual(ret[4].Name, "_4");
Assert.AreEqual(ret[4].WorkingObjects.Count, 2);
Assert.AreEqual(ret[5].Name, "_1_1");
Assert.AreEqual(ret[5].WorkingObjects.Count, 1);
Assert.AreEqual(ret[6].Name, "_2_2");
Assert.AreEqual(ret[6].WorkingObjects.Count, 1);
Assert.AreEqual(ret[7].Name, "_2_3");
Assert.AreEqual(ret[7].WorkingObjects.Count, 1);
Assert.AreEqual(ret[8].Name, "_3_3");
Assert.AreEqual(ret[8].WorkingObjects.Count, 1);
Assert.AreEqual(ret[9].Name, "_4_4");
Assert.AreEqual(ret[9].WorkingObjects.Count, 1);
}
//exclude object smaller than 1.
using (DisposableList<HLODBuildInfo> ret = (DisposableList<HLODBuildInfo>)m_buildInfoFunc.Invoke(null, new object[] { null, rootNodes[0], 1.0f }))
{
//only exists nodes are creating info.
Assert.AreEqual(ret.Count, 9);
Assert.AreEqual(ret[0].Name, "");
Assert.AreEqual(ret[0].WorkingObjects.Count, 7);
Assert.AreEqual(ret[1].Name, "_1");
Assert.AreEqual(ret[1].WorkingObjects.Count, 1);
Assert.AreEqual(ret[2].Name, "_2");
Assert.AreEqual(ret[2].WorkingObjects.Count, 1);
Assert.AreEqual(ret[3].Name, "_3");
Assert.AreEqual(ret[3].WorkingObjects.Count, 2);
Assert.AreEqual(ret[4].Name, "_4");
Assert.AreEqual(ret[4].WorkingObjects.Count, 2);
Assert.AreEqual(ret[5].Name, "_1_1");
Assert.AreEqual(ret[5].WorkingObjects.Count, 1);
Assert.AreEqual(ret[6].Name, "_2_2");
Assert.AreEqual(ret[6].WorkingObjects.Count, 1);
Assert.AreEqual(ret[7].Name, "_3_3");
Assert.AreEqual(ret[7].WorkingObjects.Count, 1);
Assert.AreEqual(ret[8].Name, "_4_4");
Assert.AreEqual(ret[8].WorkingObjects.Count, 1);
}
}
private static int CalcLevel(SpaceNode node)
{
SpaceNode curNode = node;
int level = 0;
while (curNode != null)
{
level += 1;
if (curNode.HasChild() == true)
{
curNode = curNode.GetChild(0);
}
else
{
curNode = null;
}
}
return level;
}
private static int GetTargetCount(SpaceNode node)
{
int count = 0;
Stack<SpaceNode> searchNodes = new Stack<SpaceNode>();
searchNodes.Push(node);
while(searchNodes.Count > 0 )
{
SpaceNode curNode = searchNodes.Pop();
count += curNode.Objects.Count;
for ( int i = 0; i < curNode.GetChildCount(); ++i )
{
searchNodes.Push(curNode.GetChild(i));
}
}
return count;
}
}
}