From 8ddfdfd2b2a52f746312246aa3099ab0df8544a0 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 26 Oct 2021 11:25:44 -0500 Subject: Geometry Nodes: Handle multiple grids in the volume to mesh node In future use cases, a volume can contain many grids that represent the density information. In this case, it's better if the volume to mesh node creates a mesh based on all of the grids in the volume. This is also a benefit to share-ability, since one doesn't have to specify the grid name in the node. Instead, in the future we can have a way to split particular grids into separate volumes, if only one grid should be considered. The code changes are relatively simple: - Move the old volume to mesh node to the legacy folder. - Run the volume to mesh node on all instance geometry, like elsewhere. - Make the blenkernel's volume to mesh API a bit more specific. Differential Revision: https://developer.blender.org/D12997 --- source/blender/blenkernel/BKE_node.h | 3 +- source/blender/blenkernel/BKE_volume.h | 5 ++ source/blender/blenkernel/BKE_volume_to_mesh.hh | 32 ++++++++ source/blender/blenkernel/intern/node.cc | 1 + source/blender/blenkernel/intern/volume.cc | 17 ++++ source/blender/blenkernel/intern/volume_to_mesh.cc | 93 +++++++++++++++------- 6 files changed, 120 insertions(+), 31 deletions(-) (limited to 'source/blender/blenkernel') diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index c868eb414f7..8daa96164ef 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -1442,7 +1442,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree, #define GEO_NODE_COLLECTION_INFO 1023 #define GEO_NODE_IS_VIEWPORT 1024 #define GEO_NODE_LEGACY_ATTRIBUTE_PROXIMITY 1025 -#define GEO_NODE_VOLUME_TO_MESH 1026 +#define GEO_NODE_LEGACY_VOLUME_TO_MESH 1026 #define GEO_NODE_LEGACY_ATTRIBUTE_COMBINE_XYZ 1027 #define GEO_NODE_LEGACY_ATTRIBUTE_SEPARATE_XYZ 1028 #define GEO_NODE_SUBDIVIDE_MESH 1029 @@ -1548,6 +1548,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree, #define GEO_NODE_CURVE_TO_POINTS 1130 #define GEO_NODE_INSTANCES_TO_POINTS 1131 #define GEO_NODE_IMAGE_TEXTURE 1132 +#define GEO_NODE_VOLUME_TO_MESH 1133 /** \} */ diff --git a/source/blender/blenkernel/BKE_volume.h b/source/blender/blenkernel/BKE_volume.h index 5fe0d54c2cf..601e0cf26a9 100644 --- a/source/blender/blenkernel/BKE_volume.h +++ b/source/blender/blenkernel/BKE_volume.h @@ -160,6 +160,7 @@ bool BKE_volume_save(const struct Volume *volume, #ifdef __cplusplus # include "BLI_float3.hh" # include "BLI_float4x4.hh" +# include "BLI_string_ref.hh" bool BKE_volume_min_max(const Volume *volume, blender::float3 &r_min, blender::float3 &r_max); @@ -167,6 +168,10 @@ bool BKE_volume_min_max(const Volume *volume, blender::float3 &r_min, blender::f # include # include +VolumeGrid *BKE_volume_grid_add_vdb(Volume &volume, + blender::StringRef name, + openvdb::GridBase::Ptr vdb_grid); + bool BKE_volume_grid_bounds(openvdb::GridBase::ConstPtr grid, blender::float3 &r_min, blender::float3 &r_max); diff --git a/source/blender/blenkernel/BKE_volume_to_mesh.hh b/source/blender/blenkernel/BKE_volume_to_mesh.hh index 1f6e89636c4..9532da8c23c 100644 --- a/source/blender/blenkernel/BKE_volume_to_mesh.hh +++ b/source/blender/blenkernel/BKE_volume_to_mesh.hh @@ -14,6 +14,8 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "BLI_span.hh" + #include "DNA_modifier_types.h" #ifdef WITH_OPENVDB @@ -33,10 +35,40 @@ struct VolumeToMeshResolution { }; #ifdef WITH_OPENVDB + +/** + * The result of converting a volume grid to mesh data, in the format used by the OpenVDB API. + */ +struct OpenVDBMeshData { + std::vector verts; + std::vector tris; + std::vector quads; + bool is_empty() const + { + return verts.empty(); + } +}; + struct Mesh *volume_to_mesh(const openvdb::GridBase &grid, const VolumeToMeshResolution &resolution, const float threshold, const float adaptivity); + +struct OpenVDBMeshData volume_to_mesh_data(const openvdb::GridBase &grid, + const VolumeToMeshResolution &resolution, + const float threshold, + const float adaptivity); + +void fill_mesh_from_openvdb_data(const Span vdb_verts, + const Span vdb_tris, + const Span vdb_quads, + const int vert_offset, + const int poly_offset, + const int loop_offset, + MutableSpan verts, + MutableSpan polys, + MutableSpan loops); + #endif } // namespace blender::bke diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index fb2110d7e53..8494c51a66e 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -5753,6 +5753,7 @@ static void registerGeometryNodes() register_node_type_geo_legacy_select_by_handle_type(); register_node_type_geo_legacy_select_by_material(); register_node_type_geo_legacy_subdivision_surface(); + register_node_type_geo_legacy_volume_to_mesh(); register_node_type_geo_align_rotation_to_vector(); register_node_type_geo_attribute_capture(); diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc index 7e7a40d8e9b..a72b5268e1d 100644 --- a/source/blender/blenkernel/intern/volume.cc +++ b/source/blender/blenkernel/intern/volume.cc @@ -36,6 +36,7 @@ #include "BLI_math.h" #include "BLI_path_util.h" #include "BLI_string.h" +#include "BLI_string_ref.hh" #include "BLI_task.hh" #include "BLI_utildefines.h" @@ -71,6 +72,7 @@ static CLG_LogRef LOG = {"bke.volume"}; using blender::float3; using blender::float4x4; using blender::IndexRange; +using blender::StringRef; #ifdef WITH_OPENVDB # include @@ -1451,6 +1453,21 @@ VolumeGrid *BKE_volume_grid_add(Volume *volume, const char *name, VolumeGridType #endif } +#ifdef WITH_OPENVDB +VolumeGrid *BKE_volume_grid_add_vdb(Volume &volume, + const StringRef name, + openvdb::GridBase::Ptr vdb_grid) +{ + VolumeGridVector &grids = *volume.runtime.grids; + BLI_assert(BKE_volume_grid_find_for_read(&volume, name.data()) == nullptr); + BLI_assert(BKE_volume_grid_type_openvdb(*vdb_grid) != VOLUME_GRID_UNKNOWN); + + vdb_grid->setName(name); + grids.emplace_back(vdb_grid); + return &grids.back(); +} +#endif + void BKE_volume_grid_remove(Volume *volume, VolumeGrid *grid) { #ifdef WITH_OPENVDB diff --git a/source/blender/blenkernel/intern/volume_to_mesh.cc b/source/blender/blenkernel/intern/volume_to_mesh.cc index e9d6eea4614..6e465b2fdf0 100644 --- a/source/blender/blenkernel/intern/volume_to_mesh.cc +++ b/source/blender/blenkernel/intern/volume_to_mesh.cc @@ -121,46 +121,66 @@ struct VolumeToMeshOp { } }; -static Mesh *new_mesh_from_openvdb_data(Span verts, - Span tris, - Span quads) +/** + * Convert mesh data from the format provided by OpenVDB into Blender's #Mesh data structure. + * This can be used to add mesh data from a grid into an existing mesh rather than merging multiple + * meshes later on. + */ +void fill_mesh_from_openvdb_data(const Span vdb_verts, + const Span vdb_tris, + const Span vdb_quads, + const int vert_offset, + const int poly_offset, + const int loop_offset, + MutableSpan verts, + MutableSpan polys, + MutableSpan loops) { - const int tot_loops = 3 * tris.size() + 4 * quads.size(); - const int tot_polys = tris.size() + quads.size(); - - Mesh *mesh = BKE_mesh_new_nomain(verts.size(), 0, 0, tot_loops, tot_polys); - /* Write vertices. */ - for (const int i : verts.index_range()) { - const blender::float3 co = blender::float3(verts[i].asV()); - copy_v3_v3(mesh->mvert[i].co, co); + for (const int i : vdb_verts.index_range()) { + const blender::float3 co = blender::float3(vdb_verts[i].asV()); + copy_v3_v3(verts[vert_offset + i].co, co); } /* Write triangles. */ - for (const int i : tris.index_range()) { - mesh->mpoly[i].loopstart = 3 * i; - mesh->mpoly[i].totloop = 3; + for (const int i : vdb_tris.index_range()) { + polys[poly_offset + i].loopstart = loop_offset + 3 * i; + polys[poly_offset + i].totloop = 3; for (int j = 0; j < 3; j++) { /* Reverse vertex order to get correct normals. */ - mesh->mloop[3 * i + j].v = tris[i][2 - j]; + loops[loop_offset + 3 * i + j].v = vert_offset + vdb_tris[i][2 - j]; } } /* Write quads. */ - const int poly_offset = tris.size(); - const int loop_offset = tris.size() * 3; - for (const int i : quads.index_range()) { - mesh->mpoly[poly_offset + i].loopstart = loop_offset + 4 * i; - mesh->mpoly[poly_offset + i].totloop = 4; + const int quad_offset = poly_offset + vdb_tris.size(); + const int quad_loop_offset = loop_offset + vdb_tris.size() * 3; + for (const int i : vdb_quads.index_range()) { + polys[quad_offset + i].loopstart = quad_loop_offset + 4 * i; + polys[quad_offset + i].totloop = 4; for (int j = 0; j < 4; j++) { /* Reverse vertex order to get correct normals. */ - mesh->mloop[loop_offset + 4 * i + j].v = quads[i][3 - j]; + loops[quad_loop_offset + 4 * i + j].v = vert_offset + vdb_quads[i][3 - j]; } } +} - BKE_mesh_calc_edges(mesh, false, false); - BKE_mesh_normals_tag_dirty(mesh); - return mesh; +/** + * Convert an OpenVDB volume grid to corresponding mesh data: vertex positions and quad and + * triangle indices. + */ +bke::OpenVDBMeshData volume_to_mesh_data(const openvdb::GridBase &grid, + const VolumeToMeshResolution &resolution, + const float threshold, + const float adaptivity) +{ + const VolumeGridType grid_type = BKE_volume_grid_type_openvdb(grid); + + VolumeToMeshOp to_mesh_op{grid, resolution, threshold, adaptivity}; + if (!BKE_volume_grid_type_operation(grid_type, to_mesh_op)) { + return {}; + } + return {std::move(to_mesh_op.verts), std::move(to_mesh_op.tris), std::move(to_mesh_op.quads)}; } Mesh *volume_to_mesh(const openvdb::GridBase &grid, @@ -168,14 +188,27 @@ Mesh *volume_to_mesh(const openvdb::GridBase &grid, const float threshold, const float adaptivity) { - const VolumeGridType grid_type = BKE_volume_grid_type_openvdb(grid); + const bke::OpenVDBMeshData mesh_data = volume_to_mesh_data( + grid, resolution, threshold, adaptivity); + + const int tot_loops = 3 * mesh_data.tris.size() + 4 * mesh_data.quads.size(); + const int tot_polys = mesh_data.tris.size() + mesh_data.quads.size(); + Mesh *mesh = BKE_mesh_new_nomain(mesh_data.verts.size(), 0, 0, tot_loops, tot_polys); + + fill_mesh_from_openvdb_data(mesh_data.verts, + mesh_data.tris, + mesh_data.quads, + 0, + 0, + 0, + {mesh->mvert, mesh->totvert}, + {mesh->mpoly, mesh->totpoly}, + {mesh->mloop, mesh->totloop}); - VolumeToMeshOp to_mesh_op{grid, resolution, threshold, adaptivity}; - if (!BKE_volume_grid_type_operation(grid_type, to_mesh_op)) { - return nullptr; - } + BKE_mesh_calc_edges(mesh, false, false); + BKE_mesh_normals_tag_dirty(mesh); - return new_mesh_from_openvdb_data(to_mesh_op.verts, to_mesh_op.tris, to_mesh_op.quads); + return mesh; } #endif /* WITH_OPENVDB */ -- cgit v1.2.3