Как заполнить вокселы OpenVDB, которые находятся внутри заданной плоскости?
У меня есть четырехугольник, определяемый 4 (x,y,z) точками (как плоскость с ребрами). У меня есть сетка OpenVDB. Я хочу заполнить все вокселы значением 1, которые находятся внутри моего четырехугольника (включая ребра). Это возможно без установки каждого вокселя четырехугольника (ограниченной плоскости) вручную?
2 ответа
Если четыре точки строят прямоугольник, это может быть возможно с помощью
void fill(const CoordBBox& bbox, const ValueType& value, bool active = true);
функция, которая существует в Grid
-учебный класс. Невозможно преобразовать CoordBBox
для вращений вместо этого вы должны будете сделать это, изменив трансформацию сетки. С псевдокодом это может выглядеть
CoordBBox plane; // created from your points
Transform old = grid.transform();
grid.setTransform(...); // Some transformation that places the grid correctly with respect to the plane
grid.fill(plane, 1);
grid.setTransform(old);
Если это не так, вам придется установить значения самостоятельно.
Существует неоптимизированный метод, для плоских четырехугольников произвольной формы вам нужно ввести только четыре вершины трехмерной пространственной плоскости, а на выходе будут заполнены плоские воксели.
- Получите вершину с наибольшей суммой смежных сторон как A, соседними вершинами A являются B и D, и получите координаты вокселя и номера вокселей между AB и AD на основе raycast, и, кроме того, вершины CB и CD постепенно сэмплировать такое же количество вокселей.
- Установите взаимно однозначное соответствие между вокселями, смежными с двумя вершинами A и D выше, и заполните область плоскости на основе raycast.
void VDBVolume::fillPlaneVoxel(const PlanarEquation& planar) {
auto accessor = volume_->getUnsafeAccessor();
const auto transform = volume_->transform();
const openvdb::Vec3f vdbnormal(planar.normal.x(), planar.normal.y(), planar.normal.z());
int longside_vtx[2];
calVtxLongSide(planar.vtx, longside_vtx);
// 1. ray cast long side
std::vector<Eigen::Vector3f> longsidepoints;
int neiborvtx[2];
{
const Eigen::Vector3f origin = planar.vtx[longside_vtx[0]];
const openvdb::Vec3R eye(origin.x(), origin.y(), origin.z());
GetRectNeiborVtx(longside_vtx[0], neiborvtx);
for(int i = 0; i < 2; ++i) {
Eigen::Vector3f direction = planar.vtx[neiborvtx[i]] - origin;
openvdb::Vec3R dir(direction.x(), direction.y(), direction.z());
dir.normalize();
const float length = static_cast<float>(direction.norm());
if(length > 50.f) {
std::cout << "GetRectNeiborVtx length to large, something wrong: "<< i << "\n" << origin.transpose() << "\n"
<< planar.vtx[neiborvtx[i]].transpose() << std::endl;
continue;
}
const float t0 = -voxel_size_/2;
const float t1 = length + voxel_size_/2;
const auto ray = openvdb::math::Ray<float>(eye, dir, t0, t1).worldToIndex(*volume_);
openvdb::math::DDA<decltype(ray)> dda(ray);
do {
const auto voxel = dda.voxel();
const auto voxel_center_world = GetVoxelCenter(voxel, transform);
longsidepoints.emplace_back(voxel_center_world);
} while (dda.step());
}
}
// 2. 在小边均匀采样相同数目点
const int longsidepointnum = longsidepoints.size();
std::vector<Eigen::Vector3f> shortsidepoints;
shortsidepoints.resize(longsidepointnum);
{
// 输入:顶点、两邻接点,vtxs, 输出采样带年坐标,根据距离进行采样
GenerateShortSidePoints(longside_vtx[1], neiborvtx, planar.vtx, shortsidepoints);
}
// 3. ray cast from longsidepoints to shortsidepoints
// std::cout << "longsidepointnum: " << longsidepointnum << std::endl;
for(int pid = 0; pid < longsidepointnum; ++pid) {
const Eigen::Vector3f origin = longsidepoints[pid];
const openvdb::Vec3R eye(origin.x(), origin.y(), origin.z());
const Eigen::Vector3f direction = shortsidepoints[pid] - origin;
openvdb::Vec3R dir(direction.x(), direction.y(), direction.z());
dir.normalize();
const float length = direction.norm();
if(length > 50.f) {
std::cout << "length to large, something wrong: "<< pid << "\n" << origin.transpose() << "\n"
<< shortsidepoints[pid].transpose() << std::endl;
continue;
}
const float t0 = -voxel_size_/2;
const float t1 = length + voxel_size_/2;
const auto ray = openvdb::math::Ray<float>(eye, dir, t0, t1).worldToIndex(*volume_);
openvdb::math::DDA<decltype(ray)> dda(ray);
do {
const auto voxel = dda.voxel();
accessor.setValue(voxel, vdbnormal);
} while (dda.step());
}
}