[Bf-blender-cvs] [9280fb19e4f] blender-v2.90-release: Fixes T77882: artifacts rendering OpenVDB volumes with multiple grids in Cycles

Kévin Dietrich noreply at git.blender.org
Wed Aug 12 12:07:12 CEST 2020


Commit: 9280fb19e4ff5038734d9867d152c10d4daf03bb
Author: Kévin Dietrich
Date:   Tue Aug 11 17:34:34 2020 +0200
Branches: blender-v2.90-release
https://developer.blender.org/rB9280fb19e4ff5038734d9867d152c10d4daf03bb

Fixes T77882: artifacts rendering OpenVDB volumes with multiple grids in Cycles

The previous algorithm was not using all of the requested grids to build a mesh
around the volume due to limitations regarding the use of a dense buffer to
gather information about the volume's topology. This resulted in artefacts during
rendering.

The mesh generation is now done by merging all of the input grids and using the
resulting grid's topology to create the mesh. The generation of the mesh
is still done in index space as before, and the vertices are converted to object
space by using the merged topology grid indexToWorld transform.

To be able to merge the grids together we have to make sure that their transformation
matrices and their index spaces match, thus, if they do not match we simply resample
the grids. This behaviour should tackle one other limitation of the current algorithm,
which is that only one transformation matrix was used to generate the final mesh.

If we do not have an OpenVDB grid for the requested volume data, we generate
a temporary OpenVDB grid for it.

Differential Revision: https://developer.blender.org/D8401

===================================================================

M	intern/cycles/render/geometry.cpp
M	intern/cycles/render/image.cpp
M	intern/cycles/render/image.h
M	intern/cycles/render/image_vdb.cpp
M	intern/cycles/render/image_vdb.h
M	intern/cycles/render/mesh_volume.cpp
M	intern/cycles/util/CMakeLists.txt
A	intern/cycles/util/util_openvdb.h

===================================================================

diff --git a/intern/cycles/render/geometry.cpp b/intern/cycles/render/geometry.cpp
index 3d1b6e1d865..145b1fa492c 100644
--- a/intern/cycles/render/geometry.cpp
+++ b/intern/cycles/render/geometry.cpp
@@ -1201,9 +1201,13 @@ void GeometryManager::device_update_volume_images(Device *device, Scene *scene,
       }
 
       ImageHandle &handle = attr.data_voxel();
-      const int slot = handle.svm_slot();
-      if (slot != -1) {
-        volume_images.insert(slot);
+      /* We can build directly from OpenVDB data structures, no need to
+       * load such images early. */
+      if (!handle.vdb_loader()) {
+        const int slot = handle.svm_slot();
+        if (slot != -1) {
+          volume_images.insert(slot);
+        }
       }
     }
   }
diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp
index 691eb162dd0..a5dfcf60d61 100644
--- a/intern/cycles/render/image.cpp
+++ b/intern/cycles/render/image.cpp
@@ -18,6 +18,7 @@
 #include "device/device.h"
 #include "render/colorspace.h"
 #include "render/image_oiio.h"
+#include "render/image_vdb.h"
 #include "render/scene.h"
 #include "render/stats.h"
 
@@ -172,6 +173,31 @@ device_texture *ImageHandle::image_memory(const int tile_index) const
   return img ? img->mem : NULL;
 }
 
+VDBImageLoader *ImageHandle::vdb_loader(const int tile_index) const
+{
+  if (tile_index >= tile_slots.size()) {
+    return NULL;
+  }
+
+  ImageManager::Image *img = manager->images[tile_slots[tile_index]];
+
+  if (img == NULL) {
+    return NULL;
+  }
+
+  ImageLoader *loader = img->loader;
+
+  if (loader == NULL) {
+    return NULL;
+  }
+
+  if (loader->is_vdb_loader()) {
+    return dynamic_cast<VDBImageLoader *>(loader);
+  }
+
+  return NULL;
+}
+
 bool ImageHandle::operator==(const ImageHandle &other) const
 {
   return manager == other.manager && tile_slots == other.tile_slots;
@@ -258,6 +284,11 @@ bool ImageLoader::equals(const ImageLoader *a, const ImageLoader *b)
   }
 }
 
+bool ImageLoader::is_vdb_loader() const
+{
+  return false;
+}
+
 /* Image Manager */
 
 ImageManager::ImageManager(const DeviceInfo &info)
diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h
index 47be0ee559a..cb059256ce3 100644
--- a/intern/cycles/render/image.h
+++ b/intern/cycles/render/image.h
@@ -39,6 +39,7 @@ class Progress;
 class RenderStats;
 class Scene;
 class ColorSpaceProcessor;
+class VDBImageLoader;
 
 /* Image Parameters */
 class ImageParams {
@@ -124,6 +125,8 @@ class ImageLoader {
   virtual bool equals(const ImageLoader &other) const = 0;
   static bool equals(const ImageLoader *a, const ImageLoader *b);
 
+  virtual bool is_vdb_loader() const;
+
   /* Work around for no RTTI. */
 };
 
@@ -149,6 +152,8 @@ class ImageHandle {
   int svm_slot(const int tile_index = 0) const;
   device_texture *image_memory(const int tile_index = 0) const;
 
+  VDBImageLoader *vdb_loader(const int tile_index = 0) const;
+
  protected:
   vector<int> tile_slots;
   ImageManager *manager;
diff --git a/intern/cycles/render/image_vdb.cpp b/intern/cycles/render/image_vdb.cpp
index 500131c2d84..3f7dd45ee88 100644
--- a/intern/cycles/render/image_vdb.cpp
+++ b/intern/cycles/render/image_vdb.cpp
@@ -185,4 +185,16 @@ void VDBImageLoader::cleanup()
 #endif
 }
 
+bool VDBImageLoader::is_vdb_loader() const
+{
+  return true;
+}
+
+#ifdef WITH_OPENVDB
+openvdb::GridBase::ConstPtr VDBImageLoader::get_grid()
+{
+  return grid;
+}
+#endif
+
 CCL_NAMESPACE_END
diff --git a/intern/cycles/render/image_vdb.h b/intern/cycles/render/image_vdb.h
index 7dec63b11e6..4500cfbfb88 100644
--- a/intern/cycles/render/image_vdb.h
+++ b/intern/cycles/render/image_vdb.h
@@ -43,6 +43,12 @@ class VDBImageLoader : public ImageLoader {
 
   virtual void cleanup() override;
 
+  virtual bool is_vdb_loader() const override;
+
+#ifdef WITH_OPENVDB
+  openvdb::GridBase::ConstPtr get_grid();
+#endif
+
  protected:
   string grid_name;
 #ifdef WITH_OPENVDB
diff --git a/intern/cycles/render/mesh_volume.cpp b/intern/cycles/render/mesh_volume.cpp
index 607363d01c6..70189ea4812 100644
--- a/intern/cycles/render/mesh_volume.cpp
+++ b/intern/cycles/render/mesh_volume.cpp
@@ -15,34 +15,25 @@
  */
 
 #include "render/attribute.h"
+#include "render/image_vdb.h"
 #include "render/mesh.h"
 #include "render/scene.h"
 
+#ifdef WITH_OPENVDB
+#  include <openvdb/tools/Dense.h>
+#  include <openvdb/tools/GridTransformer.h>
+#  include <openvdb/tools/Morphology.h>
+#endif
+
 #include "util/util_foreach.h"
 #include "util/util_hash.h"
 #include "util/util_logging.h"
+#include "util/util_openvdb.h"
 #include "util/util_progress.h"
 #include "util/util_types.h"
 
 CCL_NAMESPACE_BEGIN
 
-const int64_t VOXEL_INDEX_NONE = -1;
-
-static int64_t compute_voxel_index(const int3 &resolution, int64_t x, int64_t y, int64_t z)
-{
-  if (x < 0 || x >= resolution.x) {
-    return VOXEL_INDEX_NONE;
-  }
-  else if (y < 0 || y >= resolution.y) {
-    return VOXEL_INDEX_NONE;
-  }
-  else if (z < 0 || z >= resolution.z) {
-    return VOXEL_INDEX_NONE;
-  }
-
-  return x + y * resolution.x + z * resolution.x * resolution.y;
-}
-
 struct QuadData {
   int v0, v1, v2, v3;
 
@@ -123,122 +114,146 @@ static void create_quad(int3 corners[8],
   quads.push_back(quad);
 }
 
-struct VolumeParams {
-  int3 resolution;
-  float3 cell_size;
-  float3 start_point;
-  int pad_size;
-};
-
-static const int CUBE_SIZE = 8;
-
 /* Create a mesh from a volume.
  *
  * The way the algorithm works is as follows:
  *
- * - The coordinates of active voxels from a dense volume (or 3d image) are
- *   gathered inside an auxiliary volume.
- * - Each set of coordinates of an CUBE_SIZE cube are mapped to the same
- *   coordinate of the auxiliary volume.
- * - Quads are created between active and non-active voxels in the auxiliary
- *   volume to generate a tight mesh around the volume.
+ * - The topologies of input OpenVDB grids are merged into a temporary grid.
+ * - Voxels of the temporary grid are dilated to account for the padding necessary for volume
+ * sampling.
+ * - Quads are created on the boundary between active and inactive leaf nodes of the temporary
+ * grid.
  */
 class VolumeMeshBuilder {
-  /* Auxiliary volume that is used to check if a node already added. */
-  vector<char> grid;
-
-  /* The resolution of the auxiliary volume, set to be equal to 1/CUBE_SIZE
-   * of the original volume on each axis. */
-  int3 res;
-
-  size_t number_of_nodes;
-
-  /* Offset due to padding in the original grid. Padding will transform the
-   * coordinates of the original grid from 0...res to -padding...res+padding,
-   * so some coordinates are negative, and we need to properly account for
-   * them. */
-  int3 pad_offset;
-
-  VolumeParams *params;
-
  public:
-  VolumeMeshBuilder(VolumeParams *volume_params);
+#ifdef WITH_OPENVDB
+  /* use a MaskGrid to store the topology to save memory */
+  openvdb::MaskGrid::Ptr topology_grid;
+  openvdb::CoordBBox bbox;
+#endif
+  bool first_grid;
 
-  void add_node(int x, int y, int z);
+  VolumeMeshBuilder();
 
-  void add_node_with_padding(int x, int y, int z);
+#ifdef WITH_OPENVDB
+  void add_grid(openvdb::GridBase::ConstPtr grid, bool do_clipping, float volume_clipping);
+#endif
 
-  void create_mesh(vector<float3> &vertices, vector<int> &indices, vector<float3> &face_normals);
+  void add_padding(int pad_size);
+
+  void create_mesh(vector<float3> &vertices,
+                   vector<int> &indices,
+                   vector<float3> &face_normals,
+                   const float face_overlap_avoidance);
 
- private:
   void generate_vertices_and_quads(vector<int3> &vertices_is, vector<QuadData> &quads);
 
-  void convert_object_space(const vector<int3> &vertices, vector<float3> &out_vertices);
+  void convert_object_space(const vector<int3> &vertices,
+                            vector<float3> &out_vertices,
+                            const float face_overlap_avoidance);
 
   void convert_quads_to_tris(const vector<QuadData> &quads,
                              vector<int> &tris,
                              vector<float3> &face_normals);
-};
 
-VolumeMeshBuilder::VolumeMeshBuilder(VolumeParams *volume_params)
-{
-  params = volume_params;
-  number_of_nodes = 0;
+  bool empty_grid() const;
 
-  const int64_t x = divide_up(params->resolution.x, CUBE_SIZE);
-  const int64_t y = divide_up(params->resolution.y, CUBE_SIZE);
-  const int64_t z = divide_up(params->resolution.z, CUBE_SIZE);
+#ifdef WITH_OPENVDB
+  template <typename GridType>
+  void merge_grid(openvdb::GridBase::ConstPtr grid, bool do_clipping, float volume_clipping)
+  {
+    typename GridType::ConstPtr typed_grid = openvdb::gridConstPtrCast<GridType>(grid);
 
-  /* Adding 2*pad_size since we pad in both positive and negative directions
-   * along the axis. */
-  const int64_t px = divide_up(params->resolution.x + 2 * params->pad_size, CUBE_SIZE);
-  const int64_t py = divide_up(params->resolution.y + 2 * params->pad_size, CUBE_SIZE);
-  const int64_t pz = divide_up(params->resolution.z + 2 * params->pad_size, CUBE_SIZE);
+    if (do_clipping) {
+      using ValueType = typename GridType::ValueType;
+      typename GridType::Ptr copy = typed_grid->deepCopy();
+      typename GridType::ValueOnIter iter = copy->beginValueOn();
 
-  res = make_int3(px, py, pz);
-  pad_offset = make_int3(px - x, py - y, pz - z);
+      for (; iter; ++iter) {
+        if (iter.getValue() < ValueType(volume_clipping)) {
+          iter.setValueOff();
+        }
+      }
 
-  grid.resize(px * py * pz, 0);
-}
+      typed_grid = copy;
+    }
 
-void VolumeMeshBuilder::add_node(int x, int y, int z)
-{
-  /* Map coordinates to index space. */
-  const int index_x = (x / CUBE_SIZE) + pad_offset.x;
-  const int index_y = (y / CUBE_SIZE) + pad_offset.y;
-  const int index_z = (z / CUBE_SIZE) + pad_offset.z;
+    topology_grid->topologyUnion(*typed_grid);
+  }
+#endif
+};
 
-  assert((index_x >= 0) && (index_y >= 0) && (index_z >= 0));
+VolumeMeshBuilder::VolumeMeshBuilder()
+{
+  first_grid = true;
+}
 
-  const int64_t index = compute_voxel_index(res, index_x, index_y, index_z);
-  if (index == VOXEL_INDEX_NONE) {
-    return;
+#ifdef WITH_OPENVDB
+void VolumeMeshBuilder::add_grid(openvdb::GridBase::ConstPtr gr

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list