OpenVDB: mesh/level set conversion, filters and CSG operations

This code is needed to implement the Voxel Remesher as well as other features like a better remesh modifier with filters and CSG operations.

Done by Martin Felke and Pablo Dobarro

Reviewed By: brecht

Differential Revision: https://developer.blender.org/D5364
master
Pablo Dobarro 5 years ago
parent 5ca5357e08
commit 9ac3964be1

@ -21,6 +21,7 @@
set(INC
.
intern
../guardedalloc
)
set(INC_SYS
@ -56,12 +57,16 @@ if(WITH_OPENVDB)
intern/openvdb_dense_convert.cc
intern/openvdb_reader.cc
intern/openvdb_writer.cc
intern/openvdb_level_set.cc
intern/openvdb_transform.cc
openvdb_capi.cc
openvdb_util.cc
intern/openvdb_dense_convert.h
intern/openvdb_reader.h
intern/openvdb_writer.h
intern/openvdb_level_set.h
intern/openvdb_transform.h
openvdb_util.h
)

@ -0,0 +1,176 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2015 Blender Foundation.
* All rights reserved.
*/
#include "openvdb_level_set.h"
#include "openvdb_util.h"
#include "openvdb_capi.h"
#include "MEM_guardedalloc.h"
#include "openvdb/tools/Composite.h"
OpenVDBLevelSet::OpenVDBLevelSet()
{
openvdb::initialize();
}
OpenVDBLevelSet::~OpenVDBLevelSet()
{
}
void OpenVDBLevelSet::mesh_to_level_set(const float *vertices,
const unsigned int *faces,
const unsigned int totvertices,
const unsigned int totfaces,
const openvdb::math::Transform::Ptr &xform)
{
std::vector<openvdb::Vec3s> points(totvertices);
std::vector<openvdb::Vec3I> triangles(totfaces);
std::vector<openvdb::Vec4I> quads;
for (unsigned int i = 0; i < totvertices; i++) {
points[i] = openvdb::Vec3s(vertices[i * 3], vertices[i * 3 + 1], vertices[i * 3 + 2]);
}
for (unsigned int i = 0; i < totfaces; i++) {
triangles[i] = openvdb::Vec3I(faces[i * 3], faces[i * 3 + 1], faces[i * 3 + 2]);
}
this->grid = openvdb::tools::meshToLevelSet<openvdb::FloatGrid>(
*xform, points, triangles, quads, 1);
}
void OpenVDBLevelSet::volume_to_mesh(OpenVDBVolumeToMeshData *mesh,
const double isovalue,
const double adaptivity,
const bool relax_disoriented_triangles)
{
std::vector<openvdb::Vec3s> out_points;
std::vector<openvdb::Vec4I> out_quads;
std::vector<openvdb::Vec3I> out_tris;
openvdb::tools::volumeToMesh<openvdb::FloatGrid>(*this->grid,
out_points,
out_tris,
out_quads,
isovalue,
adaptivity,
relax_disoriented_triangles);
mesh->vertices = (float *)MEM_malloc_arrayN(
out_points.size(), 3 * sizeof(float), "openvdb remesher out verts");
mesh->quads = (unsigned int *)MEM_malloc_arrayN(
out_quads.size(), 4 * sizeof(unsigned int), "openvdb remesh out quads");
mesh->triangles = NULL;
if (out_tris.size() > 0) {
mesh->triangles = (unsigned int *)MEM_malloc_arrayN(
out_tris.size(), 3 * sizeof(unsigned int), "openvdb remesh out tris");
}
mesh->totvertices = out_points.size();
mesh->tottriangles = out_tris.size();
mesh->totquads = out_quads.size();
for (size_t i = 0; i < out_points.size(); i++) {
mesh->vertices[i * 3] = out_points[i].x();
mesh->vertices[i * 3 + 1] = out_points[i].y();
mesh->vertices[i * 3 + 2] = out_points[i].z();
}
for (size_t i = 0; i < out_quads.size(); i++) {
mesh->quads[i * 4] = out_quads[i].x();
mesh->quads[i * 4 + 1] = out_quads[i].y();
mesh->quads[i * 4 + 2] = out_quads[i].z();
mesh->quads[i * 4 + 3] = out_quads[i].w();
}
for (size_t i = 0; i < out_tris.size(); i++) {
mesh->triangles[i * 3] = out_tris[i].x();
mesh->triangles[i * 3 + 1] = out_tris[i].y();
mesh->triangles[i * 3 + 2] = out_tris[i].z();
}
}
void OpenVDBLevelSet::filter(OpenVDBLevelSet_FilterType filter_type,
int width,
float distance,
OpenVDBLevelSet_FilterBias filter_bias)
{
if (!this->grid) {
return;
}
if (this->grid->getGridClass() != openvdb::GRID_LEVEL_SET) {
return;
}
openvdb::tools::LevelSetFilter<openvdb::FloatGrid> filter(*this->grid);
filter.setSpatialScheme((openvdb::math::BiasedGradientScheme)filter_bias);
switch (filter_type) {
case OPENVDB_LEVELSET_FILTER_GAUSSIAN:
filter.gaussian(width);
break;
case OPENVDB_LEVELSET_FILTER_MEDIAN:
filter.median(width);
break;
case OPENVDB_LEVELSET_FILTER_MEAN:
filter.mean(width);
break;
case OPENVDB_LEVELSET_FILTER_MEAN_CURVATURE:
filter.meanCurvature();
break;
case OPENVDB_LEVELSET_FILTER_LAPLACIAN:
filter.laplacian();
break;
case OPENVDB_LEVELSET_FILTER_DILATE:
filter.offset(distance);
break;
case OPENVDB_LEVELSET_FILTER_ERODE:
filter.offset(distance);
break;
case OPENVDB_LEVELSET_FILTER_NONE:
break;
}
}
openvdb::FloatGrid::Ptr OpenVDBLevelSet::CSG_operation_apply(
const openvdb::FloatGrid::Ptr &gridA,
const openvdb::FloatGrid::Ptr &gridB,
OpenVDBLevelSet_CSGOperation operation)
{
switch (operation) {
case OPENVDB_LEVELSET_CSG_UNION:
openvdb::tools::csgUnion(*gridA, *gridB);
break;
case OPENVDB_LEVELSET_CSG_DIFFERENCE:
openvdb::tools::csgDifference(*gridA, *gridB);
break;
case OPENVDB_LEVELSET_CSG_INTERSECTION:
openvdb::tools::csgIntersection(*gridA, *gridB);
break;
}
return gridA;
}
const openvdb::FloatGrid::Ptr &OpenVDBLevelSet::get_grid()
{
return this->grid;
}
void OpenVDBLevelSet::set_grid(const openvdb::FloatGrid::Ptr &grid)
{
this->grid = grid;
}

@ -0,0 +1,60 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2015 Blender Foundation.
* All rights reserved.
*/
#ifndef __OPENVDB_LEVEL_SET_H__
#define __OPENVDB_LEVEL_SET_H__
#include <openvdb/openvdb.h>
#include <openvdb/math/FiniteDifference.h>
#include <openvdb/tools/MeshToVolume.h>
#include <openvdb/tools/VolumeToMesh.h>
#include <openvdb/tools/LevelSetFilter.h>
#include <openvdb/tools/GridTransformer.h>
#include "openvdb_capi.h"
struct OpenVDBLevelSet {
private:
openvdb::FloatGrid::Ptr grid;
public:
OpenVDBLevelSet();
~OpenVDBLevelSet();
const openvdb::FloatGrid::Ptr &get_grid();
void set_grid(const openvdb::FloatGrid::Ptr &grid);
void mesh_to_level_set(const float *vertices,
const unsigned int *faces,
const unsigned int totvertices,
const unsigned int totfaces,
const openvdb::math::Transform::Ptr &transform);
void volume_to_mesh(struct OpenVDBVolumeToMeshData *mesh,
const double isovalue,
const double adaptivity,
const bool relax_disoriented_triangles);
void filter(OpenVDBLevelSet_FilterType filter_type,
int width,
float distance,
OpenVDBLevelSet_FilterBias filter_bias);
openvdb::FloatGrid::Ptr CSG_operation_apply(const openvdb::FloatGrid::Ptr &gridA,
const openvdb::FloatGrid::Ptr &gridB,
OpenVDBLevelSet_CSGOperation operation);
};
#endif /* __OPENVDB_LEVEL_SET_H__ */

@ -0,0 +1,43 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2015 Blender Foundation.
* All rights reserved.
*/
#include "openvdb_transform.h"
OpenVDBTransform::OpenVDBTransform()
{
}
OpenVDBTransform::~OpenVDBTransform()
{
}
void OpenVDBTransform::create_linear_transform(double voxel_size)
{
this->transform = openvdb::math::Transform::createLinearTransform(voxel_size);
}
const openvdb::math::Transform::Ptr &OpenVDBTransform::get_transform()
{
return this->transform;
}
void OpenVDBTransform::set_transform(const openvdb::math::Transform::Ptr &transform)
{
this->transform = transform;
}

@ -0,0 +1,37 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2015 Blender Foundation.
* All rights reserved.
*/
#ifndef OPENVDB_TRANSFORM_H
#define OPENVDB_TRANSFORM_H
#include <openvdb/openvdb.h>
struct OpenVDBTransform {
private:
openvdb::math::Transform::Ptr transform;
public:
OpenVDBTransform();
~OpenVDBTransform();
void create_linear_transform(double voxel_size);
const openvdb::math::Transform::Ptr &get_transform();
void set_transform(const openvdb::math::Transform::Ptr &transform);
};
#endif // OPENVDB_TRANSFORM_H

@ -20,16 +20,8 @@
#include "openvdb_capi.h"
#include "openvdb_dense_convert.h"
#include "openvdb_util.h"
struct OpenVDBFloatGrid {
int unused;
};
struct OpenVDBIntGrid {
int unused;
};
struct OpenVDBVectorGrid {
int unused;
};
#include "openvdb_level_set.h"
#include "openvdb_transform.h"
int OpenVDB_getVersionHex()
{
@ -238,3 +230,143 @@ void OpenVDBReader_get_meta_mat4(OpenVDBReader *reader, const char *name, float
{
reader->mat4sMeta(name, value);
}
OpenVDBLevelSet *OpenVDBLevelSet_create(bool initGrid, OpenVDBTransform *xform)
{
OpenVDBLevelSet *level_set = new OpenVDBLevelSet();
if (initGrid) {
openvdb::FloatGrid::Ptr grid = openvdb::FloatGrid::create();
grid->setGridClass(openvdb::GRID_LEVEL_SET);
if (xform) {
grid->setTransform(xform->get_transform());
}
level_set->set_grid(grid);
}
return level_set;
}
OpenVDBTransform *OpenVDBTransform_create()
{
return new OpenVDBTransform();
}
void OpenVDBTransform_free(OpenVDBTransform *transform)
{
delete transform;
}
void OpenVDBTransform_create_linear_transform(OpenVDBTransform *transform, double voxel_size)
{
transform->create_linear_transform(voxel_size);
}
void OpenVDBLevelSet_free(OpenVDBLevelSet *level_set)
{
delete level_set;
}
void OpenVDBLevelSet_mesh_to_level_set(struct OpenVDBLevelSet *level_set,
const float *vertices,
const unsigned int *faces,
const unsigned int totvertices,
const unsigned int totfaces,
OpenVDBTransform *xform)
{
level_set->mesh_to_level_set(vertices, faces, totvertices, totfaces, xform->get_transform());
}
void OpenVDBLevelSet_mesh_to_level_set_transform(struct OpenVDBLevelSet *level_set,
const float *vertices,
const unsigned int *faces,
const unsigned int totvertices,
const unsigned int totfaces,
OpenVDBTransform *transform)
{
level_set->mesh_to_level_set(vertices, faces, totvertices, totfaces, transform->get_transform());
}
void OpenVDBLevelSet_volume_to_mesh(struct OpenVDBLevelSet *level_set,
struct OpenVDBVolumeToMeshData *mesh,
const double isovalue,
const double adaptivity,
const bool relax_disoriented_triangles)
{
level_set->volume_to_mesh(mesh, isovalue, adaptivity, relax_disoriented_triangles);
}
void OpenVDBLevelSet_filter(struct OpenVDBLevelSet *level_set,
OpenVDBLevelSet_FilterType filter_type,
int width,
float distance,
OpenVDBLevelSet_FilterBias bias)
{
level_set->filter(filter_type, width, distance, bias);
}
void OpenVDBLevelSet_CSG_operation(struct OpenVDBLevelSet *out,
struct OpenVDBLevelSet *gridA,
struct OpenVDBLevelSet *gridB,
OpenVDBLevelSet_CSGOperation operation)
{
openvdb::FloatGrid::Ptr grid = out->CSG_operation_apply(
gridA->get_grid(), gridB->get_grid(), operation);
out->set_grid(grid);
}
OpenVDBLevelSet *OpenVDBLevelSet_transform_and_resample(struct OpenVDBLevelSet *level_setA,
struct OpenVDBLevelSet *level_setB,
char sampler,
float isolevel)
{
openvdb::FloatGrid::Ptr sourceGrid = level_setA->get_grid();
openvdb::FloatGrid::Ptr targetGrid = level_setB->get_grid()->deepCopy();
const openvdb::math::Transform &sourceXform = sourceGrid->transform(),
&targetXform = targetGrid->transform();
// Compute a source grid to target grid transform.
// (For this example, we assume that both grids' transforms are linear,
// so that they can be represented as 4 x 4 matrices.)
openvdb::Mat4R xform = sourceXform.baseMap()->getAffineMap()->getMat4() *
targetXform.baseMap()->getAffineMap()->getMat4().inverse();
// Create the transformer.
openvdb::tools::GridTransformer transformer(xform);
switch (sampler) {
case OPENVDB_LEVELSET_GRIDSAMPLER_POINT:
// Resample using nearest-neighbor interpolation.
transformer.transformGrid<openvdb::tools::PointSampler, openvdb::FloatGrid>(*sourceGrid,
*targetGrid);
// Prune the target tree for optimal sparsity.
targetGrid->tree().prune();
break;
case OPENVDB_LEVELSET_GRIDSAMPLER_BOX:
// Resample using trilinear interpolation.
transformer.transformGrid<openvdb::tools::BoxSampler, openvdb::FloatGrid>(*sourceGrid,
*targetGrid);
// Prune the target tree for optimal sparsity.
targetGrid->tree().prune();
break;
case OPENVDB_LEVELSET_GRIDSAMPLER_QUADRATIC:
// Resample using triquadratic interpolation.
transformer.transformGrid<openvdb::tools::QuadraticSampler, openvdb::FloatGrid>(*sourceGrid,
*targetGrid);
// Prune the target tree for optimal sparsity.
targetGrid->tree().prune();
break;
case OPENVDB_LEVELSET_GRIDSAMPLER_NONE:
break;
}
targetGrid = openvdb::tools::levelSetRebuild(*targetGrid, isolevel, 1.0f);
openvdb::tools::pruneLevelSet(targetGrid->tree());
OpenVDBLevelSet *level_set = OpenVDBLevelSet_create(false, NULL);
level_set->set_grid(targetGrid);
return level_set;
}

@ -24,12 +24,80 @@
extern "C" {
#endif
/* Level Set Filters */
typedef enum OpenVDBLevelSet_FilterType {
OPENVDB_LEVELSET_FILTER_NONE = 0,
OPENVDB_LEVELSET_FILTER_GAUSSIAN = 1,
OPENVDB_LEVELSET_FILTER_MEAN = 2,
OPENVDB_LEVELSET_FILTER_MEDIAN = 3,
OPENVDB_LEVELSET_FILTER_MEAN_CURVATURE = 4,
OPENVDB_LEVELSET_FILTER_LAPLACIAN = 5,
OPENVDB_LEVELSET_FILTER_DILATE = 6,
OPENVDB_LEVELSET_FILTER_ERODE = 7,
} OpenVDBLevelSet_FilterType;
typedef enum OpenVDBLevelSet_FilterBias {
OPENVDB_LEVELSET_FIRST_BIAS = 0,
OPENVDB_LEVELSET_SECOND_BIAS,
OPENVDB_LEVELSET_THIRD_BIAS,
OPENVDB_LEVELSET_WENO5_BIAS,
OPENVDB_LEVELSET_HJWENO5_BIAS,
} OpenVDBLevelSet_FilterBias;
/* Level Set CSG Operations */
typedef enum OpenVDBLevelSet_CSGOperation {
OPENVDB_LEVELSET_CSG_UNION = 0,
OPENVDB_LEVELSET_CSG_DIFFERENCE = 1,
OPENVDB_LEVELSET_CSG_INTERSECTION = 2,
} OpenVDBLevelSet_CSGOperation;
typedef enum OpenVDBLevelSet_GridSampler {
OPENVDB_LEVELSET_GRIDSAMPLER_NONE = 0,
OPENVDB_LEVELSET_GRIDSAMPLER_POINT = 1,
OPENVDB_LEVELSET_GRIDSAMPLER_BOX = 2,
OPENVDB_LEVELSET_GRIDSAMPLER_QUADRATIC = 3,
} OpenVDBLevelSet_Gridsampler;
struct OpenVDBReader;
struct OpenVDBWriter;
struct OpenVDBTransform;
struct OpenVDBLevelSet;
struct OpenVDBFloatGrid;
struct OpenVDBIntGrid;
struct OpenVDBVectorGrid;
struct OpenVDBVolumeToMeshData {
int tottriangles;
int totquads;
int totvertices;
float *vertices;
unsigned int *quads;
unsigned int *triangles;
};
struct OpenVDBRemeshData {
float *verts;
unsigned int *faces;
int totfaces;
int totverts;
float *out_verts;
unsigned int *out_faces;
unsigned int *out_tris;
int out_totverts;
int out_totfaces;
int out_tottris;
int filter_type;
enum OpenVDBLevelSet_FilterType filter_bias;
enum OpenVDBLevelSet_FilterBias filter_width; /* Parameter for gaussian, median, mean*/
float voxel_size;
float isovalue;
float adaptivity;
int relax_disoriented_triangles;
};
int OpenVDB_getVersionHex(void);
enum {
@ -112,6 +180,45 @@ void OpenVDBReader_get_meta_mat4(struct OpenVDBReader *reader,
const char *name,
float value[4][4]);
struct OpenVDBTransform *OpenVDBTransform_create(void);
void OpenVDBTransform_free(struct OpenVDBTransform *transform);
void OpenVDBTransform_create_linear_transform(struct OpenVDBTransform *transform,
double voxel_size);
struct OpenVDBLevelSet *OpenVDBLevelSet_create(bool initGrid, struct OpenVDBTransform *xform);
void OpenVDBLevelSet_free(struct OpenVDBLevelSet *level_set);
void OpenVDBLevelSet_mesh_to_level_set(struct OpenVDBLevelSet *level_set,
const float *vertices,
const unsigned int *faces,
const unsigned int totvertices,
const unsigned int totfaces,
struct OpenVDBTransform *xform);
void OpenVDBLevelSet_mesh_to_level_set_transform(struct OpenVDBLevelSet *level_set,
const float *vertices,
const unsigned int *faces,
const unsigned int totvertices,
const unsigned int totfaces,
struct OpenVDBTransform *transform);
void OpenVDBLevelSet_volume_to_mesh(struct OpenVDBLevelSet *level_set,
struct OpenVDBVolumeToMeshData *mesh,
const double isovalue,
const double adaptivity,
const bool relax_disoriented_triangles);
void OpenVDBLevelSet_filter(struct OpenVDBLevelSet *level_set,
OpenVDBLevelSet_FilterType filter_type,
int width,
float distance,
OpenVDBLevelSet_FilterBias bias);
void OpenVDBLevelSet_CSG_operation(struct OpenVDBLevelSet *out,
struct OpenVDBLevelSet *gridA,
struct OpenVDBLevelSet *gridB,
OpenVDBLevelSet_CSGOperation operation);
struct OpenVDBLevelSet *OpenVDBLevelSet_transform_and_resample(struct OpenVDBLevelSet *level_setA,
struct OpenVDBLevelSet *level_setB,
char sampler,
float isolevel);
#ifdef __cplusplus
}
#endif

Loading…
Cancel
Save