Blender V5.0
image_vdb.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#include "scene/image_vdb.h"
6
7#include "util/log.h"
8#include "util/nanovdb.h"
9#include "util/openvdb.h"
10#include "util/texture.h"
11
12#ifdef WITH_OPENVDB
13# include <openvdb/tools/Dense.h>
14#endif
15
17
18#ifdef WITH_OPENVDB
19VDBImageLoader::VDBImageLoader(openvdb::GridBase::ConstPtr grid_,
20 const string &grid_name,
21 const float clipping)
22 : grid_name(grid_name), clipping(clipping), grid(grid_)
23{
24}
25#endif
26
31
33
35{
36 if (!features.has_nanovdb) {
37 return false;
38 }
39
40#ifdef WITH_NANOVDB
41 load_grid();
42
43 if (!grid) {
44 return false;
45 }
46
47 /* Convert to the few float types that we know. */
48 grid = openvdb_convert_to_known_type(grid);
49 if (!grid) {
50 return false;
51 }
52
53 /* Get number of channels from type. */
54 metadata.channels = openvdb_num_channels(grid);
55
56 /* Convert OpenVDB to NanoVDB grid. */
57 nanogrid = openvdb_to_nanovdb(grid, precision, clipping);
58 if (!nanogrid) {
59 grid.reset();
60 return false;
61 }
62
63 /* Set dimensions. */
64 bbox = grid->evalActiveVoxelBoundingBox();
65 if (bbox.empty()) {
67 metadata.byte_size = 1;
68 grid.reset();
69 return true;
70 }
71
72 if (metadata.channels == 1) {
73 if (precision == 0) {
75 }
76 else if (precision == 16) {
78 }
79 else {
81 }
82 }
83 else if (metadata.channels == 3) {
85 }
86 else if (metadata.channels == 4) {
88 }
89 else {
90 grid.reset();
91 return false;
92 }
93
94 metadata.byte_size = nanogrid.size();
95
96 /* Set transform from object space to voxel index. */
97 openvdb::math::Mat4f grid_matrix = grid->transform().baseMap()->getAffineMap()->getMat4();
98 Transform index_to_object;
99 for (int col = 0; col < 4; col++) {
100 for (int row = 0; row < 3; row++) {
101 index_to_object[row][col] = (float)grid_matrix[col][row];
102 }
103 }
104
105 metadata.transform_3d = transform_inverse(index_to_object);
106 metadata.use_transform_3d = true;
107
108 /* Only NanoGrid needed now, free OpenVDB grid. */
109 grid.reset();
110
111 return true;
112#else
113 (void)metadata;
114 return false;
115#endif
116}
117
119 void *pixels,
120 const size_t /*pixels_size*/,
121 const bool /*associate_alpha*/)
122{
123#ifdef WITH_NANOVDB
124 if (metadata.type == IMAGE_DATA_TYPE_NANOVDB_EMPTY) {
125 memset(pixels, 0, metadata.byte_size);
126 return true;
127 }
128 if (nanogrid) {
129 memcpy(pixels, nanogrid.data(), nanogrid.size());
130 return true;
131 }
132#else
133 (void)metadata;
134 (void)pixels;
135#endif
136
137 return false;
138}
139
141{
142 return grid_name;
143}
144
145bool VDBImageLoader::equals(const ImageLoader &other) const
146{
147#ifdef WITH_OPENVDB
148 const VDBImageLoader &other_loader = (const VDBImageLoader &)other;
149 return grid && grid == other_loader.grid;
150#else
151 (void)other;
152 return true;
153#endif
154}
155
157{
158#ifdef WITH_OPENVDB
159 /* Free OpenVDB grid memory as soon as we can. */
160 grid.reset();
161#endif
162#ifdef WITH_NANOVDB
163 nanogrid.reset();
164#endif
165}
166
168{
169 return true;
170}
171
172#ifdef WITH_OPENVDB
173openvdb::GridBase::ConstPtr VDBImageLoader::get_grid()
174{
175 return grid;
176}
177
178template<typename GridType>
179openvdb::GridBase::ConstPtr create_grid(const float *voxels,
180 const size_t width,
181 const size_t height,
182 const size_t depth,
183 Transform transform_3d,
184 const float clipping)
185{
186 using ValueType = typename GridType::ValueType;
187 openvdb::GridBase::ConstPtr grid;
188
189 const openvdb::CoordBBox dense_bbox(0, 0, 0, width - 1, height - 1, depth - 1);
190
191 typename GridType::Ptr sparse = GridType::create(ValueType(0.0f));
192 if (dense_bbox.empty()) {
193 return sparse;
194 }
195
196 const openvdb::tools::Dense<const ValueType, openvdb::tools::MemoryLayout::LayoutXYZ> dense(
197 dense_bbox, reinterpret_cast<const ValueType *>(voxels));
198
199 openvdb::tools::copyFromDense(dense, *sparse, ValueType(clipping));
200
201 /* Compute index to world matrix. */
202 const float3 voxel_size = make_float3(1.0f / width, 1.0f / height, 1.0f / depth);
203
204 transform_3d = transform_inverse(transform_3d);
205
206 const openvdb::Mat4R index_to_world_mat((double)(voxel_size.x * transform_3d[0][0]),
207 0.0,
208 0.0,
209 0.0,
210 0.0,
211 (double)(voxel_size.y * transform_3d[1][1]),
212 0.0,
213 0.0,
214 0.0,
215 0.0,
216 (double)(voxel_size.z * transform_3d[2][2]),
217 0.0,
218 (double)transform_3d[0][3] + voxel_size.x,
219 (double)transform_3d[1][3] + voxel_size.y,
220 (double)transform_3d[2][3] + voxel_size.z,
221 1.0);
222
223 const openvdb::math::Transform::Ptr index_to_world_tfm =
224 openvdb::math::Transform::createLinearTransform(index_to_world_mat);
225
226 sparse->setTransform(index_to_world_tfm);
227
228 return sparse;
229}
230#endif
231
233 const size_t height,
234 const size_t depth,
235 const int channels,
236 const float *voxels,
237 Transform transform_3d)
238{
239#ifdef WITH_OPENVDB
240 /* TODO: Create NanoVDB grid directly? */
241 if (channels == 1) {
242 grid = create_grid<openvdb::FloatGrid>(voxels, width, height, depth, transform_3d, clipping);
243 }
244 else if (channels == 3) {
245 grid = create_grid<openvdb::Vec3fGrid>(voxels, width, height, depth, transform_3d, clipping);
246 }
247 else if (channels == 4) {
248 grid = create_grid<openvdb::Vec4fGrid>(voxels, width, height, depth, transform_3d, clipping);
249 }
250
251 /* Clipping already applied, no need to do it again. */
252 clipping = 0.0f;
253#else
254 (void)width;
255 (void)height;
256 (void)depth;
257 (void)channels;
258 (void)voxels;
259 (void)transform_3d;
260#endif
261}
262
ImageDataType type
bool load_pixels(const ImageMetaData &metadata, void *pixels, const size_t pixels_size, const bool associate_alpha) final
bool equals(const ImageLoader &other) const override
string grid_name
Definition image_vdb.h:65
bool load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata) final
Definition image_vdb.cpp:34
~VDBImageLoader() override
void cleanup() override
void grid_from_dense_voxels(const size_t width, const size_t height, const size_t depth, const int channels, const float *voxels, Transform transform_3d)
bool is_vdb_loader() const override
VDBImageLoader(const string &grid_name, const float clipping=0.001f)
Definition image_vdb.cpp:27
virtual void load_grid()
Definition image_vdb.h:56
string name() const override
nullptr float
#define CCL_NAMESPACE_END
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
uint col
float z
Definition sky_math.h:136
float y
Definition sky_math.h:136
float x
Definition sky_math.h:136
@ IMAGE_DATA_TYPE_NANOVDB_FP16
Definition texture.h:45
@ IMAGE_DATA_TYPE_NANOVDB_EMPTY
Definition texture.h:46
@ IMAGE_DATA_TYPE_NANOVDB_FLOAT
Definition texture.h:41
@ IMAGE_DATA_TYPE_NANOVDB_FLOAT3
Definition texture.h:42
@ IMAGE_DATA_TYPE_NANOVDB_FLOAT4
Definition texture.h:43
@ IMAGE_DATA_TYPE_NANOVDB_FPN
Definition texture.h:44
ccl_device_inline Transform transform_inverse(const Transform tfm)
Definition transform.h:525