Blender  V2.93
MOD_mesh_to_volume.cc
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
21 #include <vector>
22 
23 #include "BKE_lib_query.h"
24 #include "BKE_mesh_runtime.h"
25 #include "BKE_mesh_wrapper.h"
26 #include "BKE_modifier.h"
27 #include "BKE_object.h"
28 #include "BKE_volume.h"
29 
30 #include "DNA_mesh_types.h"
31 #include "DNA_meshdata_types.h"
32 #include "DNA_object_types.h"
33 #include "DNA_screen_types.h"
34 #include "DNA_volume_types.h"
35 
36 #include "DEG_depsgraph.h"
37 
38 #include "UI_interface.h"
39 #include "UI_resources.h"
40 
41 #include "BLO_read_write.h"
42 
43 #include "MEM_guardedalloc.h"
44 
45 #include "MOD_modifiertypes.h"
46 #include "MOD_ui_common.h"
47 
48 #include "BLI_float4x4.hh"
49 #include "BLI_index_range.hh"
50 #include "BLI_span.hh"
51 
52 #include "RNA_access.h"
53 
54 #ifdef WITH_OPENVDB
55 # include <openvdb/openvdb.h>
56 # include <openvdb/tools/MeshToVolume.h>
57 #endif
58 
59 #ifdef WITH_OPENVDB
60 namespace blender {
61 /* This class follows the MeshDataAdapter interface from openvdb. */
62 class OpenVDBMeshAdapter {
63  private:
64  Span<MVert> vertices_;
65  Span<MLoop> loops_;
66  Span<MLoopTri> looptris_;
67  float4x4 transform_;
68 
69  public:
70  OpenVDBMeshAdapter(Mesh &mesh, float4x4 transform)
71  : vertices_(mesh.mvert, mesh.totvert),
72  loops_(mesh.mloop, mesh.totloop),
73  transform_(transform)
74  {
75  const MLoopTri *looptries = BKE_mesh_runtime_looptri_ensure(&mesh);
76  const int looptries_len = BKE_mesh_runtime_looptri_len(&mesh);
77  looptris_ = Span(looptries, looptries_len);
78  }
79 
80  size_t polygonCount() const
81  {
82  return static_cast<size_t>(looptris_.size());
83  }
84 
85  size_t pointCount() const
86  {
87  return static_cast<size_t>(vertices_.size());
88  }
89 
90  size_t vertexCount(size_t UNUSED(polygon_index)) const
91  {
92  /* All polygons are triangles. */
93  return 3;
94  }
95 
96  void getIndexSpacePoint(size_t polygon_index, size_t vertex_index, openvdb::Vec3d &pos) const
97  {
98  const MLoopTri &looptri = looptris_[polygon_index];
99  const MVert &vertex = vertices_[loops_[looptri.tri[vertex_index]].v];
100  const float3 transformed_co = transform_ * float3(vertex.co);
101  pos = &transformed_co.x;
102  }
103 };
104 } // namespace blender
105 #endif
106 
107 static void initData(ModifierData *md)
108 {
109  MeshToVolumeModifierData *mvmd = reinterpret_cast<MeshToVolumeModifierData *>(md);
110  mvmd->object = nullptr;
112  mvmd->voxel_size = 0.1f;
113  mvmd->voxel_amount = 32;
114  mvmd->fill_volume = true;
115  mvmd->interior_band_width = 0.1f;
116  mvmd->exterior_band_width = 0.1f;
117  mvmd->density = 1.0f;
118 }
119 
121 {
122  MeshToVolumeModifierData *mvmd = reinterpret_cast<MeshToVolumeModifierData *>(md);
123  DEG_add_modifier_to_transform_relation(ctx->node, "Mesh to Volume Modifier");
124  if (mvmd->object) {
126  ctx->node, mvmd->object, DEG_OB_COMP_GEOMETRY, "Mesh to Volume Modifier");
128  ctx->node, mvmd->object, DEG_OB_COMP_TRANSFORM, "Mesh to Volume Modifier");
129  }
130 }
131 
132 static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
133 {
134  MeshToVolumeModifierData *mvmd = reinterpret_cast<MeshToVolumeModifierData *>(md);
135  walk(userData, ob, (ID **)&mvmd->object, IDWALK_CB_NOP);
136 }
137 
138 static void panel_draw(const bContext *UNUSED(C), Panel *panel)
139 {
140  uiLayout *layout = panel->layout;
141 
144 
145  uiLayoutSetPropSep(layout, true);
146 
147  uiItemR(layout, ptr, "object", 0, nullptr, ICON_NONE);
148  uiItemR(layout, ptr, "density", 0, nullptr, ICON_NONE);
149 
150  {
151  uiLayout *col = uiLayoutColumn(layout, false);
152  uiItemR(col, ptr, "use_fill_volume", 0, nullptr, ICON_NONE);
153  uiItemR(col, ptr, "exterior_band_width", 0, nullptr, ICON_NONE);
154 
155  uiLayout *subcol = uiLayoutColumn(col, false);
156  uiLayoutSetActive(subcol, !mvmd->fill_volume);
157  uiItemR(subcol, ptr, "interior_band_width", 0, nullptr, ICON_NONE);
158  }
159  {
160  uiLayout *col = uiLayoutColumn(layout, false);
161  uiItemR(col, ptr, "resolution_mode", 0, nullptr, ICON_NONE);
163  uiItemR(col, ptr, "voxel_amount", 0, nullptr, ICON_NONE);
164  }
165  else {
166  uiItemR(col, ptr, "voxel_size", 0, nullptr, ICON_NONE);
167  }
168  }
169 
170  modifier_panel_end(layout, ptr);
171 }
172 
173 static void panelRegister(ARegionType *region_type)
174 {
176 }
177 
178 #ifdef WITH_OPENVDB
179 static float compute_voxel_size(const ModifierEvalContext *ctx,
180  const MeshToVolumeModifierData *mvmd,
182 {
183  using namespace blender;
184 
185  float volume_simplify = BKE_volume_simplify_factor(ctx->depsgraph);
186  if (volume_simplify == 0.0f) {
187  return 0.0f;
188  }
189 
191  return mvmd->voxel_size / volume_simplify;
192  }
193  if (mvmd->voxel_amount <= 0) {
194  return 0;
195  }
196  /* Compute the voxel size based on the desired number of voxels and the approximated bounding box
197  * of the volume. */
198  const BoundBox *bb = BKE_object_boundbox_get(mvmd->object);
199  const float diagonal = float3::distance(transform * float3(bb->vec[6]),
200  transform * float3(bb->vec[0]));
201  const float approximate_volume_side_length = diagonal + mvmd->exterior_band_width * 2.0f;
202  const float voxel_size = approximate_volume_side_length / mvmd->voxel_amount / volume_simplify;
203  return voxel_size;
204 }
205 #endif
206 
207 static Volume *modifyVolume(ModifierData *md, const ModifierEvalContext *ctx, Volume *input_volume)
208 {
209 #ifdef WITH_OPENVDB
210  using namespace blender;
211 
212  MeshToVolumeModifierData *mvmd = reinterpret_cast<MeshToVolumeModifierData *>(md);
213  Object *object_to_convert = mvmd->object;
214 
215  if (object_to_convert == nullptr) {
216  return input_volume;
217  }
219  if (mesh == nullptr) {
220  return input_volume;
221  }
223 
224  const float4x4 mesh_to_own_object_space_transform = float4x4(ctx->object->imat) *
225  float4x4(object_to_convert->obmat);
226  const float voxel_size = compute_voxel_size(ctx, mvmd, mesh_to_own_object_space_transform);
227  if (voxel_size == 0.0f) {
228  return input_volume;
229  }
230 
231  float4x4 mesh_to_index_space_transform;
232  scale_m4_fl(mesh_to_index_space_transform.values, 1.0f / voxel_size);
233  mul_m4_m4_post(mesh_to_index_space_transform.values, mesh_to_own_object_space_transform.values);
234  /* Better align generated grid with the source mesh. */
235  add_v3_fl(mesh_to_index_space_transform.values[3], -0.5f);
236 
237  OpenVDBMeshAdapter mesh_adapter{*mesh, mesh_to_index_space_transform};
238 
239  /* Convert the bandwidths from object in index space. */
240  const float exterior_band_width = MAX2(0.001f, mvmd->exterior_band_width / voxel_size);
241  const float interior_band_width = MAX2(0.001f, mvmd->interior_band_width / voxel_size);
242 
243  openvdb::FloatGrid::Ptr new_grid;
244  if (mvmd->fill_volume) {
245  /* Setting the interior bandwidth to FLT_MAX, will make it fill the entire volume. */
246  new_grid = openvdb::tools::meshToVolume<openvdb::FloatGrid>(
247  mesh_adapter, {}, exterior_band_width, FLT_MAX);
248  }
249  else {
250  new_grid = openvdb::tools::meshToVolume<openvdb::FloatGrid>(
251  mesh_adapter, {}, exterior_band_width, interior_band_width);
252  }
253 
254  /* Create a new volume object and add the density grid. */
255  Volume *volume = BKE_volume_new_for_eval(input_volume);
256  VolumeGrid *c_density_grid = BKE_volume_grid_add(volume, "density", VOLUME_GRID_FLOAT);
257  openvdb::FloatGrid::Ptr density_grid = openvdb::gridPtrCast<openvdb::FloatGrid>(
258  BKE_volume_grid_openvdb_for_write(volume, c_density_grid, false));
259 
260  /* Merge the generated grid into the density grid. Should be cheap because density_grid has just
261  * been created as well. */
262  density_grid->merge(*new_grid);
263 
264  /* Change transform so that the index space is correctly transformed to object space. */
265  density_grid->transform().postScale(voxel_size);
266 
267  /* Give each grid cell a fixed density for now. */
269  density_grid->beginValueOn(),
270  [&](const openvdb::FloatGrid::ValueOnIter &iter) { iter.setValue(mvmd->density); });
271 
272  return volume;
273 
274 #else
275  UNUSED_VARS(md);
276  BKE_modifier_set_error(ctx->object, md, "Compiled without OpenVDB");
277  return input_volume;
278 #endif
279 }
280 
282  /* name */ "Mesh to Volume",
283  /* structName */ "MeshToVolumeModifierData",
284  /* structSize */ sizeof(MeshToVolumeModifierData),
285  /* srna */ &RNA_MeshToVolumeModifier,
287  /* flags */ static_cast<ModifierTypeFlag>(0),
288  /* icon */ ICON_VOLUME_DATA, /* TODO: Use correct icon. */
289 
290  /* copyData */ BKE_modifier_copydata_generic,
291 
292  /* deformVerts */ nullptr,
293  /* deformMatrices */ nullptr,
294  /* deformVertsEM */ nullptr,
295  /* deformMatricesEM */ nullptr,
296  /* modifyMesh */ nullptr,
297  /* modifyHair */ nullptr,
298  /* modifyGeometrySet */ nullptr,
299  /* modifyVolume */ modifyVolume,
300 
301  /* initData */ initData,
302  /* requiredDataMask */ nullptr,
303  /* freeData */ nullptr,
304  /* isDisabled */ nullptr,
305  /* updateDepsgraph */ updateDepsgraph,
306  /* dependsOnTime */ nullptr,
307  /* dependsOnNormals */ nullptr,
308  /* foreachIDLink */ foreachIDLink,
309  /* foreachTexLink */ nullptr,
310  /* freeRuntimeData */ nullptr,
311  /* panelRegister */ panelRegister,
312  /* blendWrite */ nullptr,
313  /* blendRead */ nullptr,
314 };
@ IDWALK_CB_NOP
Definition: BKE_lib_query.h:47
const struct MLoopTri * BKE_mesh_runtime_looptri_ensure(struct Mesh *mesh)
Definition: mesh_runtime.c:155
int BKE_mesh_runtime_looptri_len(const struct Mesh *mesh)
void BKE_mesh_wrapper_ensure_mdata(struct Mesh *me)
Definition: mesh_wrapper.c:98
void(* IDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin, int cb_flag)
Definition: BKE_modifier.h:120
ModifierTypeFlag
Definition: BKE_modifier.h:79
void BKE_modifier_copydata_generic(const struct ModifierData *md, struct ModifierData *md_dst, const int flag)
@ eModifierTypeType_Constructive
Definition: BKE_modifier.h:61
void BKE_modifier_set_error(const struct Object *ob, struct ModifierData *md, const char *format,...) ATTR_PRINTF_FORMAT(3
struct Mesh * BKE_modifier_get_evaluated_mesh_from_evaluated_object(struct Object *ob_eval, const bool get_cage_mesh)
General operations, lookup, etc. for blender objects.
struct BoundBox * BKE_object_boundbox_get(struct Object *ob)
Definition: object.c:3817
Volume datablock.
struct VolumeGrid * BKE_volume_grid_add(struct Volume *volume, const char *name, VolumeGridType type)
Definition: volume.cc:1417
@ VOLUME_GRID_FLOAT
Definition: BKE_volume.h:101
struct Volume * BKE_volume_new_for_eval(const struct Volume *volume_src)
float BKE_volume_simplify_factor(const struct Depsgraph *depsgraph)
void scale_m4_fl(float R[4][4], float scale)
Definition: math_matrix.c:2309
void mul_m4_m4_post(float R[4][4], const float B[4][4])
Definition: math_matrix.c:383
MINLINE void add_v3_fl(float r[3], float f)
#define UNUSED_VARS(...)
#define UNUSED(x)
#define MAX2(a, b)
void DEG_add_object_relation(struct DepsNodeHandle *node_handle, struct Object *object, eDepsObjectComponentType component, const char *description)
void DEG_add_modifier_to_transform_relation(struct DepsNodeHandle *node_handle, const char *description)
@ DEG_OB_COMP_GEOMETRY
@ DEG_OB_COMP_TRANSFORM
struct MeshToVolumeModifierData MeshToVolumeModifierData
@ eModifierType_MeshToVolume
@ MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_SIZE
@ MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_AMOUNT
Object is a sort of wrapper for general info.
Read Guarded memory(de)allocation.
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
ModifierTypeInfo modifierType_MeshToVolume
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
static Volume * modifyVolume(ModifierData *md, const ModifierEvalContext *ctx, Volume *input_volume)
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
static void initData(ModifierData *md)
static void panelRegister(ARegionType *region_type)
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
void modifier_panel_end(uiLayout *layout, PointerRNA *ptr)
PanelType * modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
StructRNA RNA_MeshToVolumeModifier
#define C
Definition: RandGen.cpp:39
void uiLayoutSetActive(uiLayout *layout, bool active)
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
uint pos
uint col
VecMat::Vec3< double > Vec3d
Definition: Geom.h:41
float vec[8][3]
Definition: DNA_ID.h:273
unsigned int tri[3]
float co[3]
struct Depsgraph * depsgraph
Definition: BKE_modifier.h:153
struct Object * object
Definition: BKE_modifier.h:154
struct DepsNodeHandle * node
Definition: BKE_modifier.h:147
float imat[4][4]
float obmat[4][4]
struct uiLayout * layout
void * data
Definition: RNA_types.h:52
static float distance(const float3 &a, const float3 &b)
Definition: BLI_float3.hh:255
float values[4][4]
Definition: BLI_float4x4.hh:25
float x
Definition: sky_float3.h:35
#define foreach(x, y)
Definition: util_foreach.h:22
PointerRNA * ptr
Definition: wm_files.c:3157