現在我試圖加速我的Force-Directed圖形實現。到目前爲止,我已經實現了使用八叉樹來減少計算次數的Barnes-Hut算法。我已經多次測試過,並且與力相關的計算次數確實大幅減少。下面是沒有Barns-Hut(藍線)和(紅線)的節點數的計算圖: 即使現在它應該快得多,事實是,在速度(時間)的問題上,升級只有百分之幾。八叉樹實現的速度問題
我想這可能是造成這種情況的一個部分,就是樹的創建和樹中的元素放置。由於元素不斷移動,我需要在每個循環中重新創建樹,直到達到一些停止條件。但是如果我會花很多時間來創建樹,那麼我會在那裏花費大量時間來增加強制計算。至少這是我的想法。這是我如何在我的主文件循環添加元素:
void AddTreeElements(Octree* tree, glm::vec3* boundries, Graph& graph)
{
for(auto& node:graph.NodeVector())
{
node.parent_group = nullptr;
if(node.pos[0] < boundries[1][0] && node.pos[0] > boundries[0][0] &&
node.pos[1] > boundries[4][1] && node.pos[1] < boundries[1][1] &&
node.pos[2] < boundries[0][2] && node.pos[2] > boundries[3][2])
{
tree->AddObject(&node.second);
continue;
}
if(node.pos[0] < boundries[0][0])
{
boundries[0][0] = node.pos[0]-1.0f;
boundries[3][0] = node.pos[0]-1.0f;
boundries[4][0] = node.pos[0]-1.0f;
boundries[7][0] = node.pos[0]-1.0f;
}
else if(node.pos[0] > boundries[1][0])
{
boundries[1][0] = node.pos[0]+1.0f;
boundries[2][0] = node.pos[0]+1.0f;
boundries[5][0] = node.pos[0]+1.0f;
boundries[6][0] = node.pos[0]+1.0f;
}
if(node.pos[1] < boundries[4][1])
{
boundries[4][1] = node.pos[1]-1.0f;
boundries[5][1] = node.pos[1]-1.0f;
boundries[6][1] = node.pos[1]-1.0f;
boundries[7][1] = node.pos[1]-1.0f;
}
else if(node.pos[1] > boundries[0][1])
{
boundries[0][1] = node.pos[1]+1.0f;
boundries[1][1] = node.pos[1]+1.0f;
boundries[2][1] = node.pos[1]+1.0f;
boundries[3][1] = node.pos[1]+1.0f;
}
if(node.pos[2] < boundries[3][2])
{
boundries[2][2] = node.pos[2]-1.0f;
boundries[3][2] = node.pos[2]-1.0f;
boundries[6][2] = node.pos[2]-1.0f;
boundries[7][2] = node.pos[2]-1.0f;
}
else if(node.pos[2] > boundries[0][2])
{
boundries[0][2] = node.pos[2]+1.0f;
boundries[1][2] = node.pos[2]+1.0f;
boundries[4][2] = node.pos[2]+1.0f;
boundries[5][2] = node.pos[2]+1.0f;
}
}
}
我在做什麼這裏是經過我在圖中的所有元素,並將它們添加到樹的根部。另外,我正在擴展代表下一個循環的八叉樹邊界的方框,因此所有節點都將適合內部。如下所示
字段以八叉樹更新重要:
Octree* trees[2][2][2];
glm::vec3 vBoundriesBox[8];
bool leaf;
float combined_weight = 0;
std::vector<Element*> objects;
,並負責更新代碼的一部分:
#define MAX_LEVELS 5
void Octree::AddObject(Element* object)
{
this->objects.push_back(object);
}
void Octree::Update()
{
if(this->objects.size()<=1 || level > MAX_LEVELS)
{
for(Element* Element:this->objects)
{
Element->parent_group = this;
}
return;
}
if(leaf)
{
GenerateChildren();
leaf = false;
}
while (!this->objects.empty())
{
Element* obj = this->objects.back();
this->objects.pop_back();
if(contains(trees[0][0][0],obj))
{
trees[0][0][0]->AddObject(obj);
trees[0][0][0]->combined_weight += obj->weight;
} else if(contains(trees[0][0][1],obj))
{
trees[0][0][1]->AddObject(obj);
trees[0][0][1]->combined_weight += obj->weight;
} else if(contains(trees[0][1][0],obj))
{
trees[0][1][0]->AddObject(obj);
trees[0][1][0]->combined_weight += obj->weight;
} else if(contains(trees[0][1][1],obj))
{
trees[0][1][1]->AddObject(obj);
trees[0][1][1]->combined_weight += obj->weight;
} else if(contains(trees[1][0][0],obj))
{
trees[1][0][0]->AddObject(obj);
trees[1][0][0]->combined_weight += obj->weight;
} else if(contains(trees[1][0][1],obj))
{
trees[1][0][1]->AddObject(obj);
trees[1][0][1]->combined_weight += obj->weight;
} else if(contains(trees[1][1][0],obj))
{
trees[1][1][0]->AddObject(obj);
trees[1][1][0]->combined_weight += obj->weight;
} else if(contains(trees[1][1][1],obj))
{
trees[1][1][1]->AddObject(obj);
trees[1][1][1]->combined_weight += obj->weight;
}
}
for(int i=0;i<2;i++)
{
for(int j=0;j<2;j++)
{
for(int k=0;k<2;k++)
{
trees[i][j][k]->Update();
}
}
}
}
bool Octree::contains(Octree* child, Element* object)
{
if(object->pos[0] >= child->vBoundriesBox[0][0] && object->pos[0] <= child->vBoundriesBox[1][0] &&
object->pos[1] >= child->vBoundriesBox[4][1] && object->pos[1] <= child->vBoundriesBox[0][1] &&
object->pos[2] >= child->vBoundriesBox[3][2] && object->pos[2] <= child->vBoundriesBox[0][2])
return true;
return false;
}
因爲我使用的指針圍繞樹移動元素我不認爲對象創建/銷燬是一個問題。一個地方,我想可能對速度的影響是這一個:
Element* obj = this->objects.back();
this->objects.pop_back();
if(contains(trees[0][0][0],obj))
雖然我不知道我該怎麼ommit /加快速度。有人有什麼建議可以在這裏做什麼?
編輯:
我已經做了一些餐巾數學,我想還有一個地方可能會造成重大的速度下降。 Boundries在Update
方法如下檢查就像是做了很多,我的計算是,由於這種增加的複雜性是在最壞的情況下:
number_of_elements * number_of_childern * number_of_faces * MAX_LEVELS
這在我的情況下,等於到number_of_elements * 240。
有人可以確認我的想法是否合理嗎?
http://codereview.stackexchange.com/ – Mihai
@Mihai我在你的建議後發佈它:http://codereview.stackexchange.com/questions/127693/speed-concerns-of-octree-plementation – sebap123
DrunkCoder說的可能會幫助,但請記住性能優化的前三條規則:度量,度量,度量!爲您的平臺使用採樣CPU分析器(例如,Linux上的perf +熱點,Windows上的Visual Studio分析器或macOS上的Instruments),然後使用該數據查找性能原因。 – milianw