Skip to content

Instantly share code, notes, and snippets.

@cgmb
Created December 21, 2018 07:38
Show Gist options
  • Save cgmb/6e0aabf45584a74b56114cd7405932d1 to your computer and use it in GitHub Desktop.
Save cgmb/6e0aabf45584a74b56114cd7405932d1 to your computer and use it in GitHub Desktop.
OpenVDB particles to mesh example
#include "opengl/extract_mesh.h"
#include "opengl/mesh.h"
#include <openvdb/openvdb.h>
#include <openvdb/tools/ParticlesToLevelSet.h>
#include <openvdb/tools/VolumeToMesh.h>
#include <openvdb/tools/LevelSetFilter.h>
static openvdb::Vec3R to_ovdb(const vec3f& p) {
return {p.x, p.y, p.z};
}
static vec3f to_vec3f(const openvdb::Vec3s& p) {
return {p[0], p[1], p[2]};
}
// An adaptor so OpenVDB can access my particle positions
class OvdbParticleList {
public:
using PosType = openvdb::Vec3R;
using value_type = openvdb::Vec3R;
explicit OvdbParticleList(absl::Span<const vec3f> positions)
: positions_(positions) {
}
size_t size() const { return positions_.size(); }
void getPos(size_t n, PosType& xyz) const {
xyz = to_ovdb(positions_[n]);
}
private:
const absl::Span<const vec3f> positions_;
};
// transform container
static void to_vec_vec3f(std::vector<vec3f>& to, const std::vector<openvdb::Vec3s>& from) {
to.resize(from.size());
std::transform(from.begin(), from.end(), to.begin(), to_vec3f);
}
// transform and flatten container
static void to_vec_4uint(std::vector<unsigned int>& to, const std::vector<openvdb::Vec4I>& from) {
to.resize(4*from.size());
size_t i = 0;
for (const openvdb::Vec4I& qi : from) {
to[i++] = qi[0];
to[i++] = qi[1];
to[i++] = qi[2];
to[i++] = qi[3];
}
}
static QuadMesh create_mesh(const std::vector<openvdb::Vec3s>& vertexes,
const std::vector<openvdb::Vec4I>& indexes) {
QuadMesh m;
to_vec_vec3f(m.vertexes, vertexes);
to_vec_4uint(m.indexes, indexes);
return m;
}
QuadMesh extract_mesh(absl::Span<const vec3f> positions) {
// intialize openvdb
static bool is_initialized = false;
if (!is_initialized) {
openvdb::initialize();
}
// generate our level set from our particles
constexpr float voxel_size = 1.f;
constexpr float half_width = 2.f;
openvdb::FloatGrid::Ptr levelset = openvdb::createLevelSet<openvdb::FloatGrid>(voxel_size, half_width);
openvdb::tools::ParticlesToLevelSet<openvdb::FloatGrid> raster(*levelset);
float radius = 2.f;
raster.setGrainSize(1); // passing 0 disables threading
OvdbParticleList particle_list(positions);
raster.rasterizeSpheres(particle_list, radius);
raster.finalize();
// filter the level set
openvdb::tools::LevelSetFilter<openvdb::FloatGrid> filter(*levelset);
filter.dilate(1);
filter.gaussian(1);
filter.erode(1);
// turn our levelset into a polygonal mesh
constexpr double isovalue = 0;
std::vector<openvdb::Vec3s> vertexes;
std::vector<openvdb::Vec4I> quad_indexes;
/*
There's apparently an adaptive volumeToMesh in newer versions of openvdb, which could be interesting.
constexpr double adaptivity = 0;
constexpr bool relax_distorted_triangles = true;
std::vector<openvdb::Vec3I> triangle_indexes;
openvdb::tools::volumeToMesh(*levelset, vertexes, triangle_indexes, quad_indexes, isovalue, adaptivity, relax_distorted_trianges);
*/
openvdb::tools::volumeToMesh(*levelset, vertexes, quad_indexes, isovalue);
return create_mesh(vertexes, quad_indexes);
}
#pragma once
#include <absl/types/span.h>
#include "math/vec3f.h"
struct QuadMesh;
QuadMesh extract_mesh(absl::Span<const vec3f> positions);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment