Blender  V2.93
volume.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2020 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "render/volume.h"
18 #include "render/attribute.h"
19 #include "render/image_vdb.h"
20 #include "render/scene.h"
21 
22 #ifdef WITH_OPENVDB
23 # include <openvdb/tools/Dense.h>
24 # include <openvdb/tools/GridTransformer.h>
25 # include <openvdb/tools/Morphology.h>
26 #endif
27 
28 #include "util/util_foreach.h"
29 #include "util/util_hash.h"
30 #include "util/util_logging.h"
31 #include "util/util_openvdb.h"
32 #include "util/util_progress.h"
33 #include "util/util_types.h"
34 
36 
38 {
39  NodeType *type = NodeType::add("volume", create, NodeType::NONE, Mesh::get_node_type());
40 
41  SOCKET_FLOAT(clipping, "Clipping", 0.001f);
42  SOCKET_FLOAT(step_size, "Step Size", 0.0f);
43  SOCKET_BOOLEAN(object_space, "Object Space", false);
44 
45  return type;
46 }
47 
48 Volume::Volume() : Mesh(get_node_type(), Geometry::VOLUME)
49 {
50  clipping = 0.001f;
51  step_size = 0.0f;
52  object_space = false;
53 }
54 
55 void Volume::clear(bool preserve_shaders)
56 {
57  Mesh::clear(preserve_shaders, true);
58 }
59 
60 struct QuadData {
61  int v0, v1, v2, v3;
62 
64 };
65 
66 enum {
73 };
74 
75 #ifdef WITH_OPENVDB
76 const int quads_indices[6][4] = {
77  /* QUAD_X_MIN */
78  {4, 0, 3, 7},
79  /* QUAD_X_MAX */
80  {1, 5, 6, 2},
81  /* QUAD_Y_MIN */
82  {4, 5, 1, 0},
83  /* QUAD_Y_MAX */
84  {3, 2, 6, 7},
85  /* QUAD_Z_MIN */
86  {0, 1, 2, 3},
87  /* QUAD_Z_MAX */
88  {5, 4, 7, 6},
89 };
90 
91 const float3 quads_normals[6] = {
92  /* QUAD_X_MIN */
93  make_float3(-1.0f, 0.0f, 0.0f),
94  /* QUAD_X_MAX */
95  make_float3(1.0f, 0.0f, 0.0f),
96  /* QUAD_Y_MIN */
97  make_float3(0.0f, -1.0f, 0.0f),
98  /* QUAD_Y_MAX */
99  make_float3(0.0f, 1.0f, 0.0f),
100  /* QUAD_Z_MIN */
101  make_float3(0.0f, 0.0f, -1.0f),
102  /* QUAD_Z_MAX */
103  make_float3(0.0f, 0.0f, 1.0f),
104 };
105 
106 static int add_vertex(int3 v,
107  vector<int3> &vertices,
108  int3 res,
109  unordered_map<size_t, int> &used_verts)
110 {
111  size_t vert_key = v.x + v.y * (res.x + 1) + v.z * (res.x + 1) * (res.y + 1);
112  unordered_map<size_t, int>::iterator it = used_verts.find(vert_key);
113 
114  if (it != used_verts.end()) {
115  return it->second;
116  }
117 
118  int vertex_offset = vertices.size();
119  used_verts[vert_key] = vertex_offset;
120  vertices.push_back(v);
121  return vertex_offset;
122 }
123 
124 static void create_quad(int3 corners[8],
125  vector<int3> &vertices,
126  vector<QuadData> &quads,
127  int3 res,
128  unordered_map<size_t, int> &used_verts,
129  int face_index)
130 {
131  QuadData quad;
132  quad.v0 = add_vertex(corners[quads_indices[face_index][0]], vertices, res, used_verts);
133  quad.v1 = add_vertex(corners[quads_indices[face_index][1]], vertices, res, used_verts);
134  quad.v2 = add_vertex(corners[quads_indices[face_index][2]], vertices, res, used_verts);
135  quad.v3 = add_vertex(corners[quads_indices[face_index][3]], vertices, res, used_verts);
136  quad.normal = quads_normals[face_index];
137 
138  quads.push_back(quad);
139 }
140 #endif
141 
142 /* Create a mesh from a volume.
143  *
144  * The way the algorithm works is as follows:
145  *
146  * - The topologies of input OpenVDB grids are merged into a temporary grid.
147  * - Voxels of the temporary grid are dilated to account for the padding necessary for volume
148  * sampling.
149  * - Quads are created on the boundary between active and inactive leaf nodes of the temporary
150  * grid.
151  */
153  public:
154 #ifdef WITH_OPENVDB
155  /* use a MaskGrid to store the topology to save memory */
156  openvdb::MaskGrid::Ptr topology_grid;
157  openvdb::CoordBBox bbox;
158 #endif
160 
162 
163 #ifdef WITH_OPENVDB
164  void add_grid(openvdb::GridBase::ConstPtr grid, bool do_clipping, float volume_clipping);
165 #endif
166 
167  void add_padding(int pad_size);
168 
169  void create_mesh(vector<float3> &vertices,
171  vector<float3> &face_normals,
172  const float face_overlap_avoidance);
173 
174  void generate_vertices_and_quads(vector<int3> &vertices_is, vector<QuadData> &quads);
175 
176  void convert_object_space(const vector<int3> &vertices,
177  vector<float3> &out_vertices,
178  const float face_overlap_avoidance);
179 
180  void convert_quads_to_tris(const vector<QuadData> &quads,
181  vector<int> &tris,
182  vector<float3> &face_normals);
183 
184  bool empty_grid() const;
185 
186 #ifdef WITH_OPENVDB
187  template<typename GridType>
188  void merge_grid(openvdb::GridBase::ConstPtr grid, bool do_clipping, float volume_clipping)
189  {
190  typename GridType::ConstPtr typed_grid = openvdb::gridConstPtrCast<GridType>(grid);
191 
192  if (do_clipping) {
193  using ValueType = typename GridType::ValueType;
194  typename GridType::Ptr copy = typed_grid->deepCopy();
195  typename GridType::ValueOnIter iter = copy->beginValueOn();
196 
197  for (; iter; ++iter) {
198  if (iter.getValue() < ValueType(volume_clipping)) {
199  iter.setValueOff();
200  }
201  }
202 
203  typed_grid = copy;
204  }
205 
206  topology_grid->topologyUnion(*typed_grid);
207  }
208 #endif
209 };
210 
212 {
213  first_grid = true;
214 }
215 
216 #ifdef WITH_OPENVDB
217 void VolumeMeshBuilder::add_grid(openvdb::GridBase::ConstPtr grid,
218  bool do_clipping,
219  float volume_clipping)
220 {
221  /* set the transform of our grid from the first one */
222  if (first_grid) {
223  topology_grid = openvdb::MaskGrid::create();
224  topology_grid->setTransform(grid->transform().copy());
225  first_grid = false;
226  }
227  /* if the transforms do not match, we need to resample one of the grids so that
228  * its index space registers with that of the other, here we resample our mask
229  * grid so memory usage is kept low */
230  else if (topology_grid->transform() != grid->transform()) {
231  openvdb::MaskGrid::Ptr temp_grid = topology_grid->copyWithNewTree();
232  temp_grid->setTransform(grid->transform().copy());
233  openvdb::tools::resampleToMatch<openvdb::tools::BoxSampler>(*topology_grid, *temp_grid);
234  topology_grid = temp_grid;
235  topology_grid->setTransform(grid->transform().copy());
236  }
237 
238  if (grid->isType<openvdb::FloatGrid>()) {
239  merge_grid<openvdb::FloatGrid>(grid, do_clipping, volume_clipping);
240  }
241  else if (grid->isType<openvdb::Vec3fGrid>()) {
242  merge_grid<openvdb::Vec3fGrid>(grid, do_clipping, volume_clipping);
243  }
244  else if (grid->isType<openvdb::Vec4fGrid>()) {
245  merge_grid<openvdb::Vec4fGrid>(grid, do_clipping, volume_clipping);
246  }
247  else if (grid->isType<openvdb::BoolGrid>()) {
248  merge_grid<openvdb::BoolGrid>(grid, do_clipping, volume_clipping);
249  }
250  else if (grid->isType<openvdb::DoubleGrid>()) {
251  merge_grid<openvdb::DoubleGrid>(grid, do_clipping, volume_clipping);
252  }
253  else if (grid->isType<openvdb::Int32Grid>()) {
254  merge_grid<openvdb::Int32Grid>(grid, do_clipping, volume_clipping);
255  }
256  else if (grid->isType<openvdb::Int64Grid>()) {
257  merge_grid<openvdb::Int64Grid>(grid, do_clipping, volume_clipping);
258  }
259  else if (grid->isType<openvdb::Vec3IGrid>()) {
260  merge_grid<openvdb::Vec3IGrid>(grid, do_clipping, volume_clipping);
261  }
262  else if (grid->isType<openvdb::Vec3dGrid>()) {
263  merge_grid<openvdb::Vec3dGrid>(grid, do_clipping, volume_clipping);
264  }
265  else if (grid->isType<openvdb::MaskGrid>()) {
266  topology_grid->topologyUnion(*openvdb::gridConstPtrCast<openvdb::MaskGrid>(grid));
267  }
268 }
269 #endif
270 
272 {
273 #ifdef WITH_OPENVDB
274  openvdb::tools::dilateVoxels(topology_grid->tree(), pad_size);
275 #else
276  (void)pad_size;
277 #endif
278 }
279 
282  vector<float3> &face_normals,
283  const float face_overlap_avoidance)
284 {
285 #ifdef WITH_OPENVDB
286  /* We create vertices in index space (is), and only convert them to object
287  * space when done. */
288  vector<int3> vertices_is;
289  vector<QuadData> quads;
290 
291  /* make sure we only have leaf nodes in the tree, as tiles are not handled by
292  * this algorithm */
293  topology_grid->tree().voxelizeActiveTiles();
294 
295  generate_vertices_and_quads(vertices_is, quads);
296 
297  convert_object_space(vertices_is, vertices, face_overlap_avoidance);
298 
299  convert_quads_to_tris(quads, indices, face_normals);
300 #else
301  (void)vertices;
302  (void)indices;
303  (void)face_normals;
304  (void)face_overlap_avoidance;
305 #endif
306 }
307 
309  vector<QuadData> &quads)
310 {
311 #ifdef WITH_OPENVDB
312  const openvdb::MaskGrid::TreeType &tree = topology_grid->tree();
313  tree.evalLeafBoundingBox(bbox);
314 
315  const int3 resolution = make_int3(bbox.dim().x(), bbox.dim().y(), bbox.dim().z());
316 
317  unordered_map<size_t, int> used_verts;
318 
319  for (auto iter = tree.cbeginLeaf(); iter; ++iter) {
320  openvdb::CoordBBox leaf_bbox = iter->getNodeBoundingBox();
321  /* +1 to convert from exclusive to include bounds. */
322  leaf_bbox.max() = leaf_bbox.max().offsetBy(1);
323 
324  int3 min = make_int3(leaf_bbox.min().x(), leaf_bbox.min().y(), leaf_bbox.min().z());
325  int3 max = make_int3(leaf_bbox.max().x(), leaf_bbox.max().y(), leaf_bbox.max().z());
326 
327  int3 corners[8] = {
328  make_int3(min[0], min[1], min[2]),
329  make_int3(max[0], min[1], min[2]),
330  make_int3(max[0], max[1], min[2]),
331  make_int3(min[0], max[1], min[2]),
332  make_int3(min[0], min[1], max[2]),
333  make_int3(max[0], min[1], max[2]),
334  make_int3(max[0], max[1], max[2]),
335  make_int3(min[0], max[1], max[2]),
336  };
337 
338  /* Only create a quad if on the border between an active and an inactive leaf.
339  *
340  * We verify that a leaf exists by probing a coordinate that is at its center,
341  * to do so we compute the center of the current leaf and offset this coordinate
342  * by the size of a leaf in each direction.
343  */
344  static const int LEAF_DIM = openvdb::MaskGrid::TreeType::LeafNodeType::DIM;
345  auto center = leaf_bbox.min() + openvdb::Coord(LEAF_DIM / 2);
346 
347  if (!tree.probeLeaf(openvdb::Coord(center.x() - LEAF_DIM, center.y(), center.z()))) {
348  create_quad(corners, vertices_is, quads, resolution, used_verts, QUAD_X_MIN);
349  }
350 
351  if (!tree.probeLeaf(openvdb::Coord(center.x() + LEAF_DIM, center.y(), center.z()))) {
352  create_quad(corners, vertices_is, quads, resolution, used_verts, QUAD_X_MAX);
353  }
354 
355  if (!tree.probeLeaf(openvdb::Coord(center.x(), center.y() - LEAF_DIM, center.z()))) {
356  create_quad(corners, vertices_is, quads, resolution, used_verts, QUAD_Y_MIN);
357  }
358 
359  if (!tree.probeLeaf(openvdb::Coord(center.x(), center.y() + LEAF_DIM, center.z()))) {
360  create_quad(corners, vertices_is, quads, resolution, used_verts, QUAD_Y_MAX);
361  }
362 
363  if (!tree.probeLeaf(openvdb::Coord(center.x(), center.y(), center.z() - LEAF_DIM))) {
364  create_quad(corners, vertices_is, quads, resolution, used_verts, QUAD_Z_MIN);
365  }
366 
367  if (!tree.probeLeaf(openvdb::Coord(center.x(), center.y(), center.z() + LEAF_DIM))) {
368  create_quad(corners, vertices_is, quads, resolution, used_verts, QUAD_Z_MAX);
369  }
370  }
371 #else
372  (void)vertices_is;
373  (void)quads;
374 #endif
375 }
376 
378  vector<float3> &out_vertices,
379  const float face_overlap_avoidance)
380 {
381 #ifdef WITH_OPENVDB
382  /* compute the offset for the face overlap avoidance */
383  bbox = topology_grid->evalActiveVoxelBoundingBox();
384  openvdb::Coord dim = bbox.dim();
385 
386  float3 cell_size = make_float3(1.0f / dim.x(), 1.0f / dim.y(), 1.0f / dim.z());
387  float3 point_offset = cell_size * face_overlap_avoidance;
388 
389  out_vertices.reserve(vertices.size());
390 
391  for (size_t i = 0; i < vertices.size(); ++i) {
392  openvdb::math::Vec3d p = topology_grid->indexToWorld(
393  openvdb::math::Vec3d(vertices[i].x, vertices[i].y, vertices[i].z));
394  float3 vertex = make_float3((float)p.x(), (float)p.y(), (float)p.z());
395  out_vertices.push_back(vertex + point_offset);
396  }
397 #else
398  (void)vertices;
399  (void)out_vertices;
400  (void)face_overlap_avoidance;
401 #endif
402 }
403 
405  vector<int> &tris,
406  vector<float3> &face_normals)
407 {
408  int index_offset = 0;
409  tris.resize(quads.size() * 6);
410  face_normals.reserve(quads.size() * 2);
411 
412  for (size_t i = 0; i < quads.size(); ++i) {
413  tris[index_offset++] = quads[i].v0;
414  tris[index_offset++] = quads[i].v2;
415  tris[index_offset++] = quads[i].v1;
416 
417  face_normals.push_back(quads[i].normal);
418 
419  tris[index_offset++] = quads[i].v0;
420  tris[index_offset++] = quads[i].v3;
421  tris[index_offset++] = quads[i].v2;
422 
423  face_normals.push_back(quads[i].normal);
424  }
425 }
426 
428 {
429 #ifdef WITH_OPENVDB
430  return !topology_grid || topology_grid->tree().leafCount() == 0;
431 #else
432  return true;
433 #endif
434 }
435 
436 #ifdef WITH_OPENVDB
437 template<typename GridType>
438 static openvdb::GridBase::ConstPtr openvdb_grid_from_device_texture(device_texture *image_memory,
439  float volume_clipping,
440  Transform transform_3d)
441 {
442  using ValueType = typename GridType::ValueType;
443 
444  openvdb::CoordBBox dense_bbox(0,
445  0,
446  0,
447  image_memory->data_width - 1,
448  image_memory->data_height - 1,
449  image_memory->data_depth - 1);
450 
451  typename GridType::Ptr sparse = GridType::create(ValueType(0.0f));
452  if (dense_bbox.empty()) {
453  return sparse;
454  }
455 
456  openvdb::tools::Dense<ValueType, openvdb::tools::MemoryLayout::LayoutXYZ> dense(
457  dense_bbox, static_cast<ValueType *>(image_memory->host_pointer));
458 
459  openvdb::tools::copyFromDense(dense, *sparse, ValueType(volume_clipping));
460 
461  /* #copyFromDense will remove any leaf node that contains constant data and replace it with a
462  * tile, however, we need to preserve the leaves in order to generate the mesh, so re-voxelize
463  * the leaves that were pruned. This should not affect areas that were skipped due to the
464  * volume_clipping parameter. */
465  sparse->tree().voxelizeActiveTiles();
466 
467  /* Compute index to world matrix. */
468  float3 voxel_size = make_float3(1.0f / image_memory->data_width,
469  1.0f / image_memory->data_height,
470  1.0f / image_memory->data_depth);
471 
472  transform_3d = transform_inverse(transform_3d);
473 
474  openvdb::Mat4R index_to_world_mat((double)(voxel_size.x * transform_3d[0][0]),
475  0.0,
476  0.0,
477  0.0,
478  0.0,
479  (double)(voxel_size.y * transform_3d[1][1]),
480  0.0,
481  0.0,
482  0.0,
483  0.0,
484  (double)(voxel_size.z * transform_3d[2][2]),
485  0.0,
486  (double)transform_3d[0][3],
487  (double)transform_3d[1][3],
488  (double)transform_3d[2][3],
489  1.0);
490 
491  openvdb::math::Transform::Ptr index_to_world_tfm =
492  openvdb::math::Transform::createLinearTransform(index_to_world_mat);
493 
494  sparse->setTransform(index_to_world_tfm);
495 
496  return sparse;
497 }
498 #endif
499 
500 /* ************************************************************************** */
501 
503 {
504  string msg = string_printf("Computing Volume Mesh %s", volume->name.c_str());
505  progress.set_status("Updating Mesh", msg);
506 
507  /* Find shader and compute padding based on volume shader interpolation settings. */
508  Shader *volume_shader = NULL;
509  int pad_size = 0;
510 
511  foreach (Node *node, volume->get_used_shaders()) {
512  Shader *shader = static_cast<Shader *>(node);
513 
514  if (!shader->has_volume) {
515  continue;
516  }
517 
518  volume_shader = shader;
519 
520  if (shader->get_volume_interpolation_method() == VOLUME_INTERPOLATION_LINEAR) {
521  pad_size = max(1, pad_size);
522  }
523  else if (shader->get_volume_interpolation_method() == VOLUME_INTERPOLATION_CUBIC) {
524  pad_size = max(2, pad_size);
525  }
526 
527  break;
528  }
529 
530  /* Clear existing volume mesh, done here in case we early out due to
531  * empty grid or missing volume shader.
532  * Also keep the shaders to avoid infinite loops when synchronizing, as this will tag the shaders
533  * as having changed. */
534  volume->clear(true);
535  volume->need_update_rebuild = true;
536 
537  if (!volume_shader) {
538  return;
539  }
540 
541  /* Create volume mesh builder. */
542  VolumeMeshBuilder builder;
543 
544 #ifdef WITH_OPENVDB
545  foreach (Attribute &attr, volume->attributes.attributes) {
546  if (attr.element != ATTR_ELEMENT_VOXEL) {
547  continue;
548  }
549 
550  bool do_clipping = false;
551 
552  ImageHandle &handle = attr.data_voxel();
553 
554  /* Try building from OpenVDB grid directly. */
555  VDBImageLoader *vdb_loader = handle.vdb_loader();
556  openvdb::GridBase::ConstPtr grid;
557  if (vdb_loader) {
558  grid = vdb_loader->get_grid();
559 
560  /* If building from an OpenVDB grid, we need to manually clip the values. */
561  do_clipping = true;
562  }
563 
564  /* Else fall back to creating an OpenVDB grid from the dense volume data. */
565  if (!grid) {
566  device_texture *image_memory = handle.image_memory();
567 
568  if (image_memory->data_elements == 1) {
569  grid = openvdb_grid_from_device_texture<openvdb::FloatGrid>(
570  image_memory, volume->get_clipping(), handle.metadata().transform_3d);
571  }
572  else if (image_memory->data_elements == 3) {
573  grid = openvdb_grid_from_device_texture<openvdb::Vec3fGrid>(
574  image_memory, volume->get_clipping(), handle.metadata().transform_3d);
575  }
576  else if (image_memory->data_elements == 4) {
577  grid = openvdb_grid_from_device_texture<openvdb::Vec4fGrid>(
578  image_memory, volume->get_clipping(), handle.metadata().transform_3d);
579  }
580  }
581 
582  if (grid) {
583  builder.add_grid(grid, do_clipping, volume->get_clipping());
584  }
585  }
586 #endif
587 
588  /* If nothing to build, early out. */
589  if (builder.empty_grid()) {
590  return;
591  }
592 
593  builder.add_padding(pad_size);
594 
595  /* Slightly offset vertex coordinates to avoid overlapping faces with other
596  * volumes or meshes. The proper solution would be to improve intersection in
597  * the kernel to support robust handling of multiple overlapping faces or use
598  * an all-hit intersection similar to shadows. */
599  const float face_overlap_avoidance = 0.1f *
600  hash_uint_to_float(hash_string(volume->name.c_str()));
601 
602  /* Create mesh. */
603  vector<float3> vertices;
605  vector<float3> face_normals;
606  builder.create_mesh(vertices, indices, face_normals, face_overlap_avoidance);
607 
608  volume->reserve_mesh(vertices.size(), indices.size() / 3);
609  volume->used_shaders.clear();
610  volume->used_shaders.push_back_slow(volume_shader);
611 
612  for (size_t i = 0; i < vertices.size(); ++i) {
613  volume->add_vertex(vertices[i]);
614  }
615 
616  for (size_t i = 0; i < indices.size(); i += 3) {
617  volume->add_triangle(indices[i], indices[i + 1], indices[i + 2], 0, false);
618  }
619 
620  Attribute *attr_fN = volume->attributes.add(ATTR_STD_FACE_NORMAL);
621  float3 *fN = attr_fN->data_float3();
622 
623  for (size_t i = 0; i < face_normals.size(); ++i) {
624  fN[i] = face_normals[i];
625  }
626 
627  /* Print stats. */
628  VLOG(1) << "Memory usage volume mesh: "
629  << ((vertices.size() + face_normals.size()) * sizeof(float3) +
630  indices.size() * sizeof(int)) /
631  (1024.0 * 1024.0)
632  << "Mb.";
633 }
634 
NSNotificationCenter * center
_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 GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble z
_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 type
_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 y
ATTR_WARN_UNUSED_RESULT const BMVert * v
Attribute * add(ustring name, TypeDesc type, AttributeElement element)
Definition: attribute.cpp:428
list< Attribute > attributes
Definition: attribute.h:181
ImageHandle & data_voxel()
Definition: attribute.h:113
AttributeElement element
Definition: attribute.h:54
float3 * data_float3()
Definition: attribute.h:86
void create_volume_mesh(Volume *volume, Progress &progress)
Definition: volume.cpp:502
bool need_update_rebuild
Definition: geometry.h:110
AttributeSet attributes
Definition: geometry.h:81
VDBImageLoader * vdb_loader(const int tile_index=0) const
Definition: image.cpp:180
device_texture * image_memory(const int tile_index=0) const
Definition: image.cpp:170
ImageMetaData metadata()
Definition: image.cpp:143
Transform transform_3d
void set_status(const string &status_, const string &substatus_="")
Definition: shader.h:80
void convert_quads_to_tris(const vector< QuadData > &quads, vector< int > &tris, vector< float3 > &face_normals)
Definition: volume.cpp:404
void add_padding(int pad_size)
Definition: volume.cpp:271
bool empty_grid() const
Definition: volume.cpp:427
void convert_object_space(const vector< int3 > &vertices, vector< float3 > &out_vertices, const float face_overlap_avoidance)
Definition: volume.cpp:377
void create_mesh(vector< float3 > &vertices, vector< int > &indices, vector< float3 > &face_normals, const float face_overlap_avoidance)
Definition: volume.cpp:280
void generate_vertices_and_quads(vector< int3 > &vertices_is, vector< QuadData > &quads)
Definition: volume.cpp:308
size_t data_height
void * host_pointer
OperationNode * node
void * tree
static ushort indices[]
GPUBatch * quad
IconTextureDrawCall normal
#define CCL_NAMESPACE_END
#define make_int3(x, y, z)
#define make_float3(x, y, z)
void KERNEL_FUNCTION_FULL_NAME() shader(KernelGlobals *kg, uint4 *input, float4 *output, int type, int filter, int i, int offset, int sample)
@ ATTR_STD_FACE_NORMAL
Definition: kernel_types.h:747
@ ATTR_ELEMENT_VOXEL
Definition: kernel_types.h:741
VecMat::Vec3< double > Vec3d
Definition: Geom.h:41
static void copy(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node)
#define SOCKET_FLOAT(name, ui_name, default_value,...)
Definition: node_type.h:204
#define SOCKET_BOOLEAN(name, ui_name, default_value,...)
Definition: node_type.h:198
@ VOLUME_INTERPOLATION_LINEAR
Definition: shader.h:60
@ VOLUME_INTERPOLATION_CUBIC
Definition: shader.h:61
#define min(a, b)
Definition: sort.c:51
void clear(bool preserve_shaders=false) override
Definition: mesh.cpp:325
void reserve_mesh(int numverts, int numfaces)
Definition: mesh.cpp:230
void add_vertex(float3 P)
Definition: mesh.cpp:330
void add_triangle(int v0, int v1, int v2, int shader, bool smooth)
Definition: mesh.cpp:352
static NodeType * add(const char *name, CreateFunc create, Type type=NONE, const NodeType *base=NULL)
Definition: node.h:98
ustring name
Definition: node.h:174
float3 normal
Definition: volume.cpp:63
int v2
Definition: volume.cpp:61
int v3
Definition: volume.cpp:61
int v1
Definition: volume.cpp:61
int v0
Definition: volume.cpp:61
NODE_DECLARE Volume()
Definition: volume.cpp:48
virtual void clear(bool preserve_shaders=false) override
Definition: volume.cpp:55
float z
Definition: sky_float3.h:35
float y
Definition: sky_float3.h:35
float x
Definition: sky_float3.h:35
float max
static uint hash_string(const char *str)
Definition: util_hash.h:376
ccl_device_inline float hash_uint_to_float(uint kx)
Definition: util_hash.h:130
#define VLOG(severity)
Definition: util_logging.h:50
CCL_NAMESPACE_BEGIN string string_printf(const char *format,...)
Definition: util_string.cpp:32
Transform transform_inverse(const Transform &tfm)
@ QUAD_X_MAX
Definition: volume.cpp:68
@ QUAD_Y_MIN
Definition: volume.cpp:69
@ QUAD_Z_MIN
Definition: volume.cpp:71
@ QUAD_Y_MAX
Definition: volume.cpp:70
@ QUAD_X_MIN
Definition: volume.cpp:67
@ QUAD_Z_MAX
Definition: volume.cpp:72
CCL_NAMESPACE_BEGIN NODE_DEFINE(Volume)
Definition: volume.cpp:37