背景:
在三维模型深度处理的时候,有时候需要对模型进行区域划分.并赋予一定的材质,力学等属性,所以,需要对模型进行划分.
目前的模型体素化的方式基本分为cpu,gpu,都是投影射线法进行的, 在调研了一些已知的开源算法和项目,并测试后发现,大部分的开源项目也都是基于抽壳进行的计算,并不满足自己项目(岩土,GIS)等方面的要求,所以这里自己按照已有的理论,进行了修改,从而做了一个空间内部填充的全体素化,而且后续也方便进行不规则体素的操作.里面使用了bsvtree进行加速处理.
结果:
改两个参数:的效果.
计算时间加长了一点,不过很多细节保留了下来
换个模型试一下:
实现过程以及关键代码:
计算流程:
1.实现流程,求解模型的OBB盒子,按照其最大面积那个面,按照sizeX,sizeY进行拆分.
2.计算一系列等距射线,构建bsvTree进行模型结构化,进行快速求交,
3.获取交点后,处理交点为1和>1的多种情况,按照射线法向,进行距离迭代插值判定,依据奇偶规则进行区分内外盒子.到此,模型内外以及壳表面区分完成,进行体素绘制;
关键代码:
mDimStartZ = 0;
int GetInterCheckFirst = 0;//我们获取当前的.
double threoldValue = gridSizePerDim[2] / 2.0;//阈值.
/// <summary>
/// 获取尺寸数据.
/// </summary>
SigleT defalutData;
defalutData.zL = 0;
defalutData.isStatus = false;
auto GetInterData = [&](int index)-> decltype(&interSectListL[0]) {
if (index < interSectListL.size())
{
return &interSectListL[index];
}
else
{
return nullptr;
}
};
SigleT*firstCheckData = nullptr;//获取第一个值.
SigleT*secondChckData = nullptr;
//全部体素,第三个循环
bool isOpenAddStatus = false;
while (mDimStartZ < ZLength)
{
firstCheckData = GetInterData(GetInterCheckFirst);
if (firstCheckData == nullptr)
{
mDimStartZ += gridSizePerDim[2];
continue;
}
CurP[0] = FaceStartPoint[0] + mDimStartX;
CurP[1] = FaceStartPoint[1] + mDimStartY;
CurP[2] = FaceStartPoint[2] + mDimStartZ;
if (intersecCount == 1)
{
CurP[2] = FaceStartPoint[2]+ firstCheckData->zL;
AddVoxelDatas(CurP.GetData());//创建.
break;
}
else
{
secondChckData = GetInterData(GetInterCheckFirst + 1);
if (secondChckData == nullptr)
{
mDimStartZ += gridSizePerDim[2];
continue;
}
double firstDiffer = mDimStartZ - firstCheckData->zL;//取负数
double secondDiffer = mDimStartZ - secondChckData->zL;
double absValue = std::abs(firstDiffer);
if (absValue < threoldValue)//横切边界.
{
AddVoxelDatas(CurP.GetData());
isOpenAddStatus = true;//激活.
}
else //填充.
{
if (isOpenAddStatus == true)
{
AddVoxelDatas(CurP.GetData());
}
}
if (secondDiffer > 0)//奇偶变换.
{
GetInterCheckFirst++;
isOpenAddStatus = false;//每次变换,关闭,直到下一次循环激活为止.
}
}
mDimStartZ += gridSizePerDim[2];
}
到此,任意模型体素化代码完成.