Blender  V3.3
blender/volume.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: Apache-2.0
2  * Copyright 2011-2022 Blender Foundation */
3 
4 #include "scene/volume.h"
5 #include "scene/colorspace.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 #ifdef WITH_OPENVDB
14 # include <openvdb/openvdb.h>
15 openvdb::GridBase::ConstPtr BKE_volume_grid_openvdb_for_read(const struct Volume *volume,
16  const struct VolumeGrid *grid);
17 #endif
18 
20 
21 /* TODO: verify this is not loading unnecessary attributes. */
23  public:
26  {
27  BL::Mesh b_mesh(b_ob.data());
29  }
30 
31  bool load_metadata(const ImageDeviceFeatures &, ImageMetaData &metadata) override
32  {
33  if (!b_domain) {
34  return false;
35  }
36 
39  metadata.type = IMAGE_DATA_TYPE_FLOAT;
40  metadata.channels = 1;
41  }
42  else if (attribute == ATTR_STD_VOLUME_COLOR) {
43  metadata.type = IMAGE_DATA_TYPE_FLOAT4;
44  metadata.channels = 4;
45  }
46  else if (attribute == ATTR_STD_VOLUME_VELOCITY) {
47  metadata.type = IMAGE_DATA_TYPE_FLOAT4;
48  metadata.channels = 3;
49  }
50  else {
51  return false;
52  }
53 
54  int3 resolution = get_int3(b_domain.domain_resolution());
55  int amplify = (b_domain.use_noise()) ? b_domain.noise_scale() : 1;
56 
57  /* Velocity and heat data is always low-resolution. */
59  amplify = 1;
60  }
61 
62  metadata.width = resolution.x * amplify;
63  metadata.height = resolution.y * amplify;
64  metadata.depth = resolution.z * amplify;
65 
66  /* Create a matrix to transform from object space to mesh texture space.
67  * This does not work with deformations but that can probably only be done
68  * well with a volume grid mapping of coordinates. */
70  metadata.use_transform_3d = true;
71 
72  return true;
73  }
74 
75  bool load_pixels(const ImageMetaData &, void *pixels, const size_t, const bool) override
76  {
77  if (!b_domain) {
78  return false;
79  }
80 #ifdef WITH_FLUID
81  int3 resolution = get_int3(b_domain.domain_resolution());
82  int length, amplify = (b_domain.use_noise()) ? b_domain.noise_scale() : 1;
83 
84  /* Velocity and heat data is always low-resolution. */
86  amplify = 1;
87  }
88 
89  const int width = resolution.x * amplify;
90  const int height = resolution.y * amplify;
91  const int depth = resolution.z * amplify;
92  const size_t num_pixels = ((size_t)width) * height * depth;
93 
94  float *fpixels = (float *)pixels;
95 
97  FluidDomainSettings_density_grid_get_length(&b_domain.ptr, &length);
98  if (length == num_pixels) {
99  FluidDomainSettings_density_grid_get(&b_domain.ptr, fpixels);
100  return true;
101  }
102  }
103  else if (attribute == ATTR_STD_VOLUME_FLAME) {
104  /* this is in range 0..1, and interpreted by the OpenGL smoke viewer
105  * as 1500..3000 K with the first part faded to zero density */
106  FluidDomainSettings_flame_grid_get_length(&b_domain.ptr, &length);
107  if (length == num_pixels) {
108  FluidDomainSettings_flame_grid_get(&b_domain.ptr, fpixels);
109  return true;
110  }
111  }
112  else if (attribute == ATTR_STD_VOLUME_COLOR) {
113  /* the RGB is "premultiplied" by density for better interpolation results */
114  FluidDomainSettings_color_grid_get_length(&b_domain.ptr, &length);
115  if (length == num_pixels * 4) {
116  FluidDomainSettings_color_grid_get(&b_domain.ptr, fpixels);
117  return true;
118  }
119  }
120  else if (attribute == ATTR_STD_VOLUME_VELOCITY) {
121  FluidDomainSettings_velocity_grid_get_length(&b_domain.ptr, &length);
122  if (length == num_pixels * 3) {
123  FluidDomainSettings_velocity_grid_get(&b_domain.ptr, fpixels);
124  return true;
125  }
126  }
127  else if (attribute == ATTR_STD_VOLUME_HEAT) {
128  FluidDomainSettings_heat_grid_get_length(&b_domain.ptr, &length);
129  if (length == num_pixels) {
130  FluidDomainSettings_heat_grid_get(&b_domain.ptr, fpixels);
131  return true;
132  }
133  }
135  FluidDomainSettings_temperature_grid_get_length(&b_domain.ptr, &length);
136  if (length == num_pixels) {
137  FluidDomainSettings_temperature_grid_get(&b_domain.ptr, fpixels);
138  return true;
139  }
140  }
141  else {
142  fprintf(stderr,
143  "Cycles error: unknown volume attribute %s, skipping\n",
145  fpixels[0] = 0.0f;
146  return false;
147  }
148 #else
149  (void)pixels;
150 #endif
151  fprintf(stderr, "Cycles error: unexpected smoke volume resolution, skipping\n");
152  return false;
153  }
154 
155  string name() const override
156  {
158  }
159 
160  bool equals(const ImageLoader &other) const override
161  {
162  const BlenderSmokeLoader &other_loader = (const BlenderSmokeLoader &)other;
163  return b_domain == other_loader.b_domain && attribute == other_loader.attribute;
164  }
165 
169 };
170 
171 static void sync_smoke_volume(
172  BL::Scene &b_scene, Scene *scene, BObjectInfo &b_ob_info, Volume *volume, float frame)
173 {
174  if (!b_ob_info.is_real_object_data()) {
175  return;
176  }
178  if (!b_domain) {
179  return;
180  }
181 
182  float velocity_scale = b_domain.velocity_scale();
183  /* Motion blur attribute is relative to seconds, we need it relative to frames. */
184  const bool need_motion = object_need_motion_attribute(b_ob_info, scene);
185  const float motion_scale = (need_motion) ?
187  (b_scene.render().fps() / b_scene.render().fps_base()) :
188  0.0f;
189 
190  velocity_scale *= motion_scale;
191 
192  volume->set_velocity_scale(velocity_scale);
193 
200  ATTR_STD_NONE};
201 
202  for (int i = 0; attributes[i] != ATTR_STD_NONE; i++) {
203  AttributeStandard std = attributes[i];
204  if (!volume->need_attribute(scene, std)) {
205  continue;
206  }
207 
208  volume->set_clipping(b_domain.clipping());
209 
210  Attribute *attr = volume->attributes.add(std);
211 
212  ImageLoader *loader = new BlenderSmokeLoader(b_ob_info.real_object, std);
214  params.frame = frame;
215 
216  attr->data_voxel() = scene->image_manager->add_image(loader, params);
217  }
218 }
219 
221  public:
222  BlenderVolumeLoader(BL::BlendData &b_data,
224  const string &grid_name,
225  BL::VolumeRender::precision_enum precision_)
227  {
228  b_volume.grids.load(b_data.ptr.data);
229 
230 #ifdef WITH_OPENVDB
231  for (BL::VolumeGrid &b_volume_grid : b_volume.grids) {
232  if (b_volume_grid.name() == grid_name) {
233  const bool unload = !b_volume_grid.is_loaded();
234 
235  ::Volume *volume = (::Volume *)b_volume.ptr.data;
236  const VolumeGrid *volume_grid = (VolumeGrid *)b_volume_grid.ptr.data;
237  grid = BKE_volume_grid_openvdb_for_read(volume, volume_grid);
238 
239  if (unload) {
240  b_volume_grid.unload();
241  }
242 
243  break;
244  }
245  }
246 #endif
247 #ifdef WITH_NANOVDB
248  switch (precision_) {
249  case BL::VolumeRender::precision_FULL:
250  precision = 32;
251  break;
252  case BL::VolumeRender::precision_HALF:
253  precision = 16;
254  break;
255  default:
256  case BL::VolumeRender::precision_VARIABLE:
257  precision = 0;
258  break;
259  }
260 #else
261  (void)precision_;
262 #endif
263  }
264 
266 };
267 
268 static void sync_volume_object(BL::BlendData &b_data,
269  BL::Scene &b_scene,
270  BObjectInfo &b_ob_info,
271  Scene *scene,
272  Volume *volume)
273 {
274  BL::Volume b_volume(b_ob_info.object_data);
275  b_volume.grids.load(b_data.ptr.data);
276 
277  BL::VolumeRender b_render(b_volume.render());
278 
279  volume->set_clipping(b_render.clipping());
280  volume->set_step_size(b_render.step_size());
281  volume->set_object_space((b_render.space() == BL::VolumeRender::space_OBJECT));
282 
283  float velocity_scale = b_volume.velocity_scale();
284  if (b_volume.velocity_unit() == BL::Volume::velocity_unit_SECOND) {
285  /* Motion blur attribute is relative to seconds, we need it relative to frames. */
286  const bool need_motion = object_need_motion_attribute(b_ob_info, scene);
287  const float motion_scale = (need_motion) ?
289  (b_scene.render().fps() / b_scene.render().fps_base()) :
290  0.0f;
291 
292  velocity_scale *= motion_scale;
293  }
294 
295  volume->set_velocity_scale(velocity_scale);
296 
297  /* Find grid with matching name. */
298  for (BL::VolumeGrid &b_grid : b_volume.grids) {
299  ustring name = ustring(b_grid.name());
301 
304  }
307  }
310  }
313  }
316  }
318  name == b_volume.velocity_grid()) {
320  }
322  name == b_volume.velocity_x_grid()) {
324  }
326  name == b_volume.velocity_y_grid()) {
328  }
330  name == b_volume.velocity_z_grid()) {
332  }
333 
334  if ((std != ATTR_STD_NONE && volume->need_attribute(scene, std)) ||
335  volume->need_attribute(scene, name)) {
336  Attribute *attr = (std != ATTR_STD_NONE) ?
337  volume->attributes.add(std) :
338  volume->attributes.add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_VOXEL);
339 
340  ImageLoader *loader = new BlenderVolumeLoader(
341  b_data, b_volume, name.string(), b_render.precision());
343  params.frame = b_volume.grids.frame();
344 
345  attr->data_voxel() = scene->image_manager->add_image(loader, params, false);
346  }
347  }
348 }
349 
350 void BlenderSync::sync_volume(BObjectInfo &b_ob_info, Volume *volume)
351 {
352  volume->clear(true);
353 
354  if (view_layer.use_volumes) {
355  if (b_ob_info.object_data.is_a(&RNA_Volume)) {
356  /* Volume object. Create only attributes, bounding mesh will then
357  * be automatically generated later. */
358  sync_volume_object(b_data, b_scene, b_ob_info, scene, volume);
359  }
360  else {
361  /* Smoke domain. */
362  sync_smoke_volume(b_scene, scene, b_ob_info, volume, b_scene.frame_current());
363  }
364  }
365 
366  /* Tag update. */
367  volume->tag_update(scene, true);
368 }
369 
struct VolumeGrid VolumeGrid
Definition: BKE_volume.h:65
struct FluidDomainSettings FluidDomainSettings
struct Mesh Mesh
struct Object Object
struct Scene Scene
struct VolumeRender VolumeRender
struct Volume Volume
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei width
static void sync_smoke_volume(BL::Scene &b_scene, Scene *scene, BObjectInfo &b_ob_info, Volume *volume, float frame)
static void sync_volume_object(BL::BlendData &b_data, BL::Scene &b_scene, BObjectInfo &b_ob_info, Scene *scene, Volume *volume)
Attribute * add(ustring name, TypeDesc type, AttributeElement element)
ImageHandle & data_voxel()
static const char * standard_name(AttributeStandard std)
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_)
bool need_attribute(Scene *scene, AttributeStandard std)
void tag_update(Scene *scene, bool rebuild)
AttributeSet attributes
ImageHandle add_image(const string &filename, const ImageParams &params)
ImageDataType type
Transform transform_3d
string grid_name
Definition: image_vdb.h:47
#define CCL_NAMESPACE_END
Definition: cuda/compat.h:9
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)
static void mesh_texture_space(BL::Mesh &b_mesh, float3 &loc, float3 &size)
Scene scene
SyclQueue void void size_t num_bytes void
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
ccl_device_inline Transform transform_translate(float3 t)
ccl_device_inline Transform transform_scale(float3 s)
ccl_gpu_kernel_postfix ccl_global float int num_pixels
AttributeStandard
Definition: kernel/types.h:612
@ ATTR_STD_VOLUME_VELOCITY_Y
Definition: kernel/types.h:640
@ ATTR_STD_VOLUME_TEMPERATURE
Definition: kernel/types.h:637
@ ATTR_STD_NONE
Definition: kernel/types.h:613
@ ATTR_STD_VOLUME_VELOCITY_Z
Definition: kernel/types.h:641
@ ATTR_STD_VOLUME_DENSITY
Definition: kernel/types.h:633
@ ATTR_STD_VOLUME_FLAME
Definition: kernel/types.h:635
@ ATTR_STD_VOLUME_VELOCITY
Definition: kernel/types.h:638
@ ATTR_STD_VOLUME_COLOR
Definition: kernel/types.h:634
@ ATTR_STD_VOLUME_HEAT
Definition: kernel/types.h:636
@ ATTR_STD_VOLUME_VELOCITY_X
Definition: kernel/types.h:639
@ ATTR_ELEMENT_VOXEL
Definition: kernel/types.h:609
T length(const vec_base< T, Size > &a)
BL::Object real_object
bool is_real_object_data() const
ImageManager * image_manager
Definition: scene.h:222
float motion_shutter_time()
Definition: scene.cpp:397
virtual void clear(bool preserve_shaders=false) override
float velocity_scale
@ IMAGE_DATA_TYPE_FLOAT
Definition: util/texture.h:33
@ IMAGE_DATA_TYPE_FLOAT4
Definition: util/texture.h:30