Blender  V3.3
node_geo_volume_cube.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #ifdef WITH_OPENVDB
4 # include <openvdb/openvdb.h>
5 # include <openvdb/tools/Dense.h>
6 # include <openvdb/tools/LevelSetUtil.h>
7 # include <openvdb/tools/ParticlesToLevelSet.h>
8 #endif
9 
10 #include "node_geometry_util.hh"
11 
12 #include "DNA_mesh_types.h"
13 
14 #include "BLI_task.hh"
15 
16 #include "BKE_geometry_set.hh"
17 #include "BKE_lib_id.h"
18 #include "BKE_mesh.h"
19 #include "BKE_volume.h"
20 
22 
24 {
25  b.add_input<decl::Float>(N_("Density"))
26  .description(N_("Volume density per voxel"))
27  .supports_field()
28  .default_value(1.0f);
29  b.add_input<decl::Float>(N_("Background"))
30  .description(N_("Value for voxels outside of the cube"));
31 
32  b.add_input<decl::Vector>(N_("Min"))
33  .description(N_("Minimum boundary of volume"))
34  .default_value(float3(-1.0f));
35  b.add_input<decl::Vector>(N_("Max"))
36  .description(N_("Maximum boundary of volume"))
37  .default_value(float3(1.0f));
38 
39  b.add_input<decl::Int>(N_("Resolution X"))
40  .description(N_("Number of voxels in the X axis"))
41  .default_value(32)
42  .min(2);
43  b.add_input<decl::Int>(N_("Resolution Y"))
44  .description(N_("Number of voxels in the Y axis"))
45  .default_value(32)
46  .min(2);
47  b.add_input<decl::Int>(N_("Resolution Z"))
48  .description(N_("Number of voxels in the Z axis"))
49  .default_value(32)
50  .min(2);
51 
52  b.add_output<decl::Geometry>(N_("Volume"));
53 }
54 
55 static float map(const float x,
56  const float in_min,
57  const float in_max,
58  const float out_min,
59  const float out_max)
60 {
61  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
62 }
63 
65  private:
66  int3 resolution_;
67  float3 bounds_min_;
68  float3 bounds_max_;
69 
70  public:
71  Grid3DFieldContext(const int3 resolution, const float3 bounds_min, const float3 bounds_max)
72  : resolution_(resolution), bounds_min_(bounds_min), bounds_max_(bounds_max)
73  {
74  }
75 
77  {
78  return static_cast<int64_t>(resolution_.x) * static_cast<int64_t>(resolution_.y) *
79  static_cast<int64_t>(resolution_.z);
80  }
81 
83  const IndexMask UNUSED(mask),
84  ResourceScope &UNUSED(scope)) const
85  {
86  const bke::AttributeFieldInput *attribute_field_input =
87  dynamic_cast<const bke::AttributeFieldInput *>(&field_input);
88  if (attribute_field_input == nullptr) {
89  return {};
90  }
91  if (attribute_field_input->attribute_name() != "position") {
92  return {};
93  }
94 
96 
97  threading::parallel_for(IndexRange(resolution_.x), 1, [&](const IndexRange x_range) {
98  /* Start indexing at current X slice. */
99  int64_t index = x_range.start() * resolution_.y * resolution_.z;
100  for (const int64_t x_i : x_range) {
101  const float x = map(x_i, 0.0f, resolution_.x - 1, bounds_min_.x, bounds_max_.x);
102  for (const int64_t y_i : IndexRange(resolution_.y)) {
103  const float y = map(y_i, 0.0f, resolution_.y - 1, bounds_min_.y, bounds_max_.y);
104  for (const int64_t z_i : IndexRange(resolution_.z)) {
105  const float z = map(z_i, 0.0f, resolution_.z - 1, bounds_min_.z, bounds_max_.z);
106  positions[index] = float3(x, y, z);
107  index++;
108  }
109  }
110  }
111  });
112  return VArray<float3>::ForContainer(std::move(positions));
113  }
114 };
115 
116 #ifdef WITH_OPENVDB
117 static void node_geo_exec(GeoNodeExecParams params)
118 {
119  const float3 bounds_min = params.extract_input<float3>("Min");
120  const float3 bounds_max = params.extract_input<float3>("Max");
121 
122  const int3 resolution = int3(params.extract_input<int>("Resolution X"),
123  params.extract_input<int>("Resolution Y"),
124  params.extract_input<int>("Resolution Z"));
125 
126  if (resolution.x < 2 || resolution.y < 2 || resolution.z < 2) {
127  params.error_message_add(NodeWarningType::Error, TIP_("Resolution must be greater than 1"));
128  params.set_default_remaining_outputs();
129  return;
130  }
131 
132  if (bounds_min.x == bounds_max.x || bounds_min.y == bounds_max.y ||
133  bounds_min.z == bounds_max.z) {
134  params.error_message_add(NodeWarningType::Error,
135  TIP_("Bounding box volume must be greater than 0"));
136  params.set_default_remaining_outputs();
137  return;
138  }
139 
140  const double3 scale_fac = double3(bounds_max - bounds_min) / double3(resolution - 1);
141  if (!BKE_volume_grid_determinant_valid(scale_fac.x * scale_fac.y * scale_fac.z)) {
142  params.error_message_add(NodeWarningType::Warning,
143  TIP_("Volume scale is lower than permitted by OpenVDB"));
144  params.set_default_remaining_outputs();
145  return;
146  }
147 
148  Field<float> input_field = params.extract_input<Field<float>>("Density");
149 
150  /* Evaluate input field on a 3D grid. */
151  Grid3DFieldContext context(resolution, bounds_min, bounds_max);
152  FieldEvaluator evaluator(context, context.points_num());
153  Array<float> densities(context.points_num());
154  evaluator.add_with_destination(std::move(input_field), densities.as_mutable_span());
155  evaluator.evaluate();
156 
157  /* Store resulting values in openvdb grid. */
158  const float background = params.extract_input<float>("Background");
160  grid->setGridClass(openvdb::GRID_FOG_VOLUME);
161 
162  openvdb::tools::Dense<float, openvdb::tools::LayoutZYX> dense_grid{
163  openvdb::math::CoordBBox({0, 0, 0}, {resolution.x - 1, resolution.y - 1, resolution.z - 1}),
164  densities.data()};
165  openvdb::tools::copyFromDense(dense_grid, *grid, 0.0f);
166 
167  grid->transform().preTranslate(openvdb::math::Vec3<float>(-0.5f));
168  grid->transform().postScale(openvdb::math::Vec3<double>(scale_fac.x, scale_fac.y, scale_fac.z));
169  grid->transform().postTranslate(
170  openvdb::math::Vec3<float>(bounds_min.x, bounds_min.y, bounds_min.z));
171 
172  Volume *volume = (Volume *)BKE_id_new_nomain(ID_VO, nullptr);
173  BKE_volume_init_grids(volume);
174 
175  BKE_volume_grid_add_vdb(*volume, "density", std::move(grid));
176 
177  GeometrySet r_geometry_set;
178  r_geometry_set.replace_volume(volume);
179  params.set_output("Volume", r_geometry_set);
180 }
181 
182 #else
184 {
185  params.error_message_add(NodeWarningType::Error,
186  TIP_("Disabled, Blender was compiled without OpenVDB"));
187  params.set_default_remaining_outputs();
188 }
189 #endif /* WITH_OPENVDB */
190 
191 } // namespace blender::nodes::node_geo_volume_cube_cc
192 
194 {
195  namespace file_ns = blender::nodes::node_geo_volume_cube_cc;
196 
197  static bNodeType ntype;
198 
200 
203  nodeRegisterType(&ntype);
204 }
void * BKE_id_new_nomain(short type, const char *name)
Definition: lib_id.c:1173
#define GEO_NODE_VOLUME_CUBE
Definition: BKE_node.h:1502
#define NODE_CLASS_GEOMETRY
Definition: BKE_node.h:359
void nodeRegisterType(struct bNodeType *ntype)
Definition: node.cc:1357
Volume data-block.
void BKE_volume_init_grids(struct Volume *volume)
Definition: volume.cc:679
bool BKE_volume_grid_determinant_valid(double determinant)
Definition: volume.cc:1593
#define UNUSED(x)
#define TIP_(msgid)
@ ID_VO
Definition: DNA_ID_enums.h:83
int int3[2]
static VArray ForContainer(ContainerT container)
Grid3DFieldContext(const int3 resolution, const float3 bounds_min, const float3 bounds_max)
GVArray get_varray_for_input(const FieldInput &field_input, const IndexMask UNUSED(mask), ResourceScope &UNUSED(scope)) const
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
Definition: math_float4.h:513
std::unique_ptr< IDProperty, IDPropertyDeleter > create(StringRefNull prop_name, int32_t value)
Allocate a new IDProperty of type IDP_INT, set its name and value.
std::unique_ptr< T > Ptr
Definition: BLI_any.hh:58
static void node_declare(NodeDeclarationBuilder &b)
static void node_geo_exec(GeoNodeExecParams params)
static float map(const float x, const float in_min, const float in_max, const float out_min, const float out_max)
void parallel_for(IndexRange range, int64_t grain_size, const Function &function)
Definition: BLI_task.hh:51
vec_base< float, 3 > float3
vec_base< double, 3 > double3
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
MutableSpan< float3 > positions
void register_node_type_geo_volume_cube()
void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
__int64 int64_t
Definition: stdint.h:89
void replace_volume(Volume *volume, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
Defines a node type.
Definition: BKE_node.h:226
NodeGeometryExecFunction geometry_node_execute
Definition: BKE_node.h:316
NodeDeclareFunction declare
Definition: BKE_node.h:324
#define N_(msgid)