Blender V5.0
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),
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 (!BKE_volume_voxel_size_valid(float3(voxel_size))) {
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
129 OpenVDBMeshAdapter mesh_adapter{
130 positions, corner_verts, corner_tris, mesh_to_index_space_transform};
131 const float interior = std::max(1.0f, interior_band_width / voxel_size);
132
133 openvdb::math::Transform::Ptr transform = openvdb::math::Transform::createLinearTransform(
134 voxel_size);
135 openvdb::FloatGrid::Ptr new_grid = openvdb::tools::meshToVolume<openvdb::FloatGrid>(
136 mesh_adapter, *transform, 1.0f, interior);
137
138 openvdb::tools::sdfToFogVolume(*new_grid);
139
140 if (density != 1.0f) {
141 openvdb::tools::foreach(new_grid->beginValueOn(),
142 [&](const openvdb::FloatGrid::ValueOnIter &iter) {
143 iter.modifyValue([&](float &value) { value *= density; });
144 });
145 }
146 return new_grid;
147}
148
149bke::VolumeGrid<float> mesh_to_density_grid(const Span<float3> positions,
150 const Span<int> corner_verts,
151 const Span<int3> corner_tris,
152 const float voxel_size,
153 const float interior_band_width,
154 const float density)
155{
156 openvdb::FloatGrid::Ptr grid = mesh_to_density_grid_impl(positions,
157 corner_verts,
158 corner_tris,
159 float4x4::identity(),
160 voxel_size,
161 interior_band_width,
162 density);
163 if (!grid) {
164 return {};
165 }
166 return bke::VolumeGrid<float>(std::move(grid));
167}
168
169bke::VolumeGrid<float> mesh_to_sdf_grid(const Span<float3> positions,
170 const Span<int> corner_verts,
171 const Span<int3> corner_tris,
172 const float voxel_size,
173 const float half_band_width)
174{
175 if (!BKE_volume_voxel_size_valid(float3(voxel_size)) || half_band_width <= 0.0f) {
176 return {};
177 }
178
179 std::vector<openvdb::Vec3s> points(positions.size());
180 std::vector<openvdb::Vec3I> triangles(corner_tris.size());
181
182 threading::parallel_for(positions.index_range(), 2048, [&](const IndexRange range) {
183 for (const int i : range) {
184 const float3 &co = positions[i];
185 points[i] = openvdb::Vec3s(co.x, co.y, co.z);
186 }
187 });
188
189 threading::parallel_for(corner_tris.index_range(), 2048, [&](const IndexRange range) {
190 for (const int i : range) {
191 const int3 &tri = corner_tris[i];
192 triangles[i] = openvdb::Vec3I(
193 corner_verts[tri[0]], corner_verts[tri[1]], corner_verts[tri[2]]);
194 }
195 });
196
197 openvdb::math::Transform::Ptr transform = openvdb::math::Transform::createLinearTransform(
198 voxel_size);
199 openvdb::FloatGrid::Ptr new_grid = openvdb::tools::meshToLevelSet<openvdb::FloatGrid>(
200 *transform, points, triangles, half_band_width);
201
202 return bke::VolumeGrid<float>(std::move(new_grid));
203}
204
205bke::VolumeGridData *fog_volume_grid_add_from_mesh(Volume *volume,
206 const StringRefNull name,
207 const Span<float3> positions,
208 const Span<int> corner_verts,
209 const Span<int3> corner_tris,
210 const float4x4 &mesh_to_volume_space_transform,
211 const float voxel_size,
212 const float interior_band_width,
213 const float density)
214{
215 openvdb::FloatGrid::Ptr mesh_grid = mesh_to_density_grid_impl(positions,
216 corner_verts,
217 corner_tris,
218 mesh_to_volume_space_transform,
219 voxel_size,
220 interior_band_width,
221 density);
222 return mesh_grid ? BKE_volume_grid_add_vdb(*volume, name, std::move(mesh_grid)) : nullptr;
223}
224
225} // namespace blender::geometry
226#endif
Volume data-block.
float BKE_volume_simplify_factor(const Depsgraph *depsgraph)
bool BKE_volume_voxel_size_valid(const blender::float3 &voxel_size)
@ MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_SIZE
BPy_StructRNA * depsgraph
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition btDbvt.cpp:299
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
uint pos
MatBase< 4, 4 > float4x4
VecBase< float, 3 > float3
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
const char * name
float x
Definition sky_math.h:136