Blender V4.3
node_geo_input_tangent.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 "BLI_task.hh"
6
7#include "BKE_curves.hh"
8
10
12
14{
15 b.add_output<decl::Vector>("Tangent").field_source();
16}
17
19{
20 const OffsetIndices points_by_curve = curves.points_by_curve();
21 const OffsetIndices evaluated_points_by_curve = curves.evaluated_points_by_curve();
22 const VArray<int8_t> types = curves.curve_types();
23 const VArray<int> resolutions = curves.resolution();
24 const VArray<bool> cyclic = curves.cyclic();
25 const Span<float3> positions = curves.positions();
26
27 const Span<float3> evaluated_tangents = curves.evaluated_tangents();
28
29 Array<float3> results(curves.points_num());
30
31 threading::parallel_for(curves.curves_range(), 128, [&](IndexRange range) {
32 for (const int i_curve : range) {
33 const IndexRange points = points_by_curve[i_curve];
34 const IndexRange evaluated_points = evaluated_points_by_curve[i_curve];
35
36 MutableSpan<float3> curve_tangents = results.as_mutable_span().slice(points);
37
38 switch (types[i_curve]) {
39 case CURVE_TYPE_CATMULL_ROM: {
40 Span<float3> tangents = evaluated_tangents.slice(evaluated_points);
41 const int resolution = resolutions[i_curve];
42 for (const int i : IndexRange(points.size())) {
43 curve_tangents[i] = tangents[resolution * i];
44 }
45 break;
46 }
47 case CURVE_TYPE_POLY:
48 curve_tangents.copy_from(evaluated_tangents.slice(evaluated_points));
49 break;
50 case CURVE_TYPE_BEZIER: {
51 Span<float3> tangents = evaluated_tangents.slice(evaluated_points);
52 curve_tangents.first() = tangents.first();
53 const Span<int> offsets = curves.bezier_evaluated_offsets_for_curve(i_curve);
54 for (const int i : IndexRange(points.size()).drop_front(1)) {
55 curve_tangents[i] = tangents[offsets[i]];
56 }
57 break;
58 }
59 case CURVE_TYPE_NURBS: {
60 const Span<float3> curve_positions = positions.slice(points);
61 bke::curves::poly::calculate_tangents(curve_positions, cyclic[i_curve], curve_tangents);
62 break;
63 }
64 }
65 }
66 });
67 return results;
68}
69
71 const AttrDomain domain)
72{
73 const VArray<int8_t> types = curves.curve_types();
74 if (curves.is_single_type(CURVE_TYPE_POLY)) {
75 return curves.adapt_domain<float3>(
76 VArray<float3>::ForSpan(curves.evaluated_tangents()), AttrDomain::Point, domain);
77 }
78
80
81 if (domain == AttrDomain::Point) {
82 return VArray<float3>::ForContainer(std::move(tangents));
83 }
84
85 if (domain == AttrDomain::Curve) {
86 return curves.adapt_domain<float3>(
87 VArray<float3>::ForContainer(std::move(tangents)), AttrDomain::Point, AttrDomain::Curve);
88 }
89
90 return nullptr;
91}
92
94 public:
95 TangentFieldInput() : bke::CurvesFieldInput(CPPType::get<float3>(), "Tangent node")
96 {
97 category_ = Category::Generated;
98 }
99
101 const AttrDomain domain,
102 const IndexMask & /*mask*/) const final
103 {
104 return construct_curve_tangent_gvarray(curves, domain);
105 }
106
107 uint64_t hash() const override
108 {
109 /* Some random constant hash. */
110 return 91827364589;
111 }
112
113 bool is_equal_to(const fn::FieldNode &other) const override
114 {
115 return dynamic_cast<const TangentFieldInput *>(&other) != nullptr;
116 }
117
118 std::optional<AttrDomain> preferred_domain(const bke::CurvesGeometry & /*curves*/) const final
119 {
120 return AttrDomain::Point;
121 }
122};
123
125{
126 Field<float3> tangent_field{std::make_shared<TangentFieldInput>()};
127 params.set_output("Tangent", std::move(tangent_field));
128}
129
130static void node_register()
131{
132 static blender::bke::bNodeType ntype;
133
134 geo_node_type_base(&ntype, GEO_NODE_INPUT_TANGENT, "Curve Tangent", NODE_CLASS_INPUT);
136 ntype.declare = node_declare;
138}
139NOD_REGISTER_NODE(node_register)
140
141} // namespace blender::nodes::node_geo_input_tangent_cc
Low-level operations for curves.
#define NODE_CLASS_INPUT
Definition BKE_node.hh:404
@ CURVE_TYPE_POLY
#define NOD_REGISTER_NODE(REGISTER_FUNC)
bool is_equal_to(const fn::FieldNode &other) const override
GVArray get_varray_for_context(const bke::CurvesGeometry &curves, const AttrDomain domain, const IndexMask &) const final
std::optional< AttrDomain > preferred_domain(const bke::CurvesGeometry &) const final
local_group_size(16, 16) .push_constant(Type b
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void node_register_type(bNodeType *ntype)
Definition node.cc:1708
static VArray< float3 > construct_curve_tangent_gvarray(const bke::CurvesGeometry &curves, const AttrDomain domain)
static Array< float3 > curve_tangent_point_domain(const bke::CurvesGeometry &curves)
static void node_declare(NodeDeclarationBuilder &b)
static void node_geo_exec(GeoNodeExecParams params)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:95
void geo_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
unsigned __int64 uint64_t
Definition stdint.h:90
Defines a node type.
Definition BKE_node.hh:218
NodeGeometryExecFunction geometry_node_execute
Definition BKE_node.hh:339
NodeDeclareFunction declare
Definition BKE_node.hh:347