Blender V5.0
node_geo_curve_to_mesh.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BKE_curves.hh"
6
9#include "BKE_instances.hh"
10
13#include "GEO_randomize.hh"
14
15#include "DNA_mesh_types.h"
16
17#include "node_geometry_util.hh"
18
20
22{
23 b.add_input<decl::Geometry>("Curve")
24 .supported_type({GeometryComponent::Type::Curve, GeometryComponent::Type::GreasePencil})
25 .description("Curve to convert to a mesh using the given profile");
26 b.add_input<decl::Geometry>("Profile Curve")
27 .only_realized_data()
28 .supported_type(GeometryComponent::Type::Curve)
29 .description("Curves that are swept along the main curve");
30 b.add_input<decl::Float>("Scale").default_value(1.0f).min(0.0f).field_on({0}).description(
31 "Scale of the profile at each point");
32 b.add_input<decl::Bool>("Fill Caps")
33 .description(
34 "If the profile spline is cyclic, fill the ends of the generated mesh with N-gons");
35 b.add_output<decl::Geometry>("Mesh").propagate_all();
36}
37
39 const GeometrySet &profile_set,
40 const fn::FieldContext &context,
41 const Field<float> &scale_field,
42 const bool fill_caps,
43 const AttributeFilter &attribute_filter)
44{
45 Mesh *mesh;
46 if (profile_set.has_curves()) {
47 const Curves *profile_curves = profile_set.get_curves();
48
49 FieldEvaluator evaluator{context, curves.points_num()};
50 evaluator.add(scale_field);
51 evaluator.evaluate();
52
53 const VArray<float> profile_scales = evaluator.get_evaluated<float>(0);
55 curves, profile_curves->geometry.wrap(), profile_scales, fill_caps, attribute_filter);
56 }
57 else {
58 mesh = bke::curve_to_wire_mesh(curves, attribute_filter);
59 }
61 return mesh;
62}
63
64static void grease_pencil_to_mesh(GeometrySet &geometry_set,
65 const GeometrySet &profile_set,
66 const Field<float> &scale_field,
67 const bool fill_caps,
68 const AttributeFilter &attribute_filter)
69{
70 using namespace blender::bke::greasepencil;
71
72 const GreasePencil &grease_pencil = *geometry_set.get_grease_pencil();
73 Array<Mesh *> mesh_by_layer(grease_pencil.layers().size(), nullptr);
74
75 for (const int layer_index : grease_pencil.layers().index_range()) {
76 const Drawing *drawing = grease_pencil.get_eval_drawing(grease_pencil.layer(layer_index));
77 if (drawing == nullptr) {
78 continue;
79 }
80 const bke::CurvesGeometry &curves = drawing->strokes();
82 grease_pencil, bke::AttrDomain::Point, layer_index};
83 mesh_by_layer[layer_index] = curve_to_mesh(
84 curves, profile_set, context, scale_field, fill_caps, attribute_filter);
85 }
86
87 if (mesh_by_layer.is_empty()) {
88 return;
89 }
90
91 bke::Instances *instances = new bke::Instances();
92 for (Mesh *mesh : mesh_by_layer) {
93 if (!mesh) {
94 /* Add an empty reference so the number of layers and instances match.
95 * This makes it easy to reconstruct the layers afterwards and keep their attributes.
96 * Although in this particular case we don't propagate the attributes. */
97 const int handle = instances->add_reference(bke::InstanceReference());
98 instances->add_instance(handle, float4x4::identity());
99 continue;
100 }
102 const int handle = instances->add_reference(bke::InstanceReference{temp_set});
103 instances->add_instance(handle, float4x4::identity());
104 }
105
106 bke::copy_attributes(geometry_set.get_grease_pencil()->attributes(),
109 attribute_filter,
110 instances->attributes_for_write());
111 InstancesComponent &dst_component = geometry_set.get_component_for_write<InstancesComponent>();
113 {GeometrySet::from_instances(dst_component.release()),
114 GeometrySet::from_instances(instances)},
115 attribute_filter);
116 dst_component.replace(new_instances.get_component_for_write<InstancesComponent>().release());
117 geometry_set.replace_grease_pencil(nullptr);
118}
119
121{
122 GeometrySet curve_set = params.extract_input<GeometrySet>("Curve");
123 GeometrySet profile_set = params.extract_input<GeometrySet>("Profile Curve");
124 const Field<float> scale_field = params.extract_input<Field<float>>("Scale");
125 const bool fill_caps = params.extract_input<bool>("Fill Caps");
126
128 const AttributeFilter &attribute_filter = params.get_attribute_filter("Mesh");
129
130 geometry::foreach_real_geometry(curve_set, [&](GeometrySet &geometry_set) {
131 if (geometry_set.has_curves()) {
132 const Curves &curves = *geometry_set.get_curves();
133
136 curves.geometry.wrap(), profile_set, context, scale_field, fill_caps, attribute_filter);
137 if (mesh != nullptr) {
138 mesh->mat = static_cast<Material **>(MEM_dupallocN(curves.mat));
139 mesh->totcol = curves.totcol;
140 }
141 geometry_set.replace_mesh(mesh);
142 }
143 if (geometry_set.has_grease_pencil()) {
144 grease_pencil_to_mesh(geometry_set, profile_set, scale_field, fill_caps, attribute_filter);
145 }
149 });
150
151 params.set_output("Mesh", std::move(curve_set));
152}
153
154static void node_register()
155{
156 static blender::bke::bNodeType ntype;
157
158 geo_node_type_base(&ntype, "GeometryNodeCurveToMesh", GEO_NODE_CURVE_TO_MESH);
159 ntype.ui_name = "Curve to Mesh";
160 ntype.ui_description =
161 "Convert curves into a mesh, optionally with a custom profile shape defined by curves";
162 ntype.enum_name_legacy = "CURVE_TO_MESH";
164 ntype.declare = node_declare;
167}
169
170} // namespace blender::nodes::node_geo_curve_to_mesh_cc
Low-level operations for curves.
Low-level operations for grease pencil.
#define NODE_CLASS_GEOMETRY
Definition BKE_node.hh:461
#define GEO_NODE_CURVE_TO_MESH
#define NOD_REGISTER_NODE(REGISTER_FUNC)
bool is_empty() const
Definition BLI_array.hh:264
static void remember_deformed_positions_if_necessary(GeometrySet &geometry)
void replace(Instances *instances, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
int add_reference(const InstanceReference &reference)
Definition instances.cc:261
void add_instance(int instance_handle, const float4x4 &transform)
Definition instances.cc:204
bke::MutableAttributeAccessor attributes_for_write()
Definition instances.cc:69
const bke::CurvesGeometry & strokes() const
int add(GField field, GVArray *varray_ptr)
Definition field.cc:751
const GVArray & get_evaluated(const int field_index) const
Definition FN_field.hh:448
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void node_register_type(bNodeType &ntype)
Definition node.cc:2416
void copy_attributes(const AttributeAccessor src_attributes, AttrDomain src_domain, AttrDomain dst_domain, const AttributeFilter &attribute_filter, MutableAttributeAccessor dst_attributes)
Mesh * curve_to_mesh_sweep(const CurvesGeometry &main, const CurvesGeometry &profile, const VArray< float > &scales, bool fill_caps, const bke::AttributeFilter &attribute_filter={})
Mesh * curve_to_wire_mesh(const CurvesGeometry &curve, const bke::AttributeFilter &attribute_filter={})
bke::GeometrySet join_geometries(Span< bke::GeometrySet > geometries, const bke::AttributeFilter &attribute_filter, const std::optional< Span< bke::GeometryComponent::Type > > &component_types_to_join=std::nullopt, bool allow_merging_instance_references=true)
void foreach_real_geometry(bke::GeometrySet &geometry, FunctionRef< void(bke::GeometrySet &geometry_set)> fn)
void debug_randomize_mesh_order(Mesh *mesh)
Definition randomize.cc:288
static void node_declare(NodeDeclarationBuilder &b)
static void node_geo_exec(GeoNodeExecParams params)
static void grease_pencil_to_mesh(GeometrySet &geometry_set, const GeometrySet &profile_set, const Field< float > &scale_field, const bool fill_caps, const AttributeFilter &attribute_filter)
static Mesh * curve_to_mesh(const bke::CurvesGeometry &curves, const GeometrySet &profile_set, const fn::FieldContext &context, const Field< float > &scale_field, const bool fill_caps, const AttributeFilter &attribute_filter)
void geo_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
CurvesGeometry geometry
void keep_only(Span< GeometryComponent::Type > component_types)
GeometryComponent & get_component_for_write(GeometryComponent::Type component_type)
const GreasePencil * get_grease_pencil() const
const Curves * get_curves() const
void replace_mesh(Mesh *mesh, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
void replace_grease_pencil(GreasePencil *grease_pencil, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
Defines a node type.
Definition BKE_node.hh:238
std::string ui_description
Definition BKE_node.hh:244
NodeGeometryExecFunction geometry_node_execute
Definition BKE_node.hh:354
const char * enum_name_legacy
Definition BKE_node.hh:247
NodeDeclareFunction declare
Definition BKE_node.hh:362
static GeometrySet from_instances(Instances *instances, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
static GeometrySet from_mesh(Mesh *mesh, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)