Blender V5.0
points_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_base.hh"
6
7#include "BKE_volume.hh"
8#include "BKE_volume_grid.hh"
10
12
13#ifdef WITH_OPENVDB
14# include <openvdb/openvdb.h>
15# include <openvdb/tools/LevelSetUtil.h>
16# include <openvdb/tools/ParticlesToLevelSet.h>
17
18namespace blender::geometry {
19
20/* Implements the interface required by #openvdb::tools::ParticlesToLevelSet. */
21class OpenVDBParticleList {
22 public:
23 using PosType = openvdb::Vec3R;
24
25 private:
26 Span<float3> positions_;
27 Span<float> radii_;
28 float voxel_size_inv_;
29
30 public:
31 OpenVDBParticleList(const Span<float3> positions,
32 const Span<float> radii,
33 const float voxel_size)
34 : positions_(positions), radii_(radii), voxel_size_inv_(math::rcp(voxel_size))
35 {
36 BLI_assert(voxel_size > 0.0f);
37 }
38
39 size_t size() const
40 {
41 return size_t(positions_.size());
42 }
43
44 void getPos(size_t n, openvdb::Vec3R &xyz) const
45 {
46 float3 pos = positions_[n] * voxel_size_inv_;
47 /* Better align generated grid with source points. */
48 pos -= float3(0.5f);
49 xyz = &pos.x;
50 }
51
52 void getPosRad(size_t n, openvdb::Vec3R &xyz, openvdb::Real &radius) const
53 {
54 this->getPos(n, xyz);
55 radius = radii_[n] * voxel_size_inv_;
56 }
57};
58
59static openvdb::FloatGrid::Ptr points_to_sdf_grid_impl(const Span<float3> positions,
60 const Span<float> radii,
61 const float voxel_size)
62{
63 if (!BKE_volume_voxel_size_valid(float3(voxel_size))) {
64 return nullptr;
65 }
66
67 /* Create a new grid that will be filled. #ParticlesToLevelSet requires
68 * the background value to be positive */
69 openvdb::FloatGrid::Ptr new_grid = openvdb::FloatGrid::create(1.0f);
70
71 /* Create a narrow-band level set grid based on the positions and radii. */
72 openvdb::tools::ParticlesToLevelSet op{*new_grid};
73 /* Don't ignore particles based on their radius. */
74 op.setRmin(0.0f);
75 op.setRmax(std::numeric_limits<float>::max());
76 OpenVDBParticleList particles{positions, radii, voxel_size};
77 op.rasterizeSpheres(particles);
78 op.finalize();
79
80 new_grid->transform().postScale(voxel_size);
81 new_grid->setGridClass(openvdb::GRID_LEVEL_SET);
82
83 return new_grid;
84}
85
86bke::VolumeGrid<float> points_to_sdf_grid(const Span<float3> positions,
87 const Span<float> radii,
88 const float voxel_size)
89{
90 return bke::VolumeGrid<float>(points_to_sdf_grid_impl(positions, radii, voxel_size));
91}
92
93bke::VolumeGridData *fog_volume_grid_add_from_points(Volume *volume,
94 const StringRefNull name,
95 const Span<float3> positions,
96 const Span<float> radii,
97 const float voxel_size,
98 const float density)
99{
100 openvdb::FloatGrid::Ptr new_grid = points_to_sdf_grid_impl(positions, radii, voxel_size);
101 new_grid->setGridClass(openvdb::GRID_FOG_VOLUME);
102
103 /* Convert the level set to a fog volume. This also sets the background value to zero. Inside the
104 * fog there will be a density of 1. */
105 openvdb::tools::sdfToFogVolume(*new_grid);
106
107 /* Take the desired density into account. */
108 openvdb::tools::foreach(new_grid->beginValueOn(),
109 [&](const openvdb::FloatGrid::ValueOnIter &iter) {
110 iter.modifyValue([&](float &value) { value *= density; });
111 });
112
113 return BKE_volume_grid_add_vdb(*volume, name, std::move(new_grid));
114}
115
116} // namespace blender::geometry
117#endif
Volume data-block.
bool BKE_volume_voxel_size_valid(const blender::float3 &voxel_size)
#define BLI_assert(a)
Definition BLI_assert.h:46
struct Volume Volume
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
constexpr int64_t size() const
Definition BLI_span.hh:252
uint pos
VecBase< float, 3 > float3
T rcp(const T &a)
VecBase< float, 3 > float3
const char * name