Geometry Nodes: Add Instances to Points Node
This node takes a geometry set with instances as input and outputs points located on the origins of the top level of instances in the geometry set (not nested instances). It also has position and radius inputs to allow overriding the default, and a selection input to only generate points for some instances. The use case for this node is a method to use geometry proximity on instance origins, but in a more generic way that is flexible and useful in other situations. Differential Revision: https://developer.blender.org/D12893
This commit is contained in:
parent
2a7a8a04e3
commit
3af597d16b
|
@ -695,6 +695,7 @@ geometry_node_categories = [
|
|||
GeometryNodeCategory("GEO_INPUT", "Input", items=geometry_input_node_items),
|
||||
GeometryNodeCategory("GEO_INSTANCE", "Instances", items=[
|
||||
NodeItem("GeometryNodeInstanceOnPoints"),
|
||||
NodeItem("GeometryNodeInstancesToPoints"),
|
||||
NodeItem("GeometryNodeRealizeInstances"),
|
||||
NodeItem("GeometryNodeRotateInstances"),
|
||||
NodeItem("GeometryNodeScaleInstances"),
|
||||
|
|
|
@ -1546,6 +1546,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
|
|||
#define GEO_NODE_CURVE_ENDPOINT_SELECTION 1127
|
||||
#define GEO_NODE_RAYCAST 1128
|
||||
#define GEO_NODE_CURVE_TO_POINTS 1130
|
||||
#define GEO_NODE_INSTANCES_TO_POINTS 1131
|
||||
|
||||
/** \} */
|
||||
|
||||
|
|
|
@ -5814,6 +5814,7 @@ static void registerGeometryNodes()
|
|||
register_node_type_geo_input_spline_resolution();
|
||||
register_node_type_geo_input_tangent();
|
||||
register_node_type_geo_instance_on_points();
|
||||
register_node_type_geo_instances_to_points();
|
||||
register_node_type_geo_is_viewport();
|
||||
register_node_type_geo_join_geometry();
|
||||
register_node_type_geo_material_replace();
|
||||
|
|
|
@ -240,6 +240,7 @@ set(SRC
|
|||
geometry/nodes/node_geo_input_spline_resolution.cc
|
||||
geometry/nodes/node_geo_input_tangent.cc
|
||||
geometry/nodes/node_geo_instance_on_points.cc
|
||||
geometry/nodes/node_geo_instances_to_points.cc
|
||||
geometry/nodes/node_geo_is_viewport.cc
|
||||
geometry/nodes/node_geo_join_geometry.cc
|
||||
geometry/nodes/node_geo_material_replace.cc
|
||||
|
|
|
@ -108,6 +108,7 @@ void register_node_type_geo_input_spline_length(void);
|
|||
void register_node_type_geo_input_spline_resolution(void);
|
||||
void register_node_type_geo_input_tangent(void);
|
||||
void register_node_type_geo_instance_on_points(void);
|
||||
void register_node_type_geo_instances_to_points(void);
|
||||
void register_node_type_geo_is_viewport(void);
|
||||
void register_node_type_geo_join_geometry(void);
|
||||
void register_node_type_geo_material_replace(void);
|
||||
|
|
|
@ -368,6 +368,7 @@ DefNode(GeometryNode, GEO_NODE_INPUT_SPLINE_LENGTH, 0, "SPLINE_LENGTH", SplineLe
|
|||
DefNode(GeometryNode, GEO_NODE_INPUT_SPLINE_RESOLUTION, 0, "INPUT_SPLINE_RESOLUTION", InputSplineResolution, "Spline Resolution", "")
|
||||
DefNode(GeometryNode, GEO_NODE_INPUT_TANGENT, 0, "INPUT_TANGENT", InputTangent, "Curve Tangent", "")
|
||||
DefNode(GeometryNode, GEO_NODE_INSTANCE_ON_POINTS, 0, "INSTANCE_ON_POINTS", InstanceOnPoints, "Instance on Points", "")
|
||||
DefNode(GeometryNode, GEO_NODE_INSTANCES_TO_POINTS, 0, "INSTANCES_TO_POINTS", InstancesToPoints, "Instances to Points", "")
|
||||
DefNode(GeometryNode, GEO_NODE_IS_VIEWPORT, 0, "IS_VIEWPORT", IsViewport, "Is Viewport", "")
|
||||
DefNode(GeometryNode, GEO_NODE_JOIN_GEOMETRY, 0, "JOIN_GEOMETRY", JoinGeometry, "Join Geometry", "")
|
||||
DefNode(GeometryNode, GEO_NODE_REPLACE_MATERIAL, 0, "REPLACE_MATERIAL", ReplaceMaterial, "Replace Material", "")
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "BKE_pointcloud.h"
|
||||
#include "DNA_pointcloud_types.h"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
namespace blender::nodes {
|
||||
|
||||
static void geo_node_instances_to_points_declare(NodeDeclarationBuilder &b)
|
||||
{
|
||||
b.add_input<decl::Geometry>("Instances");
|
||||
b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
|
||||
b.add_input<decl::Vector>("Position").implicit_field();
|
||||
b.add_input<decl::Float>("Radius")
|
||||
.default_value(0.05f)
|
||||
.min(0.0f)
|
||||
.subtype(PROP_DISTANCE)
|
||||
.supports_field();
|
||||
b.add_output<decl::Geometry>("Points");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void copy_attribute_to_points(const VArray<T> &src,
|
||||
const IndexMask mask,
|
||||
MutableSpan<T> dst)
|
||||
{
|
||||
for (const int i : mask.index_range()) {
|
||||
dst[i] = src[mask[i]];
|
||||
}
|
||||
}
|
||||
|
||||
static void convert_instances_to_points(GeometrySet &geometry_set,
|
||||
Field<float3> position_field,
|
||||
Field<float> radius_field,
|
||||
const Field<bool> selection_field)
|
||||
{
|
||||
const InstancesComponent &instances = *geometry_set.get_component_for_read<InstancesComponent>();
|
||||
|
||||
const AttributeDomain attribute_domain = ATTR_DOMAIN_POINT;
|
||||
GeometryComponentFieldContext field_context{instances, attribute_domain};
|
||||
const int domain_size = instances.attribute_domain_size(attribute_domain);
|
||||
|
||||
fn::FieldEvaluator selection_evaluator{field_context, domain_size};
|
||||
selection_evaluator.add(std::move(selection_field));
|
||||
selection_evaluator.evaluate();
|
||||
const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
|
||||
if (selection.is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
PointCloud *pointcloud = BKE_pointcloud_new_nomain(selection.size());
|
||||
geometry_set.replace_pointcloud(pointcloud);
|
||||
|
||||
PointCloudComponent &points = geometry_set.get_component_for_write<PointCloudComponent>();
|
||||
|
||||
fn::FieldEvaluator evaluator{field_context, &selection};
|
||||
evaluator.add(std::move(position_field));
|
||||
evaluator.add(std::move(radius_field));
|
||||
evaluator.evaluate();
|
||||
const VArray<float3> &positions = evaluator.get_evaluated<float3>(0);
|
||||
copy_attribute_to_points(positions, selection, {(float3 *)pointcloud->co, pointcloud->totpoint});
|
||||
const VArray<float> &radii = evaluator.get_evaluated<float>(1);
|
||||
copy_attribute_to_points(radii, selection, {pointcloud->radius, pointcloud->totpoint});
|
||||
|
||||
OutputAttribute_Typed<int> id_attribute = points.attribute_try_get_for_output<int>(
|
||||
"id", ATTR_DOMAIN_POINT, 0);
|
||||
MutableSpan<int> ids = id_attribute.as_span();
|
||||
for (const int64_t i : selection) {
|
||||
ids[i] = instances.instance_ids()[i];
|
||||
}
|
||||
id_attribute.save();
|
||||
}
|
||||
|
||||
static void geo_node_instances_to_points_exec(GeoNodeExecParams params)
|
||||
{
|
||||
GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances");
|
||||
|
||||
if (geometry_set.has_instances()) {
|
||||
convert_instances_to_points(geometry_set,
|
||||
params.extract_input<Field<float3>>("Position"),
|
||||
params.extract_input<Field<float>>("Radius"),
|
||||
params.extract_input<Field<bool>>("Selection"));
|
||||
geometry_set.keep_only({GEO_COMPONENT_TYPE_POINT_CLOUD});
|
||||
params.set_output("Points", std::move(geometry_set));
|
||||
}
|
||||
else {
|
||||
params.set_output("Points", GeometrySet());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::nodes
|
||||
|
||||
void register_node_type_geo_instances_to_points()
|
||||
{
|
||||
static bNodeType ntype;
|
||||
|
||||
geo_node_type_base(
|
||||
&ntype, GEO_NODE_INSTANCES_TO_POINTS, "Instances to Points", NODE_CLASS_GEOMETRY, 0);
|
||||
ntype.declare = blender::nodes::geo_node_instances_to_points_declare;
|
||||
ntype.geometry_node_execute = blender::nodes::geo_node_instances_to_points_exec;
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
Loading…
Reference in New Issue