[Bf-blender-cvs] [838c4a97f1d] master: Geometry Nodes: new Volume Cube node

Chris Clyne noreply at git.blender.org
Fri Jun 17 13:34:00 CEST 2022


Commit: 838c4a97f1d6b993f4c866c474eb02d929f0ca1d
Author: Chris Clyne
Date:   Fri Jun 17 13:26:22 2022 +0200
Branches: master
https://developer.blender.org/rB838c4a97f1d6b993f4c866c474eb02d929f0ca1d

Geometry Nodes: new Volume Cube node

This commit adds a Volume Cube primitive node. It outputs a volume that
contains a single "density" float grid. The density per voxel can be
controlled with a field that depends on the voxel position (using the
existing Position node). Other field inputs are not supported.

The density field is evaluated on every voxel.

Possible future improvements are listed in D15198.

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

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

M	release/scripts/startup/nodeitems_builtins.py
M	source/blender/blenkernel/BKE_node.h
M	source/blender/blenkernel/intern/node.cc
M	source/blender/nodes/NOD_geometry.h
M	source/blender/nodes/NOD_static_types.h
M	source/blender/nodes/geometry/CMakeLists.txt
A	source/blender/nodes/geometry/nodes/node_geo_volume_cube.cc

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

diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index fec3447ca6c..a8184b1d84b 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -714,6 +714,7 @@ geometry_node_categories = [
         NodeItem("ShaderNodeVectorRotate"),
     ]),
     GeometryNodeCategory("GEO_VOLUME", "Volume", items=[
+        NodeItem("GeometryNodeVolumeCube"),
         NodeItem("GeometryNodeVolumeToMesh"),
     ]),
     GeometryNodeCategory("GEO_GROUP", "Group", items=node_group_items),
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 7ec8000b6f9..59a1599e7ae 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -1495,6 +1495,7 @@ struct TexResult;
 #define GEO_NODE_REMOVE_ATTRIBUTE 1158
 #define GEO_NODE_INPUT_INSTANCE_ROTATION 1159
 #define GEO_NODE_INPUT_INSTANCE_SCALE 1160
+#define GEO_NODE_VOLUME_CUBE 1161
 
 /** \} */
 
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index 1ffc4a56a0e..e02d3b6486c 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -4836,6 +4836,7 @@ static void registerGeometryNodes()
   register_node_type_geo_translate_instances();
   register_node_type_geo_triangulate();
   register_node_type_geo_viewer();
+  register_node_type_geo_volume_cube();
   register_node_type_geo_volume_to_mesh();
 }
 
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h
index dc90073ec31..e4e4295fd3a 100644
--- a/source/blender/nodes/NOD_geometry.h
+++ b/source/blender/nodes/NOD_geometry.h
@@ -135,6 +135,7 @@ void register_node_type_geo_transform(void);
 void register_node_type_geo_translate_instances(void);
 void register_node_type_geo_triangulate(void);
 void register_node_type_geo_viewer(void);
+void register_node_type_geo_volume_cube(void);
 void register_node_type_geo_volume_to_mesh(void);
 
 #ifdef __cplusplus
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 7ca013bf792..9793f133dd6 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -397,6 +397,7 @@ DefNode(GeometryNode, GEO_NODE_TRANSLATE_INSTANCES, 0, "TRANSLATE_INSTANCES", Tr
 DefNode(GeometryNode, GEO_NODE_TRIANGULATE, def_geo_triangulate, "TRIANGULATE", Triangulate, "Triangulate", "")
 DefNode(GeometryNode, GEO_NODE_TRIM_CURVE, def_geo_curve_trim, "TRIM_CURVE", TrimCurve, "Trim Curve", "")
 DefNode(GeometryNode, GEO_NODE_VIEWER, def_geo_viewer, "VIEWER", Viewer, "Viewer", "")
+DefNode(GeometryNode, GEO_NODE_VOLUME_CUBE, 0, "VOLUME_CUBE", VolumeCube, "Volume Cube", "")
 DefNode(GeometryNode, GEO_NODE_VOLUME_TO_MESH, def_geo_volume_to_mesh, "VOLUME_TO_MESH", VolumeToMesh, "Volume to Mesh", "")
 
 /* undefine macros */
diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt
index 54fda328ca8..015edf2d26c 100644
--- a/source/blender/nodes/geometry/CMakeLists.txt
+++ b/source/blender/nodes/geometry/CMakeLists.txt
@@ -144,6 +144,7 @@ set(SRC
   nodes/node_geo_translate_instances.cc
   nodes/node_geo_triangulate.cc
   nodes/node_geo_viewer.cc
+  nodes/node_geo_volume_cube.cc
   nodes/node_geo_volume_to_mesh.cc
 
   node_geometry_exec.cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_volume_cube.cc b/source/blender/nodes/geometry/nodes/node_geo_volume_cube.cc
new file mode 100644
index 00000000000..d7e9e38ea0d
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_volume_cube.cc
@@ -0,0 +1,197 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifdef WITH_OPENVDB
+#  include <openvdb/openvdb.h>
+#  include <openvdb/tools/Dense.h>
+#  include <openvdb/tools/LevelSetUtil.h>
+#  include <openvdb/tools/ParticlesToLevelSet.h>
+#endif
+
+#include "node_geometry_util.hh"
+
+#include "DNA_mesh_types.h"
+
+#include "BLI_task.hh"
+
+#include "BKE_geometry_set.hh"
+#include "BKE_lib_id.h"
+#include "BKE_mesh.h"
+#include "BKE_volume.h"
+
+namespace blender::nodes::node_geo_volume_cube_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+  b.add_input<decl::Float>(N_("Density"))
+      .description(N_("Volume density per voxel"))
+      .supports_field()
+      .default_value(1.0f);
+  b.add_input<decl::Float>(N_("Background"))
+      .description(N_("Value for voxels outside of the cube"));
+
+  b.add_input<decl::Vector>(N_("Min"))
+      .description(N_("Minimum boundary of volume"))
+      .default_value(float3(-1.0f));
+  b.add_input<decl::Vector>(N_("Max"))
+      .description(N_("Maximum boundary of volume"))
+      .default_value(float3(1.0f));
+
+  b.add_input<decl::Int>(N_("Resolution X"))
+      .description(N_("Number of voxels in the X axis"))
+      .default_value(32)
+      .min(2);
+  b.add_input<decl::Int>(N_("Resolution Y"))
+      .description(N_("Number of voxels in the Y axis"))
+      .default_value(32)
+      .min(2);
+  b.add_input<decl::Int>(N_("Resolution Z"))
+      .description(N_("Number of voxels in the Z axis"))
+      .default_value(32)
+      .min(2);
+
+  b.add_output<decl::Geometry>(N_("Volume"));
+}
+
+static float map(const float x,
+                 const float in_min,
+                 const float in_max,
+                 const float out_min,
+                 const float out_max)
+{
+  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
+}
+
+class Grid3DFieldContext : public FieldContext {
+ private:
+  int3 resolution_;
+  float3 bounds_min_;
+  float3 bounds_max_;
+
+ public:
+  Grid3DFieldContext(const int3 resolution, const float3 bounds_min, const float3 bounds_max)
+      : resolution_(resolution), bounds_min_(bounds_min), bounds_max_(bounds_max)
+  {
+  }
+
+  int64_t points_num() const
+  {
+    return static_cast<int64_t>(resolution_.x) * static_cast<int64_t>(resolution_.y) *
+           static_cast<int64_t>(resolution_.z);
+  }
+
+  GVArray get_varray_for_input(const FieldInput &field_input,
+                               const IndexMask UNUSED(mask),
+                               ResourceScope &UNUSED(scope)) const
+  {
+    const bke::AttributeFieldInput *attribute_field_input =
+        dynamic_cast<const bke::AttributeFieldInput *>(&field_input);
+    if (attribute_field_input == nullptr) {
+      return {};
+    }
+    if (attribute_field_input->attribute_name() != "position") {
+      return {};
+    }
+
+    Array<float3> positions(this->points_num());
+
+    threading::parallel_for(IndexRange(resolution_.x), 1, [&](const IndexRange x_range) {
+      /* Start indexing at current X slice. */
+      int64_t index = x_range.start() * resolution_.y * resolution_.z;
+      for (const int64_t x_i : x_range) {
+        const float x = map(x_i, 0.0f, resolution_.x - 1, bounds_min_.x, bounds_max_.x);
+        for (const int64_t y_i : IndexRange(resolution_.y)) {
+          const float y = map(y_i, 0.0f, resolution_.y - 1, bounds_min_.y, bounds_max_.y);
+          for (const int64_t z_i : IndexRange(resolution_.z)) {
+            const float z = map(z_i, 0.0f, resolution_.z - 1, bounds_min_.z, bounds_max_.z);
+            positions[index] = float3(x, y, z);
+            index++;
+          }
+        }
+      }
+    });
+    return VArray<float3>::ForContainer(std::move(positions));
+  }
+};
+
+#ifdef WITH_OPENVDB
+static void node_geo_exec(GeoNodeExecParams params)
+{
+  const float3 bounds_min = params.extract_input<float3>("Min");
+  const float3 bounds_max = params.extract_input<float3>("Max");
+
+  const int3 resolution = int3(params.extract_input<int>("Resolution X"),
+                               params.extract_input<int>("Resolution Y"),
+                               params.extract_input<int>("Resolution Z"));
+
+  if (resolution.x < 2 || resolution.y < 2 || resolution.z < 2) {
+    params.error_message_add(NodeWarningType::Error, TIP_("Resolution must be greater than 1"));
+    params.set_default_remaining_outputs();
+    return;
+  }
+
+  if (bounds_min.x == bounds_max.x || bounds_min.y == bounds_max.y ||
+      bounds_min.z == bounds_max.z) {
+    params.error_message_add(NodeWarningType::Error,
+                             TIP_("Bounding box volume must be greater than 0"));
+    params.set_default_remaining_outputs();
+    return;
+  }
+
+  Field<float> input_field = params.extract_input<Field<float>>("Density");
+
+  /* Evaluate input field on a 3D grid. */
+  Grid3DFieldContext context(resolution, bounds_min, bounds_max);
+  FieldEvaluator evaluator(context, context.points_num());
+  Array<float> densities(context.points_num());
+  evaluator.add_with_destination(std::move(input_field), densities.as_mutable_span());
+  evaluator.evaluate();
+
+  /* Store resulting values in openvdb grid. */
+  const float background = params.extract_input<float>("Background");
+  openvdb::FloatGrid::Ptr grid = openvdb::FloatGrid::create(background);
+  grid->setGridClass(openvdb::GRID_FOG_VOLUME);
+
+  openvdb::tools::Dense<float, openvdb::tools::LayoutZYX> dense_grid{
+      openvdb::math::CoordBBox({0, 0, 0}, {resolution.x - 1, resolution.y - 1, resolution.z - 1}),
+      densities.data()};
+  openvdb::tools::copyFromDense(dense_grid, *grid, 0.0f);
+
+  grid->transform().preTranslate(openvdb::math::Vec3<float>(-0.5f));
+  const float3 scale_fac = (bounds_max - bounds_min) / float3(resolution - 1);
+  grid->transform().postScale(openvdb::math::Vec3<float>(scale_fac.x, scale_fac.y, scale_fac.z));
+  grid->transform().postTranslate(
+      openvdb::math::Vec3<float>(bounds_min.x, bounds_min.y, bounds_min.z));
+
+  Volume *volume = (Volume *)BKE_id_new_nomain(ID_VO, nullptr);
+  BKE_volume_init_grids(volume);
+
+  BKE_volume_grid_add_vdb(*volume, "density", std::move(grid));
+
+  GeometrySet r_geometry_set;
+  r_geometry_set.replace_volume(volume);
+  params.set_output("Volume", r_geometry_set);
+}
+
+#else
+static void node_geo_exec(GeoNodeExecParams params)
+{
+  params.error_message_add(NodeWarningType::Error,
+                           TIP_("Disabled, Blender was compiled without OpenVDB"));
+  params.set_default_remaining_outputs()

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list