Geometry Nodes: Mesh Point Cloud Conversion Nodes
This commit adds nodes to do direct conversion between meshes and point clouds in geometry nodes. The conversion from mesh to points is helpful to instance once per face, or once per edge, which was previously only possibly with ugly work-arounds. Fields can be evaluated on the mesh to pass them to the points with the attribute capture node. The other conversion, point cloud to mesh vertices, is a bit less obvious, though it is still a common request from users. It's helpful for flexibility when passing data around, better visualization in the viewport (and in the future, cycles), and the simplicity of points. This is a step towards T91754, where point clouds are currently combined with meshes when outputing to the next modifier after geometry nodes. Since we're removing the implicit behavior for realizing instances, it feels natural to use an explicit node to convert points to vertices too. Differential Revision: https://developer.blender.org/D12657
This commit is contained in:
parent
797064544e
commit
262b211856
|
@ -582,6 +582,7 @@ geometry_node_categories = [
|
|||
NodeItem("GeometryNodeBoolean"),
|
||||
NodeItem("GeometryNodeTriangulate"),
|
||||
NodeItem("GeometryNodeMeshSubdivide"),
|
||||
NodeItem("GeometryNodePointsToVertices", poll=geometry_nodes_fields_poll),
|
||||
]),
|
||||
GeometryNodeCategory("GEO_PRIMITIVES_MESH", "Mesh Primitives", items=[
|
||||
NodeItem("GeometryNodeMeshCircle"),
|
||||
|
@ -594,6 +595,7 @@ geometry_node_categories = [
|
|||
NodeItem("GeometryNodeMeshUVSphere"),
|
||||
]),
|
||||
GeometryNodeCategory("GEO_POINT", "Point", items=[
|
||||
NodeItem("GeometryNodeMeshToPoints", poll=geometry_nodes_fields_poll),
|
||||
NodeItem("GeometryNodeInstanceOnPoints", poll=geometry_nodes_fields_poll),
|
||||
NodeItem("GeometryNodeDistributePointsOnFaces", poll=geometry_nodes_fields_poll),
|
||||
NodeItem("GeometryNodeLegacyPointDistribute", poll=geometry_nodes_fields_legacy_poll),
|
||||
|
|
|
@ -1503,6 +1503,8 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
|
|||
#define GEO_NODE_DISTRIBUTE_POINTS_ON_FACES 1090
|
||||
#define GEO_NODE_STRING_TO_CURVES 1091
|
||||
#define GEO_NODE_INSTANCE_ON_POINTS 1092
|
||||
#define GEO_NODE_MESH_TO_POINTS 1093
|
||||
#define GEO_NODE_POINTS_TO_VERTICES 1094
|
||||
|
||||
/** \} */
|
||||
|
||||
|
|
|
@ -5778,6 +5778,7 @@ static void registerGeometryNodes()
|
|||
register_node_type_geo_mesh_primitive_uv_sphere();
|
||||
register_node_type_geo_mesh_subdivide();
|
||||
register_node_type_geo_mesh_to_curve();
|
||||
register_node_type_geo_mesh_to_points();
|
||||
register_node_type_geo_object_info();
|
||||
register_node_type_geo_point_distribute();
|
||||
register_node_type_geo_point_instance();
|
||||
|
@ -5785,6 +5786,7 @@ static void registerGeometryNodes()
|
|||
register_node_type_geo_point_scale();
|
||||
register_node_type_geo_point_separate();
|
||||
register_node_type_geo_point_translate();
|
||||
register_node_type_geo_points_to_vertices();
|
||||
register_node_type_geo_points_to_volume();
|
||||
register_node_type_geo_raycast();
|
||||
register_node_type_geo_realize_instances();
|
||||
|
|
|
@ -1511,6 +1511,11 @@ typedef struct NodeGeometryCurveFill {
|
|||
uint8_t mode;
|
||||
} NodeGeometryCurveFill;
|
||||
|
||||
typedef struct NodeGeometryMeshToPoints {
|
||||
/* GeometryNodeMeshToPointsMode */
|
||||
uint8_t mode;
|
||||
} NodeGeometryMeshToPoints;
|
||||
|
||||
typedef struct NodeGeometryAttributeCapture {
|
||||
/* CustomDataType. */
|
||||
int8_t data_type;
|
||||
|
@ -2124,6 +2129,13 @@ typedef enum GeometryNodeCurveFillMode {
|
|||
GEO_NODE_CURVE_FILL_MODE_NGONS = 1,
|
||||
} GeometryNodeCurveFillMode;
|
||||
|
||||
typedef enum GeometryNodeMeshToPointsMode {
|
||||
GEO_NODE_MESH_TO_POINTS_VERTICES = 0,
|
||||
GEO_NODE_MESH_TO_POINTS_EDGES = 1,
|
||||
GEO_NODE_MESH_TO_POINTS_FACES = 2,
|
||||
GEO_NODE_MESH_TO_POINTS_CORNERS = 3,
|
||||
} GeometryNodeMeshToPointsMode;
|
||||
|
||||
typedef enum GeometryNodeStringToCurvesOverflowMode {
|
||||
GEO_NODE_STRING_TO_CURVES_MODE_OVERFLOW = 0,
|
||||
GEO_NODE_STRING_TO_CURVES_MODE_SCALE_TO_FIT = 1,
|
||||
|
|
|
@ -10306,6 +10306,42 @@ static void def_geo_curve_to_points(StructRNA *srna)
|
|||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
|
||||
}
|
||||
|
||||
static void def_geo_mesh_to_points(StructRNA *srna)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
|
||||
static EnumPropertyItem mode_items[] = {
|
||||
{GEO_NODE_MESH_TO_POINTS_VERTICES,
|
||||
"VERTICES",
|
||||
0,
|
||||
"Vertices",
|
||||
"Create a point in the point cloud for each selected vertex"},
|
||||
{GEO_NODE_MESH_TO_POINTS_EDGES,
|
||||
"EDGES",
|
||||
0,
|
||||
"Edges",
|
||||
"Create a point in the point cloud for each selected edge"},
|
||||
{GEO_NODE_MESH_TO_POINTS_FACES,
|
||||
"FACES",
|
||||
0,
|
||||
"Faces",
|
||||
"Create a point in the point cloud for each selected face"},
|
||||
{GEO_NODE_MESH_TO_POINTS_CORNERS,
|
||||
"CORNERS",
|
||||
0,
|
||||
"Corners",
|
||||
"Create a point in the point cloud for each selected face corner"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
RNA_def_struct_sdna_from(srna, "NodeGeometryMeshToPoints", "storage");
|
||||
|
||||
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, mode_items);
|
||||
RNA_def_property_ui_text(prop, "Mode", "");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
}
|
||||
|
||||
static void def_geo_curve_trim(StructRNA *srna)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
|
|
|
@ -329,7 +329,7 @@ static void get_socket_value(const SocketRef &socket, void *r_value)
|
|||
if (bsocket.flag & SOCK_HIDE_VALUE) {
|
||||
const bNode &bnode = *socket.bnode();
|
||||
if (bsocket.type == SOCK_VECTOR) {
|
||||
if (ELEM(bnode.type, GEO_NODE_SET_POSITION, SH_NODE_TEX_NOISE)) {
|
||||
if (ELEM(bnode.type, GEO_NODE_SET_POSITION, SH_NODE_TEX_NOISE, GEO_NODE_MESH_TO_POINTS)) {
|
||||
new (r_value) Field<float3>(
|
||||
std::make_shared<bke::AttributeFieldInput>("position", CPPType::get<float3>()));
|
||||
return;
|
||||
|
|
|
@ -231,7 +231,9 @@ set(SRC
|
|||
geometry/nodes/node_geo_mesh_primitive_line.cc
|
||||
geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
|
||||
geometry/nodes/node_geo_mesh_subdivide.cc
|
||||
geometry/nodes/node_geo_mesh_to_points.cc
|
||||
geometry/nodes/node_geo_object_info.cc
|
||||
geometry/nodes/node_geo_points_to_vertices.cc
|
||||
geometry/nodes/node_geo_realize_instances.cc
|
||||
geometry/nodes/node_geo_separate_components.cc
|
||||
geometry/nodes/node_geo_set_position.cc
|
||||
|
|
|
@ -101,6 +101,7 @@ void register_node_type_geo_mesh_primitive_line(void);
|
|||
void register_node_type_geo_mesh_primitive_uv_sphere(void);
|
||||
void register_node_type_geo_mesh_subdivide(void);
|
||||
void register_node_type_geo_mesh_to_curve(void);
|
||||
void register_node_type_geo_mesh_to_points(void);
|
||||
void register_node_type_geo_object_info(void);
|
||||
void register_node_type_geo_point_distribute(void);
|
||||
void register_node_type_geo_point_instance(void);
|
||||
|
@ -108,6 +109,7 @@ void register_node_type_geo_point_rotate(void);
|
|||
void register_node_type_geo_point_scale(void);
|
||||
void register_node_type_geo_point_separate(void);
|
||||
void register_node_type_geo_point_translate(void);
|
||||
void register_node_type_geo_points_to_vertices(void);
|
||||
void register_node_type_geo_points_to_volume(void);
|
||||
void register_node_type_geo_raycast(void);
|
||||
void register_node_type_geo_realize_instances(void);
|
||||
|
|
|
@ -358,7 +358,9 @@ DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE, 0, "MESH_PRIMITIVE_ICO
|
|||
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_LINE, def_geo_mesh_line, "MESH_PRIMITIVE_LINE", MeshLine, "Mesh Line", "")
|
||||
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_UV_SPHERE, 0, "MESH_PRIMITIVE_UV_SPHERE", MeshUVSphere, "UV Sphere", "")
|
||||
DefNode(GeometryNode, GEO_NODE_MESH_SUBDIVIDE, 0, "MESH_SUBDIVIDE", MeshSubdivide, "Mesh Subdivide", "")
|
||||
DefNode(GeometryNode, GEO_NODE_MESH_TO_POINTS, def_geo_mesh_to_points, "MESH_TO_POINTS", MeshToPoints, "Mesh to Points", "")
|
||||
DefNode(GeometryNode, GEO_NODE_OBJECT_INFO, def_geo_object_info, "OBJECT_INFO", ObjectInfo, "Object Info", "")
|
||||
DefNode(GeometryNode, GEO_NODE_POINTS_TO_VERTICES, 0, "POINTS_TO_VERTICES", PointsToVertices, "Points to Vertices", "")
|
||||
DefNode(GeometryNode, GEO_NODE_REALIZE_INSTANCES, 0, "REALIZE_INSTANCES", RealizeInstances, "Realize Instances", "")
|
||||
DefNode(GeometryNode, GEO_NODE_SEPARATE_COMPONENTS, 0, "SEPARATE_COMPONENTS", SeparateComponents, "Separate Components", "")
|
||||
DefNode(GeometryNode, GEO_NODE_SET_POSITION, 0, "SET_POSITION", SetPosition, "Set Position", "")
|
||||
|
|
|
@ -0,0 +1,189 @@
|
|||
/*
|
||||
* 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 "DNA_pointcloud_types.h"
|
||||
|
||||
#include "BKE_attribute_math.hh"
|
||||
#include "BKE_pointcloud.h"
|
||||
|
||||
#include "UI_interface.h"
|
||||
#include "UI_resources.h"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
using blender::Array;
|
||||
|
||||
namespace blender::nodes {
|
||||
|
||||
static void geo_node_mesh_to_points_declare(NodeDeclarationBuilder &b)
|
||||
{
|
||||
b.add_input<decl::Geometry>("Mesh");
|
||||
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_input<decl::Bool>("Selection").default_value(true).supports_field().hide_value();
|
||||
b.add_output<decl::Geometry>("Points");
|
||||
}
|
||||
|
||||
static void geo_node_mesh_to_points_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
|
||||
{
|
||||
uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
|
||||
}
|
||||
|
||||
static void geo_node_mesh_to_points_init(bNodeTree *UNUSED(tree), bNode *node)
|
||||
{
|
||||
NodeGeometryMeshToPoints *data = (NodeGeometryMeshToPoints *)MEM_callocN(
|
||||
sizeof(NodeGeometryMeshToPoints), __func__);
|
||||
data->mode = GEO_NODE_MESH_TO_POINTS_FACES;
|
||||
node->storage = data;
|
||||
}
|
||||
|
||||
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 geometry_set_mesh_to_points(GeometrySet &geometry_set,
|
||||
Field<float3> &position_field,
|
||||
Field<float> &radius_field,
|
||||
Field<bool> &selection_field,
|
||||
const AttributeDomain domain)
|
||||
{
|
||||
const MeshComponent *mesh_component = geometry_set.get_component_for_read<MeshComponent>();
|
||||
if (mesh_component == nullptr) {
|
||||
geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
|
||||
return;
|
||||
}
|
||||
GeometryComponentFieldContext field_context{*mesh_component, domain};
|
||||
const int domain_size = mesh_component->attribute_domain_size(domain);
|
||||
if (domain_size == 0) {
|
||||
geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
|
||||
return;
|
||||
}
|
||||
fn::FieldEvaluator selection_evaluator{field_context, domain_size};
|
||||
selection_evaluator.add(selection_field);
|
||||
selection_evaluator.evaluate();
|
||||
const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
|
||||
|
||||
PointCloud *pointcloud = BKE_pointcloud_new_nomain(selection.size());
|
||||
uninitialized_fill_n(pointcloud->radius, pointcloud->totpoint, 0.05f);
|
||||
geometry_set.replace_pointcloud(pointcloud);
|
||||
PointCloudComponent &point_component =
|
||||
geometry_set.get_component_for_write<PointCloudComponent>();
|
||||
|
||||
/* Evaluating directly into the point cloud doesn't work because we are not using the full
|
||||
* "min_array_size" array but compressing the selected elements into the final array with no
|
||||
* gaps. */
|
||||
fn::FieldEvaluator evaluator{field_context, &selection};
|
||||
evaluator.add(position_field);
|
||||
evaluator.add(radius_field);
|
||||
evaluator.evaluate();
|
||||
copy_attribute_to_points(evaluator.get_evaluated<float3>(0),
|
||||
selection,
|
||||
{(float3 *)pointcloud->co, pointcloud->totpoint});
|
||||
copy_attribute_to_points(
|
||||
evaluator.get_evaluated<float>(1), selection, {pointcloud->radius, pointcloud->totpoint});
|
||||
|
||||
Map<AttributeIDRef, AttributeKind> attributes;
|
||||
geometry_set.gather_attributes_for_propagation(
|
||||
{GEO_COMPONENT_TYPE_MESH}, GEO_COMPONENT_TYPE_POINT_CLOUD, false, attributes);
|
||||
attributes.remove("position");
|
||||
|
||||
for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
|
||||
const AttributeIDRef attribute_id = entry.key;
|
||||
const CustomDataType data_type = entry.value.data_type;
|
||||
GVArrayPtr src = mesh_component->attribute_get_for_read(attribute_id, domain, data_type);
|
||||
OutputAttribute dst = point_component.attribute_try_get_for_output_only(
|
||||
attribute_id, ATTR_DOMAIN_POINT, data_type);
|
||||
if (dst && src) {
|
||||
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
GVArray_Typed<T> src_typed{*src};
|
||||
copy_attribute_to_points(*src_typed, selection, dst.as_span().typed<T>());
|
||||
});
|
||||
dst.save();
|
||||
}
|
||||
}
|
||||
|
||||
geometry_set.keep_only({GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_INSTANCES});
|
||||
}
|
||||
|
||||
static void geo_node_mesh_to_points_exec(GeoNodeExecParams params)
|
||||
{
|
||||
GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
|
||||
Field<float3> position = params.extract_input<Field<float3>>("Position");
|
||||
Field<float> radius = params.extract_input<Field<float>>("Radius");
|
||||
Field<bool> selection = params.extract_input<Field<bool>>("Selection");
|
||||
|
||||
/* Use another multi-function operation to make sure the input radius is greater than zero.
|
||||
* TODO: Use mutable multi-function once that is supported. */
|
||||
static fn::CustomMF_SI_SO<float, float> max_zero_fn(
|
||||
__func__, [](float value) { return std::max(0.0f, value); });
|
||||
auto max_zero_op = std::make_shared<FieldOperation>(
|
||||
FieldOperation(max_zero_fn, {std::move(radius)}));
|
||||
Field<float> positive_radius(std::move(max_zero_op), 0);
|
||||
|
||||
const NodeGeometryMeshToPoints &storage =
|
||||
*(const NodeGeometryMeshToPoints *)params.node().storage;
|
||||
const GeometryNodeMeshToPointsMode mode = (GeometryNodeMeshToPointsMode)storage.mode;
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
switch (mode) {
|
||||
case GEO_NODE_MESH_TO_POINTS_VERTICES:
|
||||
geometry_set_mesh_to_points(
|
||||
geometry_set, position, positive_radius, selection, ATTR_DOMAIN_POINT);
|
||||
break;
|
||||
case GEO_NODE_MESH_TO_POINTS_EDGES:
|
||||
geometry_set_mesh_to_points(
|
||||
geometry_set, position, positive_radius, selection, ATTR_DOMAIN_EDGE);
|
||||
break;
|
||||
case GEO_NODE_MESH_TO_POINTS_FACES:
|
||||
geometry_set_mesh_to_points(
|
||||
geometry_set, position, positive_radius, selection, ATTR_DOMAIN_FACE);
|
||||
break;
|
||||
case GEO_NODE_MESH_TO_POINTS_CORNERS:
|
||||
geometry_set_mesh_to_points(
|
||||
geometry_set, position, positive_radius, selection, ATTR_DOMAIN_CORNER);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
params.set_output("Points", std::move(geometry_set));
|
||||
}
|
||||
|
||||
} // namespace blender::nodes
|
||||
|
||||
void register_node_type_geo_mesh_to_points()
|
||||
{
|
||||
static bNodeType ntype;
|
||||
|
||||
geo_node_type_base(&ntype, GEO_NODE_MESH_TO_POINTS, "Mesh to Points", NODE_CLASS_GEOMETRY, 0);
|
||||
ntype.declare = blender::nodes::geo_node_mesh_to_points_declare;
|
||||
ntype.geometry_node_execute = blender::nodes::geo_node_mesh_to_points_exec;
|
||||
node_type_init(&ntype, blender::nodes::geo_node_mesh_to_points_init);
|
||||
ntype.draw_buttons = blender::nodes::geo_node_mesh_to_points_layout;
|
||||
node_type_storage(
|
||||
&ntype, "NodeGeometryMeshToPoints", node_free_standard_storage, node_copy_standard_storage);
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* 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 "BLI_task.hh"
|
||||
|
||||
#include "BKE_attribute_math.hh"
|
||||
#include "BKE_mesh.h"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
using blender::Array;
|
||||
|
||||
namespace blender::nodes {
|
||||
|
||||
static void geo_node_points_to_vertices_declare(NodeDeclarationBuilder &b)
|
||||
{
|
||||
b.add_input<decl::Geometry>("Points");
|
||||
b.add_input<decl::Bool>("Selection").default_value(true).supports_field().hide_value();
|
||||
b.add_output<decl::Geometry>("Mesh");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void copy_attribute_to_vertices(const Span<T> src, const IndexMask mask, MutableSpan<T> dst)
|
||||
{
|
||||
for (const int i : mask.index_range()) {
|
||||
dst[i] = src[mask[i]];
|
||||
}
|
||||
}
|
||||
|
||||
/* One improvement would be to move the attribute arrays directly to the mesh when possible. */
|
||||
static void geometry_set_points_to_vertices(GeometrySet &geometry_set,
|
||||
Field<bool> &selection_field)
|
||||
{
|
||||
const PointCloudComponent *point_component =
|
||||
geometry_set.get_component_for_read<PointCloudComponent>();
|
||||
if (point_component == nullptr) {
|
||||
geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
|
||||
return;
|
||||
}
|
||||
|
||||
GeometryComponentFieldContext field_context{*point_component, ATTR_DOMAIN_POINT};
|
||||
const int domain_size = point_component->attribute_domain_size(ATTR_DOMAIN_POINT);
|
||||
if (domain_size == 0) {
|
||||
geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
|
||||
return;
|
||||
}
|
||||
|
||||
fn::FieldEvaluator selection_evaluator{field_context, domain_size};
|
||||
selection_evaluator.add(selection_field);
|
||||
selection_evaluator.evaluate();
|
||||
const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
|
||||
|
||||
Map<AttributeIDRef, AttributeKind> attributes;
|
||||
geometry_set.gather_attributes_for_propagation(
|
||||
{GEO_COMPONENT_TYPE_POINT_CLOUD}, GEO_COMPONENT_TYPE_MESH, false, attributes);
|
||||
|
||||
Mesh *mesh = BKE_mesh_new_nomain(selection.size(), 0, 0, 0, 0);
|
||||
geometry_set.replace_mesh(mesh);
|
||||
MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
|
||||
|
||||
for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
|
||||
const AttributeIDRef attribute_id = entry.key;
|
||||
const CustomDataType data_type = entry.value.data_type;
|
||||
GVArrayPtr src = point_component->attribute_get_for_read(
|
||||
attribute_id, ATTR_DOMAIN_POINT, data_type);
|
||||
OutputAttribute dst = mesh_component.attribute_try_get_for_output_only(
|
||||
attribute_id, ATTR_DOMAIN_POINT, data_type);
|
||||
if (dst && src) {
|
||||
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
GVArray_Typed<T> src_typed{*src};
|
||||
VArray_Span<T> src_typed_span{*src_typed};
|
||||
copy_attribute_to_vertices(src_typed_span, selection, dst.as_span().typed<T>());
|
||||
});
|
||||
dst.save();
|
||||
}
|
||||
}
|
||||
|
||||
geometry_set.keep_only({GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_INSTANCES});
|
||||
}
|
||||
|
||||
static void geo_node_points_to_vertices_exec(GeoNodeExecParams params)
|
||||
{
|
||||
GeometrySet geometry_set = params.extract_input<GeometrySet>("Points");
|
||||
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
|
||||
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
|
||||
geometry_set_points_to_vertices(geometry_set, selection_field);
|
||||
});
|
||||
|
||||
params.set_output("Mesh", std::move(geometry_set));
|
||||
}
|
||||
|
||||
} // namespace blender::nodes
|
||||
|
||||
void register_node_type_geo_points_to_vertices()
|
||||
{
|
||||
static bNodeType ntype;
|
||||
|
||||
geo_node_type_base(
|
||||
&ntype, GEO_NODE_POINTS_TO_VERTICES, "Points to Vertices", NODE_CLASS_GEOMETRY, 0);
|
||||
ntype.declare = blender::nodes::geo_node_points_to_vertices_declare;
|
||||
ntype.geometry_node_execute = blender::nodes::geo_node_points_to_vertices_exec;
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
Loading…
Reference in New Issue