Blender V4.3
mesh_to_volume.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
5#include "BLI_math_matrix.hh"
6#include "BLI_task.hh"
7
8#include "BKE_volume.hh"
9#include "BKE_volume_grid.hh"
10#include "BKE_volume_openvdb.hh"
11
12#include "GEO_mesh_to_volume.hh"
13
14#ifdef WITH_OPENVDB
15# include <algorithm>
16# include <openvdb/openvdb.h>
17# include <openvdb/tools/GridTransformer.h>
18# include <openvdb/tools/LevelSetUtil.h>
19# include <openvdb/tools/VolumeToMesh.h>
20
21namespace blender::geometry {
22
23/* This class follows the MeshDataAdapter interface from openvdb. */
24class OpenVDBMeshAdapter {
25 private:
26 Span<float3> positions_;
27 Span<int> corner_verts_;
28 Span<int3> corner_tris_;
29 float4x4 transform_;
30
31 public:
32 OpenVDBMeshAdapter(const Span<float3> positions,
33 const Span<int> corner_verts,
34 const Span<int3> corner_tris,
35 const float4x4 &transform);
36 size_t polygonCount() const;
37 size_t pointCount() const;
38 size_t vertexCount(size_t /*polygon_index*/) const;
39 void getIndexSpacePoint(size_t polygon_index, size_t vertex_index, openvdb::Vec3d &pos) const;
40};
41
42OpenVDBMeshAdapter::OpenVDBMeshAdapter(const Span<float3> positions,
43 const Span<int> corner_verts,
44 const Span<int3> corner_tris,
45 const float4x4 &transform)
46 : positions_(positions),
47 corner_verts_(corner_verts),
48 corner_tris_(corner_tris),
49 transform_(transform)
50{
51}
52
53size_t OpenVDBMeshAdapter::polygonCount() const
54{
55 return size_t(corner_tris_.size());
56}
57
58size_t OpenVDBMeshAdapter::pointCount() const
59{
60 return size_t(positions_.size());
61}
62
63size_t OpenVDBMeshAdapter::vertexCount(size_t /*polygon_index*/) const
64{
65 /* All polygons are triangles. */
66 return 3;
67}
68
69void OpenVDBMeshAdapter::getIndexSpacePoint(size_t polygon_index,
70 size_t vertex_index,
71 openvdb::Vec3d &pos) const
72{
73 const int3 &tri = corner_tris_[polygon_index];
74 const float3 transformed_co = math::transform_point(
75 transform_, positions_[corner_verts_[tri[vertex_index]]]);
76 pos = &transformed_co.x;
77}
78
79float volume_compute_voxel_size(const Depsgraph *depsgraph,
80 const FunctionRef<Bounds<float3>()> bounds_fn,
81 const MeshToVolumeResolution res,
82 const float exterior_band_width,
83 const float4x4 &transform)
84{
85 const float volume_simplify = BKE_volume_simplify_factor(depsgraph);
86 if (volume_simplify == 0.0f) {
87 return 0.0f;
88 }
89
91 return res.settings.voxel_size / volume_simplify;
92 }
93 if (res.settings.voxel_amount <= 0) {
94 return 0;
95 }
96
97 const Bounds<float3> bounds = bounds_fn();
98
99 /* Compute the diagonal of the bounding box. This is used because
100 * it will always be bigger than the widest side of the mesh. */
101 const float diagonal = math::distance(math::transform_point(transform, bounds.min),
102 math::transform_point(transform, bounds.max));
103
104 /* To get the approximate size per voxel, first subtract the exterior band from the requested
105 * voxel amount, then divide the diagonal with this value if it's bigger than 1. */
106 const float voxel_size =
107 (diagonal / std::max(1.0f, float(res.settings.voxel_amount) - 2.0f * exterior_band_width));
108
109 /* Return the simplified voxel size. */
110 return voxel_size / volume_simplify;
111}
112
113static openvdb::FloatGrid::Ptr mesh_to_density_grid_impl(
114 const Span<float3> positions,
115 const Span<int> corner_verts,
116 const Span<int3> corner_tris,
117 const float4x4 &mesh_to_volume_space_transform,
118 const float voxel_size,
119 const float interior_band_width,
120 const float density)
121{
122 if (voxel_size < 1e-5f) {
123 return nullptr;
124 }
125
126 float4x4 mesh_to_index_space_transform = math::from_scale<float4x4>(float3(1.0f / voxel_size));
127 mesh_to_index_space_transform *= mesh_to_volume_space_transform;
128 /* Better align generated grid with the source mesh. */
129 mesh_to_index_space_transform.location() -= 0.5f;
130
131 OpenVDBMeshAdapter mesh_adapter{
132 positions, corner_verts, corner_tris, mesh_to_index_space_transform};
133 const float interior = std::max(1.0f, interior_band_width / voxel_size);
134
135 openvdb::math::Transform::Ptr transform = openvdb::math::Transform::createLinearTransform(
136 voxel_size);
137 openvdb::FloatGrid::Ptr new_grid = openvdb::tools::meshToVolume<openvdb::FloatGrid>(
138 mesh_adapter, *transform, 1.0f, interior);
139
140 openvdb::tools::sdfToFogVolume(*new_grid);
141
142 if (density != 1.0f) {
143 openvdb::tools::foreach (new_grid->beginValueOn(),
144 [&](const openvdb::FloatGrid::ValueOnIter &iter) {
145 iter.modifyValue([&](float &value) { value *= density; });
146 });
147 }
148 return new_grid;
149}
150
151bke::VolumeGrid<float> mesh_to_density_grid(const Span<float3> positions,
152 const Span<int> corner_verts,
153 const Span<int3> corner_tris,
154 const float voxel_size,
155 const float interior_band_width,
156 const float density)
157{
158 openvdb::FloatGrid::Ptr grid = mesh_to_density_grid_impl(positions,
159 corner_verts,
160 corner_tris,
161 float4x4::identity(),
162 voxel_size,
163 interior_band_width,
164 density);
165 if (!grid) {
166 return {};
167 }
168 return bke::VolumeGrid<float>(std::move(grid));
169}
170
171bke::VolumeGrid<float> mesh_to_sdf_grid(const Span<float3> positions,
172 const Span<int> corner_verts,
173 const Span<int3> corner_tris,
174 const float voxel_size,
175 const float half_band_width)
176{
177 if (voxel_size <= 0.0f || half_band_width <= 0.0f) {
178 return {};
179 }
180
181 std::vector<openvdb::Vec3s> points(positions.size());
182 std::vector<openvdb::Vec3I> triangles(corner_tris.size());
183
184 threading::parallel_for(positions.index_range(), 2048, [&](const IndexRange range) {
185 for (const int i : range) {
186 const float3 &co = positions[i];
187 points[i] = openvdb::Vec3s(co.x, co.y, co.z) - 0.5f * voxel_size;
188 }
189 });
190
191 threading::parallel_for(corner_tris.index_range(), 2048, [&](const IndexRange range) {
192 for (const int i : range) {
193 const int3 &tri = corner_tris[i];
194 triangles[i] = openvdb::Vec3I(
195 corner_verts[tri[0]], corner_verts[tri[1]], corner_verts[tri[2]]);
196 }
197 });
198
199 openvdb::math::Transform::Ptr transform = openvdb::math::Transform::createLinearTransform(
200 voxel_size);
201 openvdb::FloatGrid::Ptr new_grid = openvdb::tools::meshToLevelSet<openvdb::FloatGrid>(
202 *transform, points, triangles, half_band_width);
203
204 return bke::VolumeGrid<float>(std::move(new_grid));
205}
206
207bke::VolumeGridData *fog_volume_grid_add_from_mesh(Volume *volume,
208 const StringRefNull name,
209 const Span<float3> positions,
210 const Span<int> corner_verts,
211 const Span<int3> corner_tris,
212 const float4x4 &mesh_to_volume_space_transform,
213 const float voxel_size,
214 const float interior_band_width,
215 const float density)
216{
217 openvdb::FloatGrid::Ptr mesh_grid = mesh_to_density_grid_impl(positions,
218 corner_verts,
219 corner_tris,
220 mesh_to_volume_space_transform,
221 voxel_size,
222 interior_band_width,
223 density);
224 return mesh_grid ? BKE_volume_grid_add_vdb(*volume, name, std::move(mesh_grid)) : nullptr;
225}
226
227} // namespace blender::geometry
228#endif
Volume data-block.
float BKE_volume_simplify_factor(const Depsgraph *depsgraph)
@ MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_SIZE
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition btDbvt.cpp:299
const Depsgraph * depsgraph
T distance(const T &a, const T &b)
MatT from_scale(const VecBase< typename MatT::base_type, ScaleDim > &scale)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
MatBase< float, 4, 4 > float4x4
float x
Definition sky_float3.h:27