Blender  V3.3
mesh_to_volume.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include "BKE_mesh_runtime.h"
4 #include "BKE_volume.h"
5 
6 #include "GEO_mesh_to_volume.hh"
7 
8 #ifdef WITH_OPENVDB
9 # include <openvdb/openvdb.h>
10 # include <openvdb/tools/GridTransformer.h>
11 # include <openvdb/tools/VolumeToMesh.h>
12 
13 namespace blender::geometry {
14 
15 /* This class follows the MeshDataAdapter interface from openvdb. */
16 class OpenVDBMeshAdapter {
17  private:
18  Span<MVert> vertices_;
19  Span<MLoop> loops_;
20  Span<MLoopTri> looptris_;
21  float4x4 transform_;
22 
23  public:
24  OpenVDBMeshAdapter(const Mesh &mesh, float4x4 transform);
25  size_t polygonCount() const;
26  size_t pointCount() const;
27  size_t vertexCount(size_t UNUSED(polygon_index)) const;
28  void getIndexSpacePoint(size_t polygon_index, size_t vertex_index, openvdb::Vec3d &pos) const;
29 };
30 
31 OpenVDBMeshAdapter::OpenVDBMeshAdapter(const Mesh &mesh, float4x4 transform)
32  : vertices_(mesh.mvert, mesh.totvert), loops_(mesh.mloop, mesh.totloop), transform_(transform)
33 {
34  /* This only updates a cache and can be considered to be logically const. */
35  const MLoopTri *looptris = BKE_mesh_runtime_looptri_ensure(&mesh);
36  const int looptris_len = BKE_mesh_runtime_looptri_len(&mesh);
37  looptris_ = Span(looptris, looptris_len);
38 }
39 
40 size_t OpenVDBMeshAdapter::polygonCount() const
41 {
42  return static_cast<size_t>(looptris_.size());
43 }
44 
45 size_t OpenVDBMeshAdapter::pointCount() const
46 {
47  return static_cast<size_t>(vertices_.size());
48 }
49 
50 size_t OpenVDBMeshAdapter::vertexCount(size_t UNUSED(polygon_index)) const
51 {
52  /* All polygons are triangles. */
53  return 3;
54 }
55 
56 void OpenVDBMeshAdapter::getIndexSpacePoint(size_t polygon_index,
57  size_t vertex_index,
58  openvdb::Vec3d &pos) const
59 {
60  const MLoopTri &looptri = looptris_[polygon_index];
61  const MVert &vertex = vertices_[loops_[looptri.tri[vertex_index]].v];
62  const float3 transformed_co = transform_ * float3(vertex.co);
63  pos = &transformed_co.x;
64 }
65 
66 float volume_compute_voxel_size(const Depsgraph *depsgraph,
67  FunctionRef<void(float3 &r_min, float3 &r_max)> bounds_fn,
68  const MeshToVolumeResolution res,
69  const float exterior_band_width,
70  const float4x4 &transform)
71 {
72  const float volume_simplify = BKE_volume_simplify_factor(depsgraph);
73  if (volume_simplify == 0.0f) {
74  return 0.0f;
75  }
76 
78  return res.settings.voxel_size / volume_simplify;
79  }
80  if (res.settings.voxel_amount <= 0) {
81  return 0;
82  }
83 
84  float3 bb_min;
85  float3 bb_max;
86  bounds_fn(bb_min, bb_max);
87 
88  /* Compute the voxel size based on the desired number of voxels and the approximated bounding
89  * box of the volume. */
90  const float diagonal = math::distance(transform * bb_max, transform * bb_min);
91  const float approximate_volume_side_length = diagonal + exterior_band_width * 2.0f;
92  const float voxel_size = approximate_volume_side_length / res.settings.voxel_amount /
93  volume_simplify;
94  return voxel_size;
95 }
96 
97 static openvdb::FloatGrid::Ptr mesh_to_volume_grid(const Mesh *mesh,
98  const float4x4 &mesh_to_volume_space_transform,
99  const float voxel_size,
100  const bool fill_volume,
101  const float exterior_band_width,
102  const float interior_band_width,
103  const float density)
104 {
105  if (voxel_size == 0.0f) {
106  return nullptr;
107  }
108 
109  float4x4 mesh_to_index_space_transform;
110  scale_m4_fl(mesh_to_index_space_transform.values, 1.0f / voxel_size);
111  mul_m4_m4_post(mesh_to_index_space_transform.values, mesh_to_volume_space_transform.values);
112  /* Better align generated grid with the source mesh. */
113  add_v3_fl(mesh_to_index_space_transform.values[3], -0.5f);
114 
115  OpenVDBMeshAdapter mesh_adapter{*mesh, mesh_to_index_space_transform};
116 
117  /* Convert the bandwidths from object in index space. */
118  const float exterior = MAX2(0.001f, exterior_band_width / voxel_size);
119  const float interior = MAX2(0.001f, interior_band_width / voxel_size);
120 
121  openvdb::FloatGrid::Ptr new_grid;
122  if (fill_volume) {
123  /* Setting the interior bandwidth to FLT_MAX, will make it fill the entire volume. */
124  new_grid = openvdb::tools::meshToVolume<openvdb::FloatGrid>(
125  mesh_adapter, {}, exterior, FLT_MAX);
126  }
127  else {
128  new_grid = openvdb::tools::meshToVolume<openvdb::FloatGrid>(
129  mesh_adapter, {}, exterior, interior);
130  }
131 
132  /* Give each grid cell a fixed density for now. */
134  new_grid->beginValueOn(),
135  [density](const openvdb::FloatGrid::ValueOnIter &iter) { iter.setValue(density); });
136 
137  return new_grid;
138 }
139 
140 VolumeGrid *volume_grid_add_from_mesh(Volume *volume,
141  const StringRefNull name,
142  const Mesh *mesh,
143  const float4x4 &mesh_to_volume_space_transform,
144  const float voxel_size,
145  const bool fill_volume,
146  const float exterior_band_width,
147  const float interior_band_width,
148  const float density)
149 {
150  VolumeGrid *c_grid = BKE_volume_grid_add(volume, name.c_str(), VOLUME_GRID_FLOAT);
151  openvdb::FloatGrid::Ptr grid = openvdb::gridPtrCast<openvdb::FloatGrid>(
152  BKE_volume_grid_openvdb_for_write(volume, c_grid, false));
153 
154  /* Generate grid from mesh */
155  openvdb::FloatGrid::Ptr mesh_grid = mesh_to_volume_grid(mesh,
156  mesh_to_volume_space_transform,
157  voxel_size,
158  fill_volume,
159  exterior_band_width,
160  interior_band_width,
161  density);
162 
163  /* Merge the generated grid. Should be cheap because grid has just been created. */
164  grid->merge(*mesh_grid);
165  /* Set class to "Fog Volume". */
166  grid->setGridClass(openvdb::GRID_FOG_VOLUME);
167  /* Change transform so that the index space is correctly transformed to object space. */
168  grid->transform().postScale(voxel_size);
169  return c_grid;
170 }
171 } // namespace blender::geometry
172 #endif
const struct MLoopTri * BKE_mesh_runtime_looptri_ensure(const struct Mesh *mesh)
int BKE_mesh_runtime_looptri_len(const struct Mesh *mesh)
Volume data-block.
struct VolumeGrid * BKE_volume_grid_add(struct Volume *volume, const char *name, VolumeGridType type)
Definition: volume.cc:1542
@ VOLUME_GRID_FLOAT
Definition: BKE_volume.h:93
float BKE_volume_simplify_factor(const struct Depsgraph *depsgraph)
void scale_m4_fl(float R[4][4], float scale)
Definition: math_matrix.c:2297
void mul_m4_m4_post(float R[4][4], const float B[4][4])
Definition: math_matrix.c:380
MINLINE void add_v3_fl(float r[3], float f)
#define UNUSED(x)
#define MAX2(a, b)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
@ MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_SIZE
float float4x4[4][4]
float float3[3]
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
const Depsgraph * depsgraph
#define foreach(x, y)
Definition: foreach.h:9
uint pos
VecMat::Vec3< double > Vec3d
Definition: Geom.h:27
std::unique_ptr< T > Ptr
Definition: BLI_any.hh:58
T distance(const T &a, const T &b)
static const pxr::TfToken density("density", pxr::TfToken::Immortal)
unsigned int tri[3]
float co[3]
float x