6# include <openvdb/openvdb.h>
7# include <openvdb/tools/Interpolation.h>
8# include <openvdb/tools/PointScatter.h>
41 .description(
"Number of points to sample per unit volume");
43 "Seed used by the random number generator to generate random points");
45 .default_value({0.3, 0.3, 0.3})
48 .description(
"Spacing between grid points");
53 .
description(
"Minimum density of a volume cell to contain a grid point");
56 const bNode *node =
b.node_or_null();
57 if (node !=
nullptr) {
84class PositionsVDBWrapper {
91 : offset_fix_(offset_fix), vector_(
vector)
94 PositionsVDBWrapper(
const PositionsVDBWrapper &wrapper) =
default;
96 void add(
const openvdb::Vec3R &
pos)
105using RNGType = std::mt19937;
107using NonUniformPointScatterVDB =
108 openvdb::tools::NonUniformPointScatter<PositionsVDBWrapper, RNGType>;
110static void point_scatter_density_random(
const openvdb::FloatGrid &grid,
113 Vector<float3> &r_positions)
116 const float3 offset_fix = {0.5f *
float(grid.voxelSize().x()),
117 0.5f *
float(grid.voxelSize().y()),
118 0.5f *
float(grid.voxelSize().z())};
120 PositionsVDBWrapper vdb_position_wrapper = PositionsVDBWrapper(r_positions, offset_fix);
121 RNGType random_generator(
seed);
122 NonUniformPointScatterVDB point_scatter(vdb_position_wrapper, density, random_generator);
126static void point_scatter_density_grid(
const openvdb::FloatGrid &grid,
128 const float threshold,
129 Vector<float3> &r_positions)
131 const openvdb::Vec3d half_voxel(0.5, 0.5, 0.5);
132 const openvdb::Vec3d voxel_spacing(
double(spacing.
x) / grid.voxelSize().x(),
133 double(spacing.
y) / grid.voxelSize().y(),
134 double(spacing.
z) / grid.voxelSize().z());
137 const double min_spacing = std::min(voxel_spacing.x(),
138 std::min(voxel_spacing.y(), voxel_spacing.z()));
139 if (std::abs(min_spacing) < 0.0001) {
144 for (openvdb::FloatGrid::ValueOnCIter cell = grid.cbeginValueOn(); cell; ++cell) {
146 if (cell.getValue() < threshold) {
150 const openvdb::CoordBBox bbox = cell.getBoundingBox();
151 const openvdb::Vec3d box_min = bbox.min().asVec3d() - half_voxel;
152 const openvdb::Vec3d box_max = bbox.max().asVec3d() + half_voxel;
155 double abs_spacing_x = std::abs(voxel_spacing.x());
156 double abs_spacing_y = std::abs(voxel_spacing.y());
157 double abs_spacing_z = std::abs(voxel_spacing.z());
158 const openvdb::Vec3d start(
ceil(box_min.x() / abs_spacing_x) * abs_spacing_x,
159 ceil(box_min.y() / abs_spacing_y) * abs_spacing_y,
160 ceil(box_min.z() / abs_spacing_z) * abs_spacing_z);
163 for (
double x = start.x(); x < box_max.x(); x += abs_spacing_x) {
164 for (
double y = start.y(); y < box_max.y(); y += abs_spacing_y) {
165 for (
double z = start.z();
z < box_max.z();
z += abs_spacing_z) {
167 const openvdb::Vec3d idx_pos(x, y,
z);
168 const openvdb::Vec3d local_pos = grid.indexToWorld(idx_pos + half_voxel);
169 r_positions.append({
float(local_pos.x()),
float(local_pos.y()),
float(local_pos.z())});
192 density =
params.extract_input<
float>(
"Density");
197 threshold =
params.extract_input<
float>(
"Threshold");
213 if (volume_grid ==
nullptr) {
217 bke::VolumeTreeAccessToken tree_token;
218 const openvdb::GridBase &base_grid = volume_grid->grid(tree_token);
220 if (!base_grid.isType<openvdb::FloatGrid>()) {
224 const openvdb::FloatGrid &grid =
static_cast<const openvdb::FloatGrid &
>(base_grid);
227 point_scatter_density_random(grid, density,
seed, positions);
230 point_scatter_density_grid(grid, spacing, threshold, positions);
236 pointcloud->positions_for_write().copy_from(positions);
240 point_radii.
span.fill(0.05f);
249 params.set_output(
"Points", std::move(geometry_set));
263 "Distribute points randomly inside of the volume"},
268 "Distribute the points in a grid pattern inside of the volume"},
269 {0,
nullptr, 0,
nullptr,
nullptr},
274 "Distribution Method",
275 "Method to use for scattering points",
285 GEO_NODE_DISTRIBUTE_POINTS_IN_VOLUME,
286 "Distribute Points in Volume",
289 "NodeGeometryDistributePointsInVolume",
#define NODE_STORAGE_FUNCS(StorageT)
#define NODE_CLASS_GEOMETRY
General operations for point clouds.
PointCloud * BKE_pointcloud_new_nomain(int totpoint)
int BKE_volume_num_grids(const Volume *volume)
bool BKE_volume_load(const Volume *volume, const Main *bmain)
const blender::bke::VolumeGridData * BKE_volume_grid_get(const Volume *volume, int grid_index)
#define BLT_I18NCONTEXT_ID_ID
GeometryNodeDistributePointsInVolumeMode
@ GEO_NODE_DISTRIBUTE_POINTS_IN_VOLUME_DENSITY_GRID
@ GEO_NODE_DISTRIBUTE_POINTS_IN_VOLUME_DENSITY_RANDOM
#define NOD_REGISTER_NODE(REGISTER_FUNC)
#define NOD_storage_enum_accessors(member)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
static unsigned long seed
void append(const T &value)
GSpanAttributeWriter lookup_or_add_for_write_only_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type)
const Volume * get() const
std::string translation_context
local_group_size(16, 16) .push_constant(Type b
draw_view in_light_buf[] float
ccl_device_inline float3 ceil(const float3 a)
static void add(blender::Map< std::string, std::string > &messages, Message &msg)
void node_type_size(bNodeType *ntype, int width, int minwidth, int maxwidth)
void node_type_storage(bNodeType *ntype, const char *storagename, void(*freefunc)(bNode *node), void(*copyfunc)(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node))
void node_register_type(bNodeType *ntype)
void debug_randomize_point_order(PointCloud *pointcloud)
static void node_init(bNodeTree *, bNode *node)
static void node_geo_exec(GeoNodeExecParams params)
static void node_rna(StructRNA *srna)
static void node_layout(uiLayout *layout, bContext *, PointerRNA *ptr)
static void node_register()
static void node_declare(NodeDeclarationBuilder &b)
PropertyRNA * RNA_def_node_enum(StructRNA *srna, const char *identifier, const char *ui_name, const char *ui_description, const EnumPropertyItem *static_items, const EnumRNAAccessors accessors, std::optional< int > default_value, const EnumPropertyItemFunc item_func, const bool allow_animation)
void node_geo_exec_with_missing_openvdb(GeoNodeExecParams ¶ms)
void geo_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
void node_free_standard_storage(bNode *node)
void node_copy_standard_storage(bNodeTree *, bNode *dest_node, const bNode *src_node)
void replace_pointcloud(PointCloud *pointcloud, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
void keep_only_during_modify(Span< GeometryComponent::Type > component_types)
const GeometryComponent * get_component(GeometryComponent::Type component_type) const
void modify_geometry_sets(ForeachSubGeometryCallback callback)
MutableVArraySpan< T > span
void(* initfunc)(bNodeTree *ntree, bNode *node)
NodeGeometryExecFunction geometry_node_execute
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
NodeDeclareFunction declare