Как заполнить вокселы 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);

Если это не так, вам придется установить значения самостоятельно.

Существует неоптимизированный метод, для плоских четырехугольников произвольной формы вам нужно ввести только четыре вершины трехмерной пространственной плоскости, а на выходе будут заполнены плоские воксели.

  1. Получите вершину с наибольшей суммой смежных сторон как A, соседними вершинами A являются B и D, и получите координаты вокселя и номера вокселей между AB и AD на основе raycast, и, кроме того, вершины CB и CD постепенно сэмплировать такое же количество вокселей.
  2. Установите взаимно однозначное соответствие между вокселями, смежными с двумя вершинами 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());
  }
}
Другие вопросы по тегам