C++ 点到体素映射的优化
我使用分析器查看了一些运行速度不够快的代码。它发现以下功能占用了大部分时间,而此功能的一半时间花在了C++ 点到体素映射的优化,c++,performance,floor,C++,Performance,Floor,我使用分析器查看了一些运行速度不够快的代码。它发现以下功能占用了大部分时间,而此功能的一半时间花在了楼层。现在,有两种可能性:优化此函数或提高一个级别并减少对此函数的调用。我想知道,第一个是否可能 int Sph::gridIndex (Vector3 position) const { int mx = ((int)floor(position.x / _gridIntervalSize) % _gridSize); int my = ((int)floor(position.
楼层。现在,有两种可能性:优化此函数或提高一个级别并减少对此函数的调用。我想知道,第一个是否可能
int Sph::gridIndex (Vector3 position) const {
int mx = ((int)floor(position.x / _gridIntervalSize) % _gridSize);
int my = ((int)floor(position.y / _gridIntervalSize) % _gridSize);
int mz = ((int)floor(position.z / _gridIntervalSize) % _gridSize);
if (mx < 0) {
mx += _gridSize;
}
if (my < 0) {
my += _gridSize;
}
if (mz < 0) {
mz += _gridSize;
}
int x = mx * _gridSize * _gridSize;
int y = my * _gridSize;
int z = mz * 1;
return x + y + z;
}
int Sph::gridIndex(矢量3位置)常量{
int mx=((int)楼层(position.x/_gridintervalize)%_gridSize);
int my=((int)楼层(position.y/_gridintervalize)%\u gridSize);
int mz=((int)楼层(position.z/_gridintervalize)%_gridSize);
如果(mx<0){
mx+=\u网格大小;
}
if(my<0){
我的+=\u网格大小;
}
if(mz<0){
mz+=\u网格大小;
}
int x=mx*_gridSize*_gridSize;
int y=我的*网格大小;
intz=mz*1;
返回x+y+z;
}
Vector3
只是一个简单的类,它存储三个浮点数并提供一些重载运算符\u gridSize
是int
类型,而\u gridintervalize
是浮点型。共有^3个桶
该函数的目的是提供哈希表支持。每个3d点都映射到一个索引,并且位于大小为_GridIntervalize ^3的相同体素中的点应该落在同一个桶中。我假设您使用地板
,因为负值是可能的,并且您不希望在强制转换为int时由于默认截断而出现异常(值从两侧向零舍入,形成一些过大的体素)
如果可以为向量中的每个值指定一个最安全的负值,则可以在施放前减去该(负值)值,或者更确切地说,减去最接近的更负的\u gridintervalize
,然后放下地板
使用fmod
可以确保您有一个最安全的负值,并替换整数%
,但这可能是一种反优化。不过,作为一种快速更改,它可能值得检查
此外,请检查您的平台是否支持向量指令,以及是否可以鼓励您的编译器轻松地使用它们。x86芯片当然有整数向量指令和浮点指令(首先是旧的奔腾1 MMX指令),并且可能能够比“普通”更有效地处理这些指令CPU指令集。这甚至可能是为您的编译器挖掘向量指令内部函数列表并进行手动优化的一个例子。只需先检查编译器能为您做些什么-我不确定这种优化编译器能为您做多少
一个可能微不足道的微观优化
return (mx * _gridSize + my) * _gridSize + mz;
保存一个整数乘法。当然,这很简单,而且编译器可能会捕获它,但这是一个老习惯
哦,注意前面的下划线。这些是保留的标识符。不太可能引起问题,但如果它们引起了问题,你也不能抱怨
编辑
另一种避免地板的方法是分别处理正负面。如果您愿意接受网格单元格边缘的项目可能位于错误的单元格中(无论如何都可能,因为浮动应视为近似值)只需在否定的情况下应用<代码> -1 < /代码>偏移量,将它从零中拉出几乎正确的量来补偿截断。您可能会考虑在以后的尾数上有点篡改(以获得您期望的单元格中的整数值),但这可能是多余的。
如果你能对你的尺寸施加两种限制的力量,可能有一种巧妙的方法可以有效地从浮点中提取网格位置,避免x、y和z的部分或全部乘法、floor和%
,假设采用标准浮点表示(即这是不可移植的)。再次,分别处理正数和负数。提取指数,相应地对尾数进行位移位,然后掩盖不需要的位。当涉及数学时,优化的第一条规则是:消除除法、平方根和三角函数
逆_size=1/_gridintervalize;
..这应该只做一次,而不是每次呼叫一次
int mx = ((int)floor(position.x * inverse_size) % _gridSize);
int my = ((int)floor(position.y * inverse_size) % _gridSize);
int mz = ((int)floor(position.z * inverse_size) % _gridSize);
我还建议删除mod操作,因为这是另一个划分-如果网格大小是2的幂,则可以使用&(gridsize-1),这也将允许您删除底部的条件代码,这是另一个巨大的节约
另一方面,使用重载运算符可能会对您造成伤害。这是一个棘手的问题,所以我让您自己尝试并决定。我认为您需要查看更高的层次结构以获得真正的速度改进。也就是说,在哈希映射中存储点真的是最有效的解决方案吗?我假设您有一个矢量3阵列,即:
矢量3*点[大小][大小][大小]
其中,3D数组中的每个元素都是矢量3的数组
您使用的算法不能保证每个Vector3数组中的点均匀分布,这可能是个问题。\u GridIntervalize
中的点簇将映射到同一数组
另一种方法是使用oct树,它类似于二叉树,但每个节点有八个子节点。每个节点都需要最小/最大x/y/z值来定义节点覆盖的体积。要向树中添加值,请执行以下操作:
递归搜索树以查找可以包含点的最小节点
将点添加到节点
如果节点中的点数>节点中点数的上限
创建子节点并将点移动到子节点
如果特定轴上的值变化不大,则可能需要使用四叉树。另一种方法是使用BSPs-将世界分成两半