Blender V4.5
blender/volume.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/volume.h"
6#include "scene/image.h"
7#include "scene/image_vdb.h"
8#include "scene/object.h"
9
10#include "blender/sync.h"
11#include "blender/util.h"
12
13#include "BKE_volume_grid.hh"
14
16
17/* TODO: verify this is not loading unnecessary attributes. */
19 public:
22 {
24 *static_cast<const ::Mesh *>(b_ob.data().ptr.data), texspace_loc, texspace_size);
25 }
26
27 bool load_metadata(const ImageDeviceFeatures & /*features*/, ImageMetaData &metadata) override
28 {
29 if (!b_domain) {
30 return false;
31 }
32
35 {
36 metadata.type = IMAGE_DATA_TYPE_FLOAT;
37 metadata.channels = 1;
38 }
39 else if (attribute == ATTR_STD_VOLUME_COLOR) {
41 metadata.channels = 4;
42 }
45 metadata.channels = 3;
46 }
47 else {
48 return false;
49 }
50
51 const int3 resolution = get_int3(b_domain.domain_resolution());
52 int amplify = (b_domain.use_noise()) ? b_domain.noise_scale() : 1;
53
54 /* Velocity and heat data is always low-resolution. */
56 amplify = 1;
57 }
58
59 metadata.width = resolution.x * amplify;
60 metadata.height = resolution.y * amplify;
61 metadata.depth = resolution.z * amplify;
62
63 /* Create a matrix to transform from object space to mesh texture space.
64 * This does not work with deformations but that can probably only be done
65 * well with a volume grid mapping of coordinates. */
67 metadata.use_transform_3d = true;
68
69 return true;
70 }
71
72 bool load_pixels(const ImageMetaData & /*metadata*/,
73 void *pixels,
74 const size_t /*pixels_size*/,
75 const bool /*associate_alpha*/) override
76 {
77 if (!b_domain) {
78 return false;
79 }
80#ifdef WITH_FLUID
81 const int3 resolution = get_int3(b_domain.domain_resolution());
82 int length;
83 int amplify = (b_domain.use_noise()) ? b_domain.noise_scale() : 1;
84
85 /* Velocity and heat data is always low-resolution. */
87 amplify = 1;
88 }
89
90 const int width = resolution.x * amplify;
91 const int height = resolution.y * amplify;
92 const int depth = resolution.z * amplify;
93 const size_t num_pixels = ((size_t)width) * height * depth;
94
95 float *fpixels = (float *)pixels;
96
98 FluidDomainSettings_density_grid_get_length(&b_domain.ptr, &length);
99 if (length == num_pixels) {
100 FluidDomainSettings_density_grid_get(&b_domain.ptr, fpixels);
101 return true;
102 }
103 }
104 else if (attribute == ATTR_STD_VOLUME_FLAME) {
105 /* this is in range 0..1, and interpreted by the OpenGL smoke viewer
106 * as 1500..3000 K with the first part faded to zero density */
107 FluidDomainSettings_flame_grid_get_length(&b_domain.ptr, &length);
108 if (length == num_pixels) {
109 FluidDomainSettings_flame_grid_get(&b_domain.ptr, fpixels);
110 return true;
111 }
112 }
113 else if (attribute == ATTR_STD_VOLUME_COLOR) {
114 /* the RGB is "premultiplied" by density for better interpolation results */
115 FluidDomainSettings_color_grid_get_length(&b_domain.ptr, &length);
116 if (length == num_pixels * 4) {
117 FluidDomainSettings_color_grid_get(&b_domain.ptr, fpixels);
118 return true;
119 }
120 }
122 FluidDomainSettings_velocity_grid_get_length(&b_domain.ptr, &length);
123 if (length == num_pixels * 3) {
124 FluidDomainSettings_velocity_grid_get(&b_domain.ptr, fpixels);
125 return true;
126 }
127 }
128 else if (attribute == ATTR_STD_VOLUME_HEAT) {
129 FluidDomainSettings_heat_grid_get_length(&b_domain.ptr, &length);
130 if (length == num_pixels) {
131 FluidDomainSettings_heat_grid_get(&b_domain.ptr, fpixels);
132 return true;
133 }
134 }
136 FluidDomainSettings_temperature_grid_get_length(&b_domain.ptr, &length);
137 if (length == num_pixels) {
138 FluidDomainSettings_temperature_grid_get(&b_domain.ptr, fpixels);
139 return true;
140 }
141 }
142 else {
143 fprintf(stderr,
144 "Cycles error: unknown volume attribute %s, skipping\n",
146 fpixels[0] = 0.0f;
147 return false;
148 }
149#else
150 (void)pixels;
151#endif
152 fprintf(stderr, "Cycles error: unexpected smoke volume resolution, skipping\n");
153 return false;
154 }
155
156 string name() const override
157 {
159 }
160
161 bool equals(const ImageLoader &other) const override
162 {
163 const BlenderSmokeLoader &other_loader = (const BlenderSmokeLoader &)other;
164 return b_domain == other_loader.b_domain && attribute == other_loader.attribute;
165 }
166
167 BL::FluidDomainSettings b_domain;
170};
171
173 BL::Scene &b_scene, Scene *scene, BObjectInfo &b_ob_info, Volume *volume, const float frame)
174{
175 if (!b_ob_info.is_real_object_data()) {
176 return;
177 }
178 BL::FluidDomainSettings b_domain = object_fluid_gas_domain_find(b_ob_info.real_object);
179 if (!b_domain) {
180 return;
181 }
182
183 float velocity_scale = b_domain.velocity_scale();
184 /* Motion blur attribute is relative to seconds, we need it relative to frames. */
185 const bool need_motion = object_need_motion_attribute(b_ob_info, scene);
186 const float motion_scale = (need_motion) ?
187 scene->motion_shutter_time() /
188 (b_scene.render().fps() / b_scene.render().fps_base()) :
189 0.0f;
190
191 velocity_scale *= motion_scale;
192
193 volume->set_velocity_scale(velocity_scale);
194
195 const AttributeStandard attributes[] = {ATTR_STD_VOLUME_DENSITY,
202
203 const Interval<int> frame_interval = {b_domain.cache_frame_start(), b_domain.cache_frame_end()};
204
205 for (int i = 0; attributes[i] != ATTR_STD_NONE; i++) {
206 const AttributeStandard std = attributes[i];
207 if (!volume->need_attribute(scene, std)) {
208 continue;
209 }
210
211 volume->set_clipping(b_domain.clipping());
212
213 Attribute *attr = volume->attributes.add(std);
214
215 if (!frame_interval.contains(frame)) {
216 attr->data_voxel().clear();
217 continue;
218 }
219
220 unique_ptr<ImageLoader> loader = make_unique<BlenderSmokeLoader>(b_ob_info.real_object, std);
222 params.frame = frame;
223
224 attr->data_voxel() = scene->image_manager->add_image(std::move(loader), params);
225 }
226}
227
229 public:
230 BlenderVolumeLoader(BL::BlendData &b_data,
231 BL::Volume &b_volume,
232 const string &grid_name,
233 BL::VolumeRender::precision_enum precision_)
235 {
236 b_volume.grids.load(b_data.ptr.data);
237
238#ifdef WITH_OPENVDB
239 for (BL::VolumeGrid &b_volume_grid : b_volume.grids) {
240 if (b_volume_grid.name() == grid_name) {
241 const auto *grid_data = static_cast<const blender::bke::VolumeGridData *>(
242 b_volume_grid.ptr.data);
243 grid_data->add_user();
244 volume_grid = blender::bke::GVolumeGrid{grid_data};
245 grid = volume_grid->grid_ptr(tree_access_token);
246 break;
247 }
248 }
249#endif
250#ifdef WITH_NANOVDB
251 switch (precision_) {
252 case BL::VolumeRender::precision_FULL:
253 precision = 32;
254 break;
255 case BL::VolumeRender::precision_HALF:
256 precision = 16;
257 break;
258 default:
259 case BL::VolumeRender::precision_VARIABLE:
260 precision = 0;
261 break;
262 }
263#else
264 (void)precision_;
265#endif
266 }
267
268 BL::Volume b_volume;
269#ifdef WITH_OPENVDB
270 /* Store tree user so that the OPENVDB grid that is shared with Blender is not unloaded. */
271 blender::bke::GVolumeGrid volume_grid;
272 blender::bke::VolumeTreeAccessToken tree_access_token;
273#endif
274};
275
276static void sync_volume_object(BL::BlendData &b_data,
277 BL::Scene &b_scene,
278 BObjectInfo &b_ob_info,
279 Scene *scene,
280 Volume *volume)
281{
282 BL::Volume b_volume(b_ob_info.object_data);
283 b_volume.grids.load(b_data.ptr.data);
284
285 BL::VolumeRender b_render(b_volume.render());
286
287 volume->set_clipping(b_render.clipping());
288 volume->set_step_size(b_render.step_size());
289 volume->set_object_space((b_render.space() == BL::VolumeRender::space_OBJECT));
290
291 float velocity_scale = b_volume.velocity_scale();
292 if (b_volume.velocity_unit() == BL::Volume::velocity_unit_SECOND) {
293 /* Motion blur attribute is relative to seconds, we need it relative to frames. */
294 const bool need_motion = object_need_motion_attribute(b_ob_info, scene);
295 const float motion_scale = (need_motion) ?
296 scene->motion_shutter_time() /
297 (b_scene.render().fps() / b_scene.render().fps_base()) :
298 0.0f;
299
300 velocity_scale *= motion_scale;
301 }
302
303 volume->set_velocity_scale(velocity_scale);
304
305 /* Find grid with matching name. */
306 for (BL::VolumeGrid &b_grid : b_volume.grids) {
307 const ustring name = ustring(b_grid.name());
309
312 }
315 }
318 }
321 }
324 }
326 name == b_volume.velocity_grid())
327 {
329 }
331 name == b_volume.velocity_x_grid())
332 {
334 }
336 name == b_volume.velocity_y_grid())
337 {
339 }
341 name == b_volume.velocity_z_grid())
342 {
344 }
345
346 if ((std != ATTR_STD_NONE && volume->need_attribute(scene, std)) ||
347 volume->need_attribute(scene, name))
348 {
349 Attribute *attr = (std != ATTR_STD_NONE) ?
350 volume->attributes.add(std) :
351 volume->attributes.add(name, TypeFloat, ATTR_ELEMENT_VOXEL);
352
353 unique_ptr<ImageLoader> loader = make_unique<BlenderVolumeLoader>(
354 b_data, b_volume, name.string(), b_render.precision());
356 params.frame = b_volume.grids.frame();
357
358 attr->data_voxel() = scene->image_manager->add_image(std::move(loader), params, false);
359 }
360 }
361}
362
363void BlenderSync::sync_volume(BObjectInfo &b_ob_info, Volume *volume)
364{
365 volume->clear(true);
366
367 if (view_layer.use_volumes) {
368 if (b_ob_info.object_data.is_a(&RNA_Volume)) {
369 /* Volume object. Create only attributes, bounding mesh will then
370 * be automatically generated later. */
371 sync_volume_object(b_data, b_scene, b_ob_info, scene, volume);
372 }
373 else {
374 /* Smoke domain. */
375 sync_smoke_volume(b_scene, scene, b_ob_info, volume, b_scene.frame_current());
376 }
377 }
378
379 /* Tag update. */
380 volume->tag_update(scene, true);
381}
382
static void sync_smoke_volume(BL::Scene &b_scene, Scene *scene, BObjectInfo &b_ob_info, Volume *volume, const float frame)
static void sync_volume_object(BL::BlendData &b_data, BL::Scene &b_scene, BObjectInfo &b_ob_info, Scene *scene, Volume *volume)
for(;discarded_id_iter !=nullptr;discarded_id_iter=static_cast< ID * >(discarded_id_iter->next))
Definition blendfile.cc:634
Attribute * add(ustring name, const TypeDesc type, AttributeElement element)
bool load_pixels(const ImageMetaData &, void *pixels, const size_t, const bool) override
string name() const override
bool load_metadata(const ImageDeviceFeatures &, ImageMetaData &metadata) override
BlenderSmokeLoader(BL::Object &b_ob, AttributeStandard attribute)
BL::FluidDomainSettings b_domain
bool equals(const ImageLoader &other) const override
AttributeStandard attribute
BlenderVolumeLoader(BL::BlendData &b_data, BL::Volume &b_volume, const string &grid_name, BL::VolumeRender::precision_enum precision_)
void tag_update(Scene *scene, bool rebuild)
bool need_attribute(Scene *scene, AttributeStandard std)
AttributeSet attributes
ImageDataType type
VDBImageLoader(const string &grid_name)
string grid_name
Definition image_vdb.h:52
static void mesh_texture_space(const ::Mesh &b_mesh, float3 &loc, float3 &size)
static bool object_need_motion_attribute(BObjectInfo &b_ob_info, Scene *scene)
static int3 get_int3(const BL::Array< int, 3 > &array)
static BL::FluidDomainSettings object_fluid_gas_domain_find(BL::Object &b_ob)
#define CCL_NAMESPACE_END
float length(VecOp< float, D >) RET
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
AttributeStandard
@ ATTR_STD_VOLUME_VELOCITY_Y
@ ATTR_STD_VOLUME_TEMPERATURE
@ ATTR_STD_NONE
@ ATTR_STD_VOLUME_VELOCITY_Z
@ ATTR_STD_VOLUME_DENSITY
@ ATTR_STD_VOLUME_FLAME
@ ATTR_STD_VOLUME_VELOCITY
@ ATTR_STD_VOLUME_COLOR
@ ATTR_STD_VOLUME_HEAT
@ ATTR_STD_VOLUME_VELOCITY_X
@ ATTR_ELEMENT_VOXEL
static const char * standard_name(AttributeStandard std)
ImageHandle & data_voxel()
BL::Object real_object
bool is_real_object_data() const
ccl_device_inline_method bool contains(T value) const
Definition math_base.h:865
unique_ptr< ImageManager > image_manager
Definition scene.h:145
float motion_shutter_time()
Definition scene.cpp:410
void clear(bool preserve_shaders=false) override
float velocity_scale
i
Definition text_draw.cc:230
ccl_device_inline Transform transform_scale(const float3 s)
Definition transform.h:247
ccl_device_inline Transform transform_translate(const float3 t)
Definition transform.h:237
@ IMAGE_DATA_TYPE_FLOAT
@ IMAGE_DATA_TYPE_FLOAT4