1
1

Compare commits

...

15 Commits

Author SHA1 Message Date
6da9286cc8 warning when compiled without openvdb 2020-09-28 13:31:27 +02:00
4803466c01 only allow mesh objects for now 2020-09-28 13:31:15 +02:00
f798a6c679 add todo comment 2020-09-28 13:18:20 +02:00
6501b05118 cleanup 2020-09-28 13:03:42 +02:00
aad5a79a94 cleanup 2020-09-28 13:00:41 +02:00
2629cf12f5 remove different modes 2020-09-28 12:39:04 +02:00
d525a541a2 Merge branch 'master' into mesh-to-volume-modifier 2020-09-28 12:30:39 +02:00
e204f67cf0 Merge branch 'master' into mesh-to-volume-modifier 2020-09-25 12:54:52 +02:00
d8d1344d96 cleanup and comments 2020-09-25 12:31:35 +02:00
9cbc874062 support different modes of operation 2020-09-24 15:32:27 +02:00
0e9e472bbe expose interior/exterior bandwidth properties 2020-09-24 14:01:50 +02:00
95e34d2ebf Volume: use meshToVolume for conversion 2020-09-24 13:35:22 +02:00
11f79038e1 Merge branch 'master' into mesh-to-volume-modifier 2020-09-24 12:01:55 +02:00
076c913a3b Volume: initial mesh to volume modifier implementation
Using `openvdb::tools::meshToLevelSet` is probably not correct.
I will look into `meshToVolume` next.
2020-09-23 17:15:18 +02:00
c5fca660bc Volume: add boilerplate code for Mesh To Volume modifier 2020-09-23 15:36:14 +02:00
8 changed files with 436 additions and 0 deletions

View File

@@ -157,4 +157,16 @@ openvdb::GridBase::ConstPtr BKE_volume_grid_openvdb_for_read(const struct Volume
openvdb::GridBase::Ptr BKE_volume_grid_openvdb_for_write(const struct Volume *volume,
struct VolumeGrid *grid,
const bool clear);
template<typename GridType>
typename GridType::Ptr BKE_volume_grid_openvdb_for_write(const struct Volume *volume,
struct VolumeGrid *grid,
const bool clear)
{
openvdb::GridBase::Ptr openvdb_grid = BKE_volume_grid_openvdb_for_write(volume, grid, clear);
BLI_assert(openvdb_grid->isType<GridType>());
typename GridType::Ptr typed_openvdb_grid = openvdb::gridPtrCast<GridType>(openvdb_grid);
return typed_openvdb_grid;
}
#endif

View File

@@ -95,6 +95,7 @@ typedef enum ModifierType {
eModifierType_Weld = 55,
eModifierType_Fluid = 56,
eModifierType_Simulation = 57,
eModifierType_MeshToVolume = 58,
NUM_MODIFIER_TYPES,
} ModifierType;
@@ -2208,6 +2209,36 @@ typedef struct SimulationModifierData {
char *data_path;
} SimulationModifierData;
typedef struct MeshToVolumeModifierData {
ModifierData modifier;
/** This is the object that is supposed to be converted to a volume. */
struct Object *object;
/** MeshToVolumeModifierResolutionMode */
int resolution_mode;
/** Size of a voxel in object space. */
float voxel_size;
/** The desired amount of voxels along one axis. The actual amount of voxels might be slightly
* different. */
int voxel_amount;
/** If true, every cell in the enclosed volume gets a density. Otherwise, the interior_bandwidth
* is used. */
char fill_volume;
char _pad1[3];
/** Bandwidths are in object space. */
float interior_bandwidth;
float exterior_bandwidth;
} MeshToVolumeModifierData;
/* MeshToVolumeModifierData->resolution_mode */
typedef enum MeshToVolumeModifierResolutionMode {
MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_AMOUNT = 0,
MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_SIZE = 1,
} MeshToVolumeModifierResolutionMode;
#ifdef __cplusplus
}
#endif

View File

@@ -389,6 +389,7 @@ extern StructRNA RNA_MaterialSlot;
extern StructRNA RNA_Menu;
extern StructRNA RNA_Mesh;
extern StructRNA RNA_MeshCacheModifier;
extern StructRNA RNA_MeshToVolumeModifier;
extern StructRNA RNA_MeshColor;
extern StructRNA RNA_MeshDeformModifier;
extern StructRNA RNA_MeshEdge;

View File

@@ -193,6 +193,11 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = {
ICON_MOD_WIREFRAME,
"Wireframe",
"Convert faces into thickened edges"},
{eModifierType_MeshToVolume,
"MESH_TO_VOLUME",
ICON_VOLUME_DATA,
"Mesh to Volume",
""}, /* TODO: Use correct icon. */
{0, "", 0, N_("Deform"), ""},
{eModifierType_Armature,
"ARMATURE",
@@ -6973,6 +6978,73 @@ static void rna_def_modifier_simulation(BlenderRNA *brna)
}
# endif
static void rna_def_modifier_mesh_to_volume(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
static EnumPropertyItem resolution_mode_items[] = {
{MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_AMOUNT,
"VOXEL_AMOUNT",
0,
"Voxel Amount",
"Specify the desired number of voxels along one axis"},
{MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_SIZE,
"VOXEL_SIZE",
0,
"Voxel Size",
"Specify the desired voxel side length"},
{0, NULL, 0, NULL, NULL},
};
srna = RNA_def_struct(brna, "MeshToVolumeModifier", "Modifier");
RNA_def_struct_ui_text(srna, "Mesh to Volume Modifier", "");
RNA_def_struct_sdna(srna, "MeshToVolumeModifierData");
RNA_def_struct_ui_icon(srna, ICON_VOLUME_DATA); /* TODO: Use correct icon. */
RNA_define_lib_overridable(true);
prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
RNA_def_property_ui_text(prop, "Object", "Object");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Mesh_object_poll");
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "resolution_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, resolution_mode_items);
RNA_def_property_ui_text(
prop, "Resolution Mode", "Mode for how the desired voxel size is specified");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "voxel_size", PROP_FLOAT, PROP_NONE);
RNA_def_property_ui_text(
prop, "Voxel Size", "The smaller this number the higher the resolution of the output");
RNA_def_property_range(prop, 0.1, FLT_MAX);
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "voxel_amount", PROP_INT, PROP_NONE);
RNA_def_property_ui_text(prop, "Voxel Amount", "The desired number of voxels along one axis");
RNA_def_property_range(prop, 0, INT_MAX);
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "fill_volume", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_ui_text(
prop, "Fill Volume", "Initialize the density grid in every cell inside the enclosed volume");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "interior_bandwidth", PROP_FLOAT, PROP_NONE);
RNA_def_property_ui_text(prop, "Interior Bandwidth", "Width of the volume inside of the mesh");
RNA_def_property_range(prop, 0.0, FLT_MAX);
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "exterior_bandwidth", PROP_FLOAT, PROP_NONE);
RNA_def_property_ui_text(prop, "Exterior Bandwidth", "Width of the volume outside of the mesh");
RNA_def_property_range(prop, 0.0, FLT_MAX);
RNA_def_property_update(prop, 0, "rna_Modifier_update");
RNA_define_lib_overridable(false);
}
void RNA_def_modifier(BlenderRNA *brna)
{
StructRNA *srna;
@@ -7104,6 +7176,7 @@ void RNA_def_modifier(BlenderRNA *brna)
# ifdef WITH_PARTICLE_NODES
rna_def_modifier_simulation(brna);
# endif
rna_def_modifier_mesh_to_volume(brna);
}
#endif

View File

@@ -67,6 +67,7 @@ set(SRC
intern/MOD_laplaciansmooth.c
intern/MOD_lattice.c
intern/MOD_mask.cc
intern/MOD_mesh_to_volume.cc
intern/MOD_meshcache.c
intern/MOD_meshcache_mdd.c
intern/MOD_meshcache_pc2.c
@@ -177,6 +178,20 @@ if(WITH_GMP)
add_definitions(-DWITH_GMP)
endif()
if(WITH_OPENVDB)
list(APPEND INC
../../../intern/openvdb
)
list(APPEND INC_SYS
${OPENVDB_INCLUDE_DIRS}
)
list(APPEND LIB
bf_intern_openvdb
${OPENVDB_LIBRARIES}
)
add_definitions(-DWITH_OPENVDB ${OPENVDB_DEFINITIONS})
endif()
if(WITH_EXPERIMENTAL_FEATURES)
add_definitions(-DWITH_PARTICLE_NODES)
add_definitions(-DWITH_HAIR_NODES)

View File

@@ -86,6 +86,7 @@ extern ModifierTypeInfo modifierType_MeshSequenceCache;
extern ModifierTypeInfo modifierType_SurfaceDeform;
extern ModifierTypeInfo modifierType_WeightedNormal;
extern ModifierTypeInfo modifierType_Simulation;
extern ModifierTypeInfo modifierType_MeshToVolume;
/* MOD_util.c */
void modifier_type_init(ModifierTypeInfo *types[]);

View File

@@ -0,0 +1,302 @@
/*
* 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.
*/
/** \file
* \ingroup modifiers
*/
#include <vector>
#include "BKE_lib_query.h"
#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_volume.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
#include "DNA_volume_types.h"
#include "DEG_depsgraph_build.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "BLO_read_write.h"
#include "MEM_guardedalloc.h"
#include "MOD_modifiertypes.h"
#include "MOD_ui_common.h"
#include "BLI_float4x4.hh"
#include "BLI_index_range.hh"
#include "BLI_span.hh"
#include "RNA_access.h"
#ifdef WITH_OPENVDB
# include <openvdb/openvdb.h>
# include <openvdb/tools/MeshToVolume.h>
#endif
#ifdef WITH_OPENVDB
namespace blender {
/* This class follows the MeshDataAdapter interface from openvdb. */
class OpenVDBMeshAdapter {
private:
Span<MVert> vertices_;
Span<MLoop> loops_;
Span<MLoopTri> looptris_;
float4x4 transform_;
public:
OpenVDBMeshAdapter(Mesh &mesh, float4x4 transform)
: vertices_(mesh.mvert, mesh.totvert),
loops_(mesh.mloop, mesh.totloop),
transform_(transform)
{
const MLoopTri *looptries = BKE_mesh_runtime_looptri_ensure(&mesh);
const int looptries_len = BKE_mesh_runtime_looptri_len(&mesh);
looptris_ = Span(looptries, looptries_len);
}
size_t polygonCount() const
{
return static_cast<size_t>(looptris_.size());
}
size_t pointCount() const
{
return static_cast<size_t>(vertices_.size());
}
size_t vertexCount(size_t UNUSED(polygon_index)) const
{
/* All polygons are triangles. */
return 3;
}
void getIndexSpacePoint(size_t polygon_index, size_t vertex_index, openvdb::Vec3d &pos) const
{
const MLoopTri &looptri = looptris_[polygon_index];
const MVert &vertex = vertices_[loops_[looptri.tri[vertex_index]].v];
const float3 transformed_co = transform_ * float3(vertex.co);
pos = &transformed_co.x;
}
};
} // namespace blender
#endif
static void initData(ModifierData *md)
{
MeshToVolumeModifierData *mvmd = reinterpret_cast<MeshToVolumeModifierData *>(md);
mvmd->object = NULL;
mvmd->resolution_mode = MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_AMOUNT;
mvmd->voxel_size = 0.1f;
mvmd->voxel_amount = 32;
mvmd->fill_volume = true;
mvmd->interior_bandwidth = 0.1f;
mvmd->exterior_bandwidth = 0.1f;
}
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
MeshToVolumeModifierData *mvmd = reinterpret_cast<MeshToVolumeModifierData *>(md);
DEG_add_modifier_to_transform_relation(ctx->node, "Mesh to Volume Modifier");
if (mvmd->object) {
DEG_add_object_relation(
ctx->node, mvmd->object, DEG_OB_COMP_GEOMETRY, "Mesh to Volume Modifier");
DEG_add_object_relation(
ctx->node, mvmd->object, DEG_OB_COMP_TRANSFORM, "Mesh to Volume Modifier");
}
}
static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData)
{
MeshToVolumeModifierData *mvmd = reinterpret_cast<MeshToVolumeModifierData *>(md);
walk(userData, ob, &mvmd->object, IDWALK_CB_NOP);
}
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
{
uiLayout *layout = panel->layout;
PointerRNA ob_ptr;
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
MeshToVolumeModifierData *mvmd = static_cast<MeshToVolumeModifierData *>(ptr->data);
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "object", 0, NULL, ICON_NONE);
{
uiLayout *col = uiLayoutColumn(layout, false);
uiItemR(col, ptr, "fill_volume", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "exterior_bandwidth", 0, NULL, ICON_NONE);
uiLayout *subcol = uiLayoutColumn(col, false);
uiLayoutSetEnabled(subcol, !mvmd->fill_volume);
uiItemR(subcol, ptr, "interior_bandwidth", 0, NULL, ICON_NONE);
}
{
uiLayout *col = uiLayoutColumn(layout, false);
uiItemR(col, ptr, "resolution_mode", 0, NULL, ICON_NONE);
if (mvmd->resolution_mode == MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_AMOUNT) {
uiItemR(col, ptr, "voxel_amount", 0, NULL, ICON_NONE);
}
else {
uiItemR(col, ptr, "voxel_size", 0, NULL, ICON_NONE);
}
}
modifier_panel_end(layout, ptr);
}
static void panelRegister(ARegionType *region_type)
{
modifier_panel_register(region_type, eModifierType_MeshToVolume, panel_draw);
}
static float compute_voxel_size(const MeshToVolumeModifierData *mvmd,
const blender::float4x4 &transform)
{
using namespace blender;
if (mvmd->resolution_mode == MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_SIZE) {
return MAX2(0.0001, mvmd->voxel_size);
}
BoundBox *bb = BKE_object_boundbox_get(mvmd->object);
float3 dimensions = float3(bb->vec[6]) - float3(bb->vec[0]);
const float3 transformed_dimensions = transform.ref_3x3() * dimensions;
const float max_dimension = std::max(
{transformed_dimensions.x, transformed_dimensions.y, transformed_dimensions.z});
const float approximate_volume_side_length = max_dimension + mvmd->exterior_bandwidth * 2.0f;
const float voxel_size = approximate_volume_side_length / MAX2(1, mvmd->voxel_amount);
return voxel_size;
}
static Volume *modifyVolume(ModifierData *md, const ModifierEvalContext *ctx, Volume *input_volume)
{
#ifdef WITH_OPENVDB
using namespace blender;
MeshToVolumeModifierData *mvmd = reinterpret_cast<MeshToVolumeModifierData *>(md);
Object *object_to_convert = mvmd->object;
if (object_to_convert == NULL) {
return input_volume;
}
/* TODO: Support other object types. */
if (object_to_convert->type != OB_MESH) {
return input_volume;
}
const float4x4 mesh_to_own_object_space_transform = float4x4(ctx->object->imat) *
float4x4(object_to_convert->obmat);
const float voxel_size = compute_voxel_size(mvmd, mesh_to_own_object_space_transform);
float4x4 mesh_to_index_space_transform;
scale_m4_fl(mesh_to_index_space_transform.values, 1.0f / voxel_size);
mul_m4_m4_post(mesh_to_index_space_transform.values, mesh_to_own_object_space_transform.values);
Mesh *mesh = static_cast<Mesh *>(object_to_convert->data);
OpenVDBMeshAdapter mesh_adapter{*mesh, mesh_to_index_space_transform};
/* Convert the bandwidths from object in index space. */
const float exterior_bandwidth = MAX2(0.001f, mvmd->exterior_bandwidth / voxel_size);
const float interior_bandwidth = MAX2(0.001f, mvmd->interior_bandwidth / voxel_size);
openvdb::FloatGrid::Ptr new_grid;
if (mvmd->fill_volume) {
/* Setting the interior bandwidth to FLT_MAX, will make it fill the entire volume. */
new_grid = openvdb::tools::meshToVolume<openvdb::FloatGrid>(
mesh_adapter, {}, exterior_bandwidth, FLT_MAX);
}
else {
new_grid = openvdb::tools::meshToVolume<openvdb::FloatGrid>(
mesh_adapter, {}, exterior_bandwidth, interior_bandwidth);
}
/* Create a new volume object and add the density grid. */
Volume *volume = BKE_volume_new_for_eval(input_volume);
VolumeGrid *c_density_grid = BKE_volume_grid_add(volume, "density", VOLUME_GRID_FLOAT);
openvdb::FloatGrid::Ptr density_grid = BKE_volume_grid_openvdb_for_write<openvdb::FloatGrid>(
volume, c_density_grid, false);
/* Merge the generated grid into the density grid. I could not figure out how to simply replace
* it yet. */
density_grid->merge(*new_grid);
/* Change transform so that the index space is correctly transformed to object space. */
density_grid->transform().postScale(voxel_size);
/* Better align generated grid with the source mesh. */
density_grid->transform().postTranslate(openvdb::math::Vec3d(-voxel_size / 2.0f));
/* Give each grid cell a fixed density for now. */
openvdb::tools::foreach (
density_grid->beginValueOn(),
[](const openvdb::FloatGrid::ValueOnIter &iter) { iter.setValue(1.0f); });
return volume;
#else
UNUSED_VARS(md, ctx);
UNUSED_VARS(compute_voxel_size);
BKE_modifier_set_error(md, "Compiled without OpenVDB");
return input_volume;
#endif
}
ModifierTypeInfo modifierType_MeshToVolume = {
/* name */ "Mesh to Volume",
/* structName */ "MeshToVolumeModifierData",
/* structSize */ sizeof(MeshToVolumeModifierData),
/* srna */ &RNA_MeshToVolumeModifier,
/* type */ eModifierTypeType_Constructive,
/* flags */ static_cast<ModifierTypeFlag>(0),
/* icon */ ICON_VOLUME_DATA, /* TODO: Use correct icon. */
/* copyData */ BKE_modifier_copydata_generic,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* modifyMesh */ NULL,
/* modifyHair */ NULL,
/* modifyPointCloud */ NULL,
/* modifyVolume */ modifyVolume,
/* initData */ initData,
/* requiredDataMask */ NULL,
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
/* freeRuntimeData */ NULL,
/* panelRegister */ panelRegister,
/* blendWrite */ NULL,
/* blendRead */ NULL,
};

View File

@@ -343,5 +343,6 @@ void modifier_type_init(ModifierTypeInfo *types[])
INIT_TYPE(SurfaceDeform);
INIT_TYPE(WeightedNormal);
INIT_TYPE(Simulation);
INIT_TYPE(MeshToVolume);
#undef INIT_TYPE
}