Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/geometry/intern/mesh_to_volume.cc')
-rw-r--r--source/blender/geometry/intern/mesh_to_volume.cc173
1 files changed, 173 insertions, 0 deletions
diff --git a/source/blender/geometry/intern/mesh_to_volume.cc b/source/blender/geometry/intern/mesh_to_volume.cc
new file mode 100644
index 00000000000..b1c7be38609
--- /dev/null
+++ b/source/blender/geometry/intern/mesh_to_volume.cc
@@ -0,0 +1,173 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_volume.h"
+
+#include "GEO_mesh_to_volume.hh"
+
+#ifdef WITH_OPENVDB
+# include <openvdb/openvdb.h>
+# include <openvdb/tools/GridTransformer.h>
+# include <openvdb/tools/VolumeToMesh.h>
+
+namespace blender::geometry {
+
+/* This class follows the MeshDataAdapter interface from openvdb. */
+class OpenVDBMeshAdapter {
+ private:
+ Span<MVert> verts_;
+ Span<MLoop> loops_;
+ Span<MLoopTri> looptris_;
+ float4x4 transform_;
+
+ public:
+ OpenVDBMeshAdapter(const Mesh &mesh, float4x4 transform);
+ size_t polygonCount() const;
+ size_t pointCount() const;
+ size_t vertexCount(size_t UNUSED(polygon_index)) const;
+ void getIndexSpacePoint(size_t polygon_index, size_t vertex_index, openvdb::Vec3d &pos) const;
+};
+
+OpenVDBMeshAdapter::OpenVDBMeshAdapter(const Mesh &mesh, float4x4 transform)
+ : verts_(mesh.verts()), loops_(mesh.loops()), transform_(transform)
+{
+ /* This only updates a cache and can be considered to be logically const. */
+ const MLoopTri *looptris = BKE_mesh_runtime_looptri_ensure(&mesh);
+ const int looptris_len = BKE_mesh_runtime_looptri_len(&mesh);
+ looptris_ = Span(looptris, looptris_len);
+}
+
+size_t OpenVDBMeshAdapter::polygonCount() const
+{
+ return static_cast<size_t>(looptris_.size());
+}
+
+size_t OpenVDBMeshAdapter::pointCount() const
+{
+ return static_cast<size_t>(verts_.size());
+}
+
+size_t OpenVDBMeshAdapter::vertexCount(size_t UNUSED(polygon_index)) const
+{
+ /* All polygons are triangles. */
+ return 3;
+}
+
+void OpenVDBMeshAdapter::getIndexSpacePoint(size_t polygon_index,
+ size_t vertex_index,
+ openvdb::Vec3d &pos) const
+{
+ const MLoopTri &looptri = looptris_[polygon_index];
+ const MVert &vertex = verts_[loops_[looptri.tri[vertex_index]].v];
+ const float3 transformed_co = transform_ * float3(vertex.co);
+ pos = &transformed_co.x;
+}
+
+float volume_compute_voxel_size(const Depsgraph *depsgraph,
+ FunctionRef<void(float3 &r_min, float3 &r_max)> bounds_fn,
+ const MeshToVolumeResolution res,
+ const float exterior_band_width,
+ const float4x4 &transform)
+{
+ const float volume_simplify = BKE_volume_simplify_factor(depsgraph);
+ if (volume_simplify == 0.0f) {
+ return 0.0f;
+ }
+
+ if (res.mode == MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_SIZE) {
+ return res.settings.voxel_size / volume_simplify;
+ }
+ if (res.settings.voxel_amount <= 0) {
+ return 0;
+ }
+
+ float3 bb_min;
+ float3 bb_max;
+ bounds_fn(bb_min, bb_max);
+
+ /* Compute the voxel size based on the desired number of voxels and the approximated bounding
+ * box of the volume. */
+ const float diagonal = math::distance(transform * bb_max, transform * bb_min);
+ const float approximate_volume_side_length = diagonal + exterior_band_width * 2.0f;
+ const float voxel_size = approximate_volume_side_length / res.settings.voxel_amount /
+ volume_simplify;
+ return voxel_size;
+}
+
+static openvdb::FloatGrid::Ptr mesh_to_volume_grid(const Mesh *mesh,
+ const float4x4 &mesh_to_volume_space_transform,
+ const float voxel_size,
+ const bool fill_volume,
+ const float exterior_band_width,
+ const float interior_band_width,
+ const float density)
+{
+ if (voxel_size == 0.0f) {
+ return nullptr;
+ }
+
+ float4x4 mesh_to_index_space_transform;
+ scale_m4_fl(mesh_to_index_space_transform.values, 1.0f / voxel_size);
+ mul_m4_m4_post(mesh_to_index_space_transform.values, mesh_to_volume_space_transform.values);
+ /* Better align generated grid with the source mesh. */
+ add_v3_fl(mesh_to_index_space_transform.values[3], -0.5f);
+
+ OpenVDBMeshAdapter mesh_adapter{*mesh, mesh_to_index_space_transform};
+
+ /* Convert the bandwidths from object in index space. */
+ const float exterior = MAX2(0.001f, exterior_band_width / voxel_size);
+ const float interior = MAX2(0.001f, interior_band_width / voxel_size);
+
+ openvdb::FloatGrid::Ptr new_grid;
+ if (fill_volume) {
+ /* Setting the interior bandwidth to FLT_MAX, will make it fill the entire volume. */
+ new_grid = openvdb::tools::meshToVolume<openvdb::FloatGrid>(
+ mesh_adapter, {}, exterior, FLT_MAX);
+ }
+ else {
+ new_grid = openvdb::tools::meshToVolume<openvdb::FloatGrid>(
+ mesh_adapter, {}, exterior, interior);
+ }
+
+ /* Give each grid cell a fixed density for now. */
+ openvdb::tools::foreach (
+ new_grid->beginValueOn(),
+ [density](const openvdb::FloatGrid::ValueOnIter &iter) { iter.setValue(density); });
+
+ return new_grid;
+}
+
+VolumeGrid *volume_grid_add_from_mesh(Volume *volume,
+ const StringRefNull name,
+ const Mesh *mesh,
+ const float4x4 &mesh_to_volume_space_transform,
+ const float voxel_size,
+ const bool fill_volume,
+ const float exterior_band_width,
+ const float interior_band_width,
+ const float density)
+{
+ VolumeGrid *c_grid = BKE_volume_grid_add(volume, name.c_str(), VOLUME_GRID_FLOAT);
+ openvdb::FloatGrid::Ptr grid = openvdb::gridPtrCast<openvdb::FloatGrid>(
+ BKE_volume_grid_openvdb_for_write(volume, c_grid, false));
+
+ /* Generate grid from mesh */
+ openvdb::FloatGrid::Ptr mesh_grid = mesh_to_volume_grid(mesh,
+ mesh_to_volume_space_transform,
+ voxel_size,
+ fill_volume,
+ exterior_band_width,
+ interior_band_width,
+ density);
+
+ /* Merge the generated grid. Should be cheap because grid has just been created. */
+ grid->merge(*mesh_grid);
+ /* Set class to "Fog Volume". */
+ grid->setGridClass(openvdb::GRID_FOG_VOLUME);
+ /* Change transform so that the index space is correctly transformed to object space. */
+ grid->transform().postScale(voxel_size);
+ return c_grid;
+}
+} // namespace blender::geometry
+#endif