Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Clyne <lateasusual>2022-06-17 14:26:22 +0300
committerJacques Lucke <jacques@blender.org>2022-06-17 14:30:44 +0300
commit838c4a97f1d6b993f4c866c474eb02d929f0ca1d (patch)
tree9b6a23c607c32acbdff09da3773851f58eabf5de
parent75489b5887cd270b8076046606baf6daeba3d259 (diff)
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
-rw-r--r--release/scripts/startup/nodeitems_builtins.py1
-rw-r--r--source/blender/blenkernel/BKE_node.h1
-rw-r--r--source/blender/blenkernel/intern/node.cc1
-rw-r--r--source/blender/nodes/NOD_geometry.h1
-rw-r--r--source/blender/nodes/NOD_static_types.h1
-rw-r--r--source/blender/nodes/geometry/CMakeLists.txt1
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_volume_cube.cc197
7 files changed, 203 insertions, 0 deletions
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();
+}
+#endif /* WITH_OPENVDB */
+
+} // namespace blender::nodes::node_geo_volume_cube_cc
+
+void register_node_type_geo_volume_cube()
+{
+ namespace file_ns = blender::nodes::node_geo_volume_cube_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_VOLUME_CUBE, "Volume Cube", NODE_CLASS_GEOMETRY);
+
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ nodeRegisterType(&ntype);
+}