Blender  V3.3
node_geo_points_to_volume.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/LevelSetUtil.h>
6 # include <openvdb/tools/ParticlesToLevelSet.h>
7 #endif
8 
9 #include "node_geometry_util.hh"
10 
11 #include "BKE_lib_id.h"
12 #include "BKE_volume.h"
13 
14 #include "UI_interface.h"
15 #include "UI_resources.h"
16 
18 
20 
22 {
23  b.add_input<decl::Geometry>(N_("Points"));
24  b.add_input<decl::Float>(N_("Density")).default_value(1.0f).min(0.0f);
25  b.add_input<decl::Float>(N_("Voxel Size"))
26  .default_value(0.3f)
27  .min(0.01f)
28  .subtype(PROP_DISTANCE)
29  .make_available([](bNode &node) {
30  node_storage(node).resolution_mode = GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE;
31  });
32  b.add_input<decl::Float>(N_("Voxel Amount"))
33  .default_value(64.0f)
34  .min(0.0f)
35  .make_available([](bNode &node) {
36  node_storage(node).resolution_mode = GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT;
37  });
38  b.add_input<decl::Float>(N_("Radius"))
39  .default_value(0.5f)
40  .min(0.0f)
41  .subtype(PROP_DISTANCE)
42  .supports_field();
43  b.add_output<decl::Geometry>(N_("Volume"));
44 }
45 
46 static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
47 {
48  uiLayoutSetPropSep(layout, true);
49  uiLayoutSetPropDecorate(layout, false);
50  uiItemR(layout, ptr, "resolution_mode", 0, IFACE_("Resolution"), ICON_NONE);
51 }
52 
54 {
55  NodeGeometryPointsToVolume *data = MEM_cnew<NodeGeometryPointsToVolume>(__func__);
57  node->storage = data;
58 }
59 
61 {
62  const NodeGeometryPointsToVolume &storage = node_storage(*node);
63  bNodeSocket *voxel_size_socket = nodeFindSocket(node, SOCK_IN, "Voxel Size");
64  bNodeSocket *voxel_amount_socket = nodeFindSocket(node, SOCK_IN, "Voxel Amount");
66  voxel_amount_socket,
67  storage.resolution_mode ==
70  voxel_size_socket,
71  storage.resolution_mode ==
73 }
74 
75 #ifdef WITH_OPENVDB
76 namespace {
77 /* Implements the interface required by #openvdb::tools::ParticlesToLevelSet. */
78 struct ParticleList {
79  using PosType = openvdb::Vec3R;
80 
83 
84  size_t size() const
85  {
86  return (size_t)positions.size();
87  }
88 
89  void getPos(size_t n, openvdb::Vec3R &xyz) const
90  {
91  xyz = &positions[n].x;
92  }
93 
94  void getPosRad(size_t n, openvdb::Vec3R &xyz, openvdb::Real &radius) const
95  {
96  xyz = &positions[n].x;
97  radius = radii[n];
98  }
99 };
100 } // namespace
101 
102 static openvdb::FloatGrid::Ptr generate_volume_from_points(const Span<float3> positions,
103  const Span<float> radii,
104  const float density)
105 {
106  /* Create a new grid that will be filled. #ParticlesToLevelSet requires the background value to
107  * be positive. It will be set to zero later on. */
109 
110  /* Create a narrow-band level set grid based on the positions and radii. */
111  openvdb::tools::ParticlesToLevelSet op{*new_grid};
112  /* Don't ignore particles based on their radius. */
113  op.setRmin(0.0f);
114  op.setRmax(FLT_MAX);
115  ParticleList particles{positions, radii};
116  op.rasterizeSpheres(particles);
117  op.finalize();
118 
119  /* Convert the level set to a fog volume. This also sets the background value to zero. Inside the
120  * fog there will be a density of 1. */
121  openvdb::tools::sdfToFogVolume(*new_grid);
122 
123  /* Take the desired density into account. */
124  openvdb::tools::foreach (new_grid->beginValueOn(),
125  [&](const openvdb::FloatGrid::ValueOnIter &iter) {
126  iter.modifyValue([&](float &value) { value *= density; });
127  });
128  return new_grid;
129 }
130 
131 static float compute_voxel_size(const GeoNodeExecParams &params,
132  Span<float3> positions,
133  const float radius)
134 {
135  const NodeGeometryPointsToVolume &storage = node_storage(params.node());
136 
138  return params.get_input<float>("Voxel Size");
139  }
140 
141  if (positions.is_empty()) {
142  return 0.0f;
143  }
144 
145  float3 min, max;
146  INIT_MINMAX(min, max);
147  minmax_v3v3_v3_array(min, max, (float(*)[3])positions.data(), positions.size());
148 
149  const float voxel_amount = params.get_input<float>("Voxel Amount");
150  if (voxel_amount <= 1) {
151  return 0.0f;
152  }
153 
154  /* The voxel size adapts to the final size of the volume. */
155  const float diagonal = math::distance(min, max);
156  const float extended_diagonal = diagonal + 2.0f * radius;
157  const float voxel_size = extended_diagonal / voxel_amount;
158  return voxel_size;
159 }
160 
161 static void gather_point_data_from_component(GeoNodeExecParams &params,
163  Vector<float3> &r_positions,
164  Vector<float> &r_radii)
165 {
166  if (component.is_empty()) {
167  return;
168  }
169  VArray<float3> positions = component.attributes()->lookup_or_default<float3>(
170  "position", ATTR_DOMAIN_POINT, {0, 0, 0});
171 
172  Field<float> radius_field = params.get_input<Field<float>>("Radius");
173  GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
174  const int domain_num = component.attribute_domain_size(ATTR_DOMAIN_POINT);
175 
176  r_positions.resize(r_positions.size() + domain_num);
177  positions.materialize(r_positions.as_mutable_span().take_back(domain_num));
178 
179  r_radii.resize(r_radii.size() + domain_num);
180  fn::FieldEvaluator evaluator{field_context, domain_num};
181  evaluator.add_with_destination(radius_field, r_radii.as_mutable_span().take_back(domain_num));
182  evaluator.evaluate();
183 }
184 
185 static void convert_to_grid_index_space(const float voxel_size,
186  MutableSpan<float3> positions,
187  MutableSpan<float> radii)
188 {
189  const float voxel_size_inv = 1.0f / voxel_size;
190  for (const int i : positions.index_range()) {
191  positions[i] *= voxel_size_inv;
192  /* Better align generated grid with source points. */
193  positions[i] -= float3(0.5f);
194  radii[i] *= voxel_size_inv;
195  }
196 }
197 
198 static void initialize_volume_component_from_points(GeoNodeExecParams &params,
199  GeometrySet &r_geometry_set)
200 {
201  Vector<float3> positions;
202  Vector<float> radii;
203 
204  for (const GeometryComponentType type :
206  if (r_geometry_set.has(type)) {
207  gather_point_data_from_component(
208  params, *r_geometry_set.get_component_for_read(type), positions, radii);
209  }
210  }
211 
212  const float max_radius = *std::max_element(radii.begin(), radii.end());
213  const float voxel_size = compute_voxel_size(params, positions, max_radius);
214  if (voxel_size == 0.0f || positions.is_empty()) {
215  return;
216  }
217 
218  Volume *volume = (Volume *)BKE_id_new_nomain(ID_VO, nullptr);
219  BKE_volume_init_grids(volume);
220 
221  const float density = params.get_input<float>("Density");
222  convert_to_grid_index_space(voxel_size, positions, radii);
223  openvdb::FloatGrid::Ptr new_grid = generate_volume_from_points(positions, radii, density);
224  new_grid->transform().postScale(voxel_size);
225  BKE_volume_grid_add_vdb(*volume, "density", std::move(new_grid));
226 
228  r_geometry_set.replace_volume(volume);
229 }
230 #endif
231 
233 {
234  GeometrySet geometry_set = params.extract_input<GeometrySet>("Points");
235 
236 #ifdef WITH_OPENVDB
237  geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
238  initialize_volume_component_from_points(params, geometry_set);
239  });
240  params.set_output("Volume", std::move(geometry_set));
241 #else
242  params.error_message_add(NodeWarningType::Error,
243  TIP_("Disabled, Blender was compiled without OpenVDB"));
244  params.set_default_remaining_outputs();
245 #endif
246 }
247 
248 } // namespace blender::nodes::node_geo_points_to_volume_cc
249 
251 {
253 
254  static bNodeType ntype;
255 
257  node_type_storage(&ntype,
258  "NodeGeometryPointsToVolume",
261  node_type_size(&ntype, 170, 120, 700);
267  nodeRegisterType(&ntype);
268 }
@ ATTR_DOMAIN_POINT
Definition: BKE_attribute.h:27
GeometryComponentType
@ GEO_COMPONENT_TYPE_MESH
@ GEO_COMPONENT_TYPE_POINT_CLOUD
@ GEO_COMPONENT_TYPE_CURVE
@ GEO_COMPONENT_TYPE_VOLUME
void * BKE_id_new_nomain(short type, const char *name)
Definition: lib_id.c:1173
void node_type_size(struct bNodeType *ntype, int width, int minwidth, int maxwidth)
Definition: node.cc:4396
void node_type_update(struct bNodeType *ntype, void(*updatefunc)(struct bNodeTree *ntree, struct bNode *node))
Definition: node.cc:4443
#define NODE_STORAGE_FUNCS(StorageT)
Definition: BKE_node.h:1563
void nodeSetSocketAvailability(struct bNodeTree *ntree, struct bNodeSocket *sock, bool is_available)
Definition: node.cc:3664
void node_type_init(struct bNodeType *ntype, void(*initfunc)(struct bNodeTree *ntree, struct bNode *node))
Definition: node.cc:4390
#define NODE_CLASS_GEOMETRY
Definition: BKE_node.h:359
void node_type_storage(struct bNodeType *ntype, const char *storagename, void(*freefunc)(struct bNode *node), void(*copyfunc)(struct bNodeTree *dest_ntree, struct bNode *dest_node, const struct bNode *src_node))
Definition: node.cc:4426
struct bNodeSocket * nodeFindSocket(const struct bNode *node, eNodeSocketInOut in_out, const char *identifier)
#define GEO_NODE_POINTS_TO_VOLUME
Definition: BKE_node.h:1443
void nodeRegisterType(struct bNodeType *ntype)
Definition: node.cc:1357
Volume data-block.
void BKE_volume_init_grids(struct Volume *volume)
Definition: volume.cc:679
void minmax_v3v3_v3_array(float r_min[3], float r_max[3], const float(*vec_arr)[3], int var_arr_num)
Definition: math_vector.c:907
#define INIT_MINMAX(min, max)
#define UNUSED(x)
#define TIP_(msgid)
#define IFACE_(msgid)
static uint8 component(Color32 c, uint i)
Definition: ColorBlock.cpp:108
@ ID_VO
Definition: DNA_ID_enums.h:83
@ SOCK_IN
@ GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT
@ GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE
_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
float float3[3]
@ PROP_DISTANCE
Definition: RNA_types.h:149
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
OperationNode * node
bNodeTree * ntree
#define foreach(x, y)
Definition: foreach.h:9
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
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.
static int domain_num(const CurvesGeometry &curves, const eAttrDomain domain)
std::unique_ptr< T > Ptr
Definition: BLI_any.hh:58
T distance(const T &a, const T &b)
static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_geo_exec(GeoNodeExecParams params)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
static void node_update(bNodeTree *ntree, bNode *node)
static void node_declare(NodeDeclarationBuilder &b)
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
static const pxr::TfToken density("density", pxr::TfToken::Immortal)
static void node_init(const struct bContext *C, bNodeTree *ntree, bNode *node)
Definition: node.cc:1082
MutableSpan< float3 > positions
MutableSpan< float > radii
void register_node_type_geo_points_to_volume()
void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
void node_copy_standard_storage(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, const bNode *src_node)
Definition: node_util.c:55
void node_free_standard_storage(bNode *node)
Definition: node_util.c:43
#define min(a, b)
Definition: sort.c:35
bool has(const GeometryComponentType component_type) const
void keep_only_during_modify(const blender::Span< GeometryComponentType > component_types)
const GeometryComponent * get_component_for_read(GeometryComponentType component_type) const
void replace_volume(Volume *volume, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
void modify_geometry_sets(ForeachSubGeometryCallback callback)
Defines a node type.
Definition: BKE_node.h:226
NodeGeometryExecFunction geometry_node_execute
Definition: BKE_node.h:316
void(* draw_buttons)(struct uiLayout *, struct bContext *C, struct PointerRNA *ptr)
Definition: BKE_node.h:244
NodeDeclareFunction declare
Definition: BKE_node.h:324
float max
#define N_(msgid)
PointerRNA * ptr
Definition: wm_files.c:3480