Blender V4.3
MOD_volume_to_mesh.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <vector>
10
11#include "BKE_lib_query.hh"
12#include "BKE_mesh.hh"
13#include "BKE_modifier.hh"
14#include "BKE_volume.hh"
15#include "BKE_volume_grid.hh"
16#include "BKE_volume_to_mesh.hh"
17
18#include "BLT_translation.hh"
19
20#include "MOD_ui_common.hh"
21
22#include "DNA_modifier_types.h"
23#include "DNA_object_types.h"
24#include "DNA_screen_types.h"
25
26#include "UI_interface.hh"
27#include "UI_resources.hh"
28
29#include "RNA_prototypes.hh"
30
32#include "BLI_span.hh"
33#include "BLI_string.h"
34
36
37#ifdef WITH_OPENVDB
38# include <openvdb/tools/GridTransformer.h>
39# include <openvdb/tools/VolumeToMesh.h>
40#endif
41
42using blender::float3;
44using blender::Span;
45
46static void init_data(ModifierData *md)
47{
48 VolumeToMeshModifierData *vmmd = reinterpret_cast<VolumeToMeshModifierData *>(md);
49 vmmd->object = nullptr;
50 vmmd->threshold = 0.1f;
51 STRNCPY(vmmd->grid_name, "density");
52 vmmd->adaptivity = 0.0f;
54 vmmd->voxel_amount = 32;
55 vmmd->voxel_size = 0.1f;
56 vmmd->flag = 0;
57}
58
60{
61 VolumeToMeshModifierData *vmmd = reinterpret_cast<VolumeToMeshModifierData *>(md);
62 DEG_add_depends_on_transform_relation(ctx->node, "Volume to Mesh Modifier");
63 if (vmmd->object) {
65 ctx->node, vmmd->object, DEG_OB_COMP_GEOMETRY, "Volume to Mesh Modifier");
67 ctx->node, vmmd->object, DEG_OB_COMP_TRANSFORM, "Volume to Mesh Modifier");
68 }
69}
70
71static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
72{
73 VolumeToMeshModifierData *vmmd = reinterpret_cast<VolumeToMeshModifierData *>(md);
74 walk(user_data, ob, (ID **)&vmmd->object, IDWALK_CB_NOP);
75}
76
77static void panel_draw(const bContext * /*C*/, Panel *panel)
78{
79 uiLayout *layout = panel->layout;
80
83
84 uiLayoutSetPropSep(layout, true);
85
86 {
87 uiLayout *col = uiLayoutColumn(layout, false);
88 uiItemR(col, ptr, "object", UI_ITEM_NONE, nullptr, ICON_NONE);
89 uiItemR(col, ptr, "grid_name", UI_ITEM_NONE, nullptr, ICON_NONE);
90 }
91
92 {
93 uiLayout *col = uiLayoutColumn(layout, false);
94 uiItemR(col, ptr, "resolution_mode", UI_ITEM_NONE, nullptr, ICON_NONE);
96 uiItemR(col, ptr, "voxel_amount", UI_ITEM_NONE, nullptr, ICON_NONE);
97 }
99 uiItemR(col, ptr, "voxel_size", UI_ITEM_NONE, nullptr, ICON_NONE);
100 }
101 }
102
103 {
104 uiLayout *col = uiLayoutColumn(layout, false);
105 uiItemR(col, ptr, "threshold", UI_ITEM_NONE, nullptr, ICON_NONE);
106 uiItemR(col, ptr, "adaptivity", UI_ITEM_NONE, nullptr, ICON_NONE);
107 uiItemR(col, ptr, "use_smooth_shade", UI_ITEM_NONE, nullptr, ICON_NONE);
108 }
109
110 modifier_panel_end(layout, ptr);
111}
112
113static void panel_register(ARegionType *region_type)
114{
116}
117
118static Mesh *create_empty_mesh(const Mesh *input_mesh)
119{
120 Mesh *new_mesh = BKE_mesh_new_nomain(0, 0, 0, 0);
121 BKE_mesh_copy_parameters_for_eval(new_mesh, input_mesh);
122 return new_mesh;
123}
124
125static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *input_mesh)
126{
127 using namespace blender;
128#ifdef WITH_OPENVDB
129 VolumeToMeshModifierData *vmmd = reinterpret_cast<VolumeToMeshModifierData *>(md);
130 if (vmmd->object == nullptr) {
131 return create_empty_mesh(input_mesh);
132 }
133 if (vmmd->object->type != OB_VOLUME) {
134 return create_empty_mesh(input_mesh);
135 }
137 vmmd->voxel_size == 0.0f)
138 {
139 return create_empty_mesh(input_mesh);
140 }
142 vmmd->voxel_amount == 0)
143 {
144 return create_empty_mesh(input_mesh);
145 }
146
147 const Volume *volume = static_cast<Volume *>(vmmd->object->data);
148
150 const blender::bke::VolumeGridData *volume_grid = BKE_volume_grid_find(volume, vmmd->grid_name);
151 if (volume_grid == nullptr) {
152 BKE_modifier_set_error(ctx->object, md, "Cannot find '%s' grid", vmmd->grid_name);
153 return create_empty_mesh(input_mesh);
154 }
155
156 blender::bke::VolumeTreeAccessToken tree_token;
157 const openvdb::GridBase &local_grid = volume_grid->grid(tree_token);
158
159 openvdb::math::Transform::Ptr transform = local_grid.transform().copy();
160 transform->postMult(openvdb::Mat4d(vmmd->object->object_to_world().base_ptr()));
161 openvdb::Mat4d imat = openvdb::Mat4d(ctx->object->world_to_object().base_ptr());
162 /* `imat` had floating point issues and wasn't affine. */
163 imat.setCol(3, openvdb::Vec4d(0, 0, 0, 1));
164 transform->postMult(imat);
165
166 /* Create a temporary transformed grid. The underlying tree is shared. */
167 openvdb::GridBase::ConstPtr transformed_grid = local_grid.copyGridReplacingTransform(transform);
168
172 resolution.settings.voxel_amount = vmmd->voxel_amount;
173 }
175 resolution.settings.voxel_size = vmmd->voxel_size;
176 }
177
178 Mesh *mesh = bke::volume_to_mesh(
179 *transformed_grid, resolution, vmmd->threshold, vmmd->adaptivity);
180 if (mesh == nullptr) {
181 BKE_modifier_set_error(ctx->object, md, "Could not generate mesh from grid");
182 return create_empty_mesh(input_mesh);
183 }
184
185 BKE_mesh_copy_parameters_for_eval(mesh, input_mesh);
186 bke::mesh_smooth_set(*mesh, vmmd->flag & VOLUME_TO_MESH_USE_SMOOTH_SHADE);
187 return mesh;
188#else
189 UNUSED_VARS(md);
190 BKE_modifier_set_error(ctx->object, md, "Compiled without OpenVDB");
191 return create_empty_mesh(input_mesh);
192#endif
193}
194
196 /*idname*/ "Volume to Mesh",
197 /*name*/ N_("Volume to Mesh"),
198 /*struct_name*/ "VolumeToMeshModifierData",
199 /*struct_size*/ sizeof(VolumeToMeshModifierData),
200 /*srna*/ &RNA_VolumeToMeshModifier,
203 /*icon*/ ICON_VOLUME_DATA, /* TODO: Use correct icon. */
204
205 /*copy_data*/ BKE_modifier_copydata_generic,
206
207 /*deform_verts*/ nullptr,
208 /*deform_matrices*/ nullptr,
209 /*deform_verts_EM*/ nullptr,
210 /*deform_matrices_EM*/ nullptr,
211 /*modify_mesh*/ modify_mesh,
212 /*modify_geometry_set*/ nullptr,
213
214 /*init_data*/ init_data,
215 /*required_data_mask*/ nullptr,
216 /*free_data*/ nullptr,
217 /*is_disabled*/ nullptr,
218 /*update_depsgraph*/ update_depsgraph,
219 /*depends_on_time*/ nullptr,
220 /*depends_on_normals*/ nullptr,
221 /*foreach_ID_link*/ foreach_ID_link,
222 /*foreach_tex_link*/ nullptr,
223 /*free_runtime_data*/ nullptr,
224 /*panel_register*/ panel_register,
225 /*blend_write*/ nullptr,
226 /*blend_read*/ nullptr,
227 /*foreach_cache*/ nullptr,
228};
@ IDWALK_CB_NOP
void BKE_mesh_copy_parameters_for_eval(Mesh *me_dst, const Mesh *me_src)
Mesh * BKE_mesh_new_nomain(int verts_num, int edges_num, int faces_num, int corners_num)
void BKE_modifier_copydata_generic(const ModifierData *md, ModifierData *md_dst, int flag)
@ eModifierTypeFlag_AcceptsMesh
void(*)(void *user_data, Object *ob, ID **idpoin, int cb_flag) IDWalkFunc
void BKE_modifier_set_error(const Object *ob, ModifierData *md, const char *format,...) ATTR_PRINTF_FORMAT(3
Volume data-block.
bool BKE_volume_load(const Volume *volume, const Main *bmain)
const blender::bke::VolumeGridData * BKE_volume_grid_find(const Volume *volume, const char *name)
#define STRNCPY(dst, src)
Definition BLI_string.h:593
#define UNUSED_VARS(...)
void DEG_add_depends_on_transform_relation(DepsNodeHandle *node_handle, const char *description)
void DEG_add_object_relation(DepsNodeHandle *node_handle, Object *object, eDepsObjectComponentType component, const char *description)
@ DEG_OB_COMP_GEOMETRY
@ DEG_OB_COMP_TRANSFORM
Main * DEG_get_bmain(const Depsgraph *graph)
@ eModifierType_VolumeToMesh
@ VOLUME_TO_MESH_USE_SMOOTH_SHADE
VolumeToMeshResolutionMode
@ VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE
@ VOLUME_TO_MESH_RESOLUTION_MODE_GRID
@ VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT
struct VolumeToMeshModifierData VolumeToMeshModifierData
Object is a sort of wrapper for general info.
@ OB_VOLUME
void modifier_panel_end(uiLayout *layout, PointerRNA *ptr)
PanelType * modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
static void init_data(ModifierData *md)
static void panel_register(ARegionType *region_type)
static Mesh * create_empty_mesh(const Mesh *input_mesh)
ModifierTypeInfo modifierType_VolumeToMesh
static void panel_draw(const bContext *, Panel *panel)
static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
static void update_depsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
static Mesh * modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *input_mesh)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
#define UI_ITEM_NONE
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
uint col
Definition DNA_ID.h:413
struct uiLayout * layout
void * data
Definition RNA_types.hh:42
union blender::bke::VolumeToMeshResolution::@73 settings
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4126