因此,基本上我想创建一个场景,在该场景中生成约50K个小行星,并带有一个位置和AABB(轴对齐边界框),并将它们中的每一个移动到开始时生成的随机方向。将它们移动后,我必须检查是否有小行星碰撞。
我正在使用四叉树数据结构进行插入和碰撞检查。 我保留了一个由5万个点组成的数组,并对其进行迭代和更新,然后将其插入四叉树中,然后再次对5万个点进行迭代,并通过QT进行查询以查看是否有任何点在碰撞。
我在这里和那里读了很多书,大约2周时间,并尝试了尽可能多的资料,但是我无法挤出最大的表现。大多数资源都使用c ++或其他性能更好的语言,但是我需要使用C#来实现。任何改善性能的建议都将不胜感激。
这是我的代码:
public struct Point
{
public float x,y;
public int ID;
public void MoveTowards(float posX, float posY)
{
position.x = position.x + posX;
position.y = position.y + posY;
}
}
public class Controller
{
Point[] asteroids = new Point[50K];
Point[] speed = new Point[50K];
QuadTree qt = new QuadTree();
//Runs every frame
void Update()
{
qt.ClearAllNodes();
for loop asteroids(50K)
{
asteroids[i].MoveTowards(speed.x, speed.y);
qt.Insert(astetoids[i]);
}
for loop asteroids(50K)
{
int collidingAsteroidID = qt.Query(astetoids[i]);
if(collidingAsteroidID != -1) {
print(collidingAsteroidID + " is colliding with " + i);
}
}
}
}
class QuadTree
{
public Rectangle boundry;
Point[] nodes;
bool root = false;
bool divided = false;
int numberOfNodesInserted = 0;
QuadTree northEast, northWest, southEast, southWest;
public QuadTree(Rectangle boundry)
{
nodes = new Point[4];
this.boundry = boundry;
}
#region Methods
//Clear all the nodes in the Quad-Tree
public void ClearAllNodes()
{
if(numberOfNodesInserted == 0 && !root) return;
numberOfNodesInserted = 0;
root = false;
if(divided)
{
northEast.ClearAllNodes();
northWest.ClearAllNodes();
southEast.ClearAllNodes();
southWest.ClearAllNodes();
}
divided = false;
}
public bool Insert(Point point)
{
//Checking if the position is in the boundries.
if(!boundry.Contains(point)) return false;
if(numberOfNodesInserted < 4 && !root)
{
nodes[numberOfNodesInserted] = point;
numberOfNodesInserted++;
return true;
}
else if(root)
{
if(northEast.Insert(point)) return true;
if(northWest.Insert(point)) return true;
if(southEast.Insert(point)) return true;
if(southWest.Insert(point)) return true;
}
else if(!root && numberOfNodesInserted == 4)
{
//Making this node a branch and moving all the to sub-leafs
root = true;
numberOfNodesInserted = 0;
if(!divided)
SubDivide();
for (int i = 0; i < 4; i++)
{
if(!northEast.Insert(nodes[i]))
if(!northWest.Insert(nodes[i]))
if(!southEast.Insert(nodes[i]))
if(!southWest.Insert(nodes[i])) { }
}
if(!northEast.Insert(point))
if(!northWest.Insert(point))
if(!southEast.Insert(point))
if(!southWest.Insert(point)) { }
return true;
}
return false;
}
public int Query(Point point, float radius)
{
if(numberOfNodesInserted == 0 && !root) return -1;
if(!boundry.Contains(point)) return -1;
if(!root && numberOfNodesInserted != 0)
{
for (int i = 0; i < numberOfNodesInserted; i++)
{
if(DoOverlap(nodes[i], point, radius))
return nodes[i].ID;
}
}
else if(root && numberOfNodesInserted == 0)
{
int result;
result = northEast.Query(point);
if(result != -1) return result;
result = northWest.Query(point);
if(result != -1) return result;
result = southEast.Query(point);
if(result != -1) return result;
result = southWest.Query(point);
if(result != -1) return result;
}
return -1;
}
#endregion
#region HelperMethods
private void SubDivide()
{
//Size of the sub boundries
if(northEast == null)
{
float x = boundry.x;
float y = boundry.y;
float r = boundry.radius / 2;
northEast = new QuadTree(new Rectangle(x + r, y + r, r));
northWest = new QuadTree(new Rectangle(x - r, y + r, r));
southEast = new QuadTree(new Rectangle(x + r, y - r, r));
southWest = new QuadTree(new Rectangle(x - r, y - r, r));
}
divided = true;
}
#endregion
}
答案 0 :(得分:1)
关于您的实施:
似乎您正在为每一步重建整个树。这有必要吗?如果移动一个点,它们通常将留在同一节点中,因此可以避免clearNodes()以及随后插入同一节点的情况。
其他实现:
我已经用Java实现了一些空间索引,插入/更新速率约为1M点/秒,查询速率(冲突检查)为每秒100,000(假设每个点通常有0或1个碰撞)。性能测量here(图16b用于3D查询,图40b用于更新)。 最快的是四叉树(请参见qthypercube and qthypercube2)和PH-Tree。 它们都使用here(自广告)中所述的z顺序导航。其中的一部分是它在导航/插入/更新/删除期间计算正确的子节点。例如,在节点上调用insert(element)时,它不会快速尝试所有子节点,而是“计算”哪个子节点正确,然后直接在该子节点上调用insert()。
答案 1 :(得分:0)
有其他要求的新答案:
好的,所以对于50K点和120Hz,您需要每秒进行50,000 * 120 = 6,000,000个碰撞检查。考虑到具有4GHz的CPU,这意味着每次冲突检查大约需要650个CPU周期。我认为即使使用最高效的编程语言,您也不能使用四叉树或类似的东西来做到这一点。
我只看到一个选项: 由于您使用的是2D,请尝试以下操作:按其X坐标对所有点进行排序。然后遍历所有点,并检查与X坐标上足够接近的所有点是否可能发生碰撞的碰撞。这种算法有一些优点:
一个CPU内核,这可能仍然太慢。但是使用4核计算机,您可能会获得所需的帧速率。使用GPU,可能会获得比您所需更多的东西。但是,我没有使用GPU的经验,所以我不知道如何(轻松)完成这项工作。