Blender V4.3
node_fn_align_euler_to_vector.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_math_matrix.h"
6#include "BLI_math_rotation.h"
7#include "BLI_math_vector.h"
8
9#include "UI_interface.hh"
10#include "UI_resources.hh"
11
12#include "NOD_rna_define.hh"
13
14#include "node_function_util.hh"
15
17
19{
20 b.is_function_node();
21 b.add_input<decl::Vector>("Rotation").subtype(PROP_EULER).hide_value();
22 b.add_input<decl::Float>("Factor").default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
23 b.add_input<decl::Vector>("Vector").default_value({0.0, 0.0, 1.0});
24 b.add_output<decl::Vector>("Rotation").subtype(PROP_EULER);
25}
26
27static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
28{
29 uiItemR(layout, ptr, "axis", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
30 uiLayoutSetPropSep(layout, true);
31 uiLayoutSetPropDecorate(layout, false);
32 uiItemR(layout, ptr, "pivot_axis", UI_ITEM_NONE, IFACE_("Pivot"), ICON_NONE);
33}
34
35static void align_rotations_auto_pivot(const IndexMask &mask,
36 const VArray<float3> &input_rotations,
37 const VArray<float3> &vectors,
38 const VArray<float> &factors,
39 const float3 local_main_axis,
40 MutableSpan<float3> output_rotations)
41{
42 mask.foreach_index([&](const int64_t i) {
43 const float3 vector = vectors[i];
44 if (math::is_zero(vector)) {
45 output_rotations[i] = input_rotations[i];
46 return;
47 }
48
49 float old_rotation[3][3];
50 eul_to_mat3(old_rotation, input_rotations[i]);
51 float3 old_axis;
52 mul_v3_m3v3(old_axis, old_rotation, local_main_axis);
53
54 const float3 new_axis = math::normalize(vector);
55 float3 rotation_axis = math::cross_high_precision(old_axis, new_axis);
56 if (math::is_zero(rotation_axis)) {
57 /* The vectors are linearly dependent, so we fall back to another axis. */
58 rotation_axis = math::cross_high_precision(old_axis, float3(1, 0, 0));
59 if (math::is_zero(rotation_axis)) {
60 /* This is now guaranteed to not be zero. */
61 rotation_axis = math::cross_high_precision(old_axis, float3(0, 1, 0));
62 }
63 }
64
65 const float full_angle = angle_normalized_v3v3(old_axis, new_axis);
66 const float angle = factors[i] * full_angle;
67
68 float rotation[3][3];
69 axis_angle_to_mat3(rotation, rotation_axis, angle);
70
71 float new_rotation_matrix[3][3];
72 mul_m3_m3m3(new_rotation_matrix, rotation, old_rotation);
73
74 float3 new_rotation;
75 mat3_to_eul(new_rotation, new_rotation_matrix);
76
77 output_rotations[i] = new_rotation;
78 });
79}
80
81static void align_rotations_fixed_pivot(const IndexMask &mask,
82 const VArray<float3> &input_rotations,
83 const VArray<float3> &vectors,
84 const VArray<float> &factors,
85 const float3 local_main_axis,
86 const float3 local_pivot_axis,
87 MutableSpan<float3> output_rotations)
88{
89 mask.foreach_index([&](const int64_t i) {
90 if (local_main_axis == local_pivot_axis) {
91 /* Can't compute any meaningful rotation angle in this case. */
92 output_rotations[i] = input_rotations[i];
93 return;
94 }
95
96 const float3 vector = vectors[i];
97 if (math::is_zero(vector)) {
98 output_rotations[i] = input_rotations[i];
99 return;
100 }
101
102 float old_rotation[3][3];
103 eul_to_mat3(old_rotation, input_rotations[i]);
104 float3 old_axis;
105 mul_v3_m3v3(old_axis, old_rotation, local_main_axis);
106 float3 pivot_axis;
107 mul_v3_m3v3(pivot_axis, old_rotation, local_pivot_axis);
108
109 float full_angle = angle_signed_on_axis_v3v3_v3(vector, old_axis, pivot_axis);
110 if (full_angle > M_PI) {
111 /* Make sure the point is rotated as little as possible. */
112 full_angle -= 2.0f * M_PI;
113 }
114 const float angle = factors[i] * full_angle;
115
116 float rotation[3][3];
117 axis_angle_to_mat3(rotation, pivot_axis, angle);
118
119 float new_rotation_matrix[3][3];
120 mul_m3_m3m3(new_rotation_matrix, rotation, old_rotation);
121
122 float3 new_rotation;
123 mat3_to_eul(new_rotation, new_rotation_matrix);
124
125 output_rotations[i] = new_rotation;
126 });
127}
128
130 private:
131 int main_axis_mode_;
132 int pivot_axis_mode_;
133
134 public:
135 MF_AlignEulerToVector(int main_axis_mode, int pivot_axis_mode)
136 : main_axis_mode_(main_axis_mode), pivot_axis_mode_(pivot_axis_mode)
137 {
138 static const mf::Signature signature = []() {
140 mf::SignatureBuilder builder{"Align Euler to Vector", signature};
141 builder.single_input<float3>("Rotation");
142 builder.single_input<float>("Factor");
143 builder.single_input<float3>("Vector");
144 builder.single_output<float3>("Rotation");
145 return signature;
146 }();
147 this->set_signature(&signature);
148 }
149
150 void call(const IndexMask &mask, mf::Params params, mf::Context /*context*/) const override
151 {
152 const VArray<float3> &input_rotations = params.readonly_single_input<float3>(0, "Rotation");
153 const VArray<float> &factors = params.readonly_single_input<float>(1, "Factor");
154 const VArray<float3> &vectors = params.readonly_single_input<float3>(2, "Vector");
155
156 auto output_rotations = params.uninitialized_single_output<float3>(3, "Rotation");
157
158 float3 local_main_axis = {0.0f, 0.0f, 0.0f};
159 local_main_axis[main_axis_mode_] = 1;
160
161 if (pivot_axis_mode_ == FN_NODE_ALIGN_EULER_TO_VECTOR_PIVOT_AXIS_AUTO) {
163 mask, input_rotations, vectors, factors, local_main_axis, output_rotations);
164 }
165 else {
166 float3 local_pivot_axis = {0.0f, 0.0f, 0.0f};
167 local_pivot_axis[pivot_axis_mode_ - 1] = 1;
169 input_rotations,
170 vectors,
171 factors,
172 local_main_axis,
173 local_pivot_axis,
174 output_rotations);
175 }
176 }
177
179 {
180 ExecutionHints hints;
181 hints.min_grain_size = 512;
182 return hints;
183 }
184};
185
187{
188 const bNode &node = builder.node();
189 builder.construct_and_set_matching_fn<MF_AlignEulerToVector>(node.custom1, node.custom2);
190}
191
192static void node_rna(StructRNA *srna)
193{
194 static const EnumPropertyItem axis_items[] = {
196 "X",
197 ICON_NONE,
198 "X",
199 "Align the X axis with the vector"},
201 "Y",
202 ICON_NONE,
203 "Y",
204 "Align the Y axis with the vector"},
206 "Z",
207 ICON_NONE,
208 "Z",
209 "Align the Z axis with the vector"},
210 {0, nullptr, 0, nullptr, nullptr},
211 };
212
213 static const EnumPropertyItem pivot_axis_items[] = {
215 "AUTO",
216 ICON_NONE,
217 "Auto",
218 "Automatically detect the best rotation axis to rotate towards the vector"},
220 "X",
221 ICON_NONE,
222 "X",
223 "Rotate around the local X axis"},
225 "Y",
226 ICON_NONE,
227 "Y",
228 "Rotate around the local Y axis"},
230 "Z",
231 ICON_NONE,
232 "Z",
233 "Rotate around the local Z axis"},
234 {0, nullptr, 0, nullptr, nullptr},
235 };
236
238 "axis",
239 "Axis",
240 "Axis to align to the vector",
241 axis_items,
243 std::nullopt,
244 nullptr,
245 true);
246
248 "pivot_axis",
249 "Pivot Axis",
250 "Axis to rotate around",
251 pivot_axis_items,
253 std::nullopt,
254 nullptr,
255 true);
256}
257
258static void node_register()
259{
260 static blender::bke::bNodeType ntype;
261
263 &ntype, FN_NODE_ALIGN_EULER_TO_VECTOR, "Align Euler to Vector", NODE_CLASS_CONVERTER);
264 ntype.declare = node_declare;
267 ntype.deprecation_notice = N_("Use the \"Align Rotation to Vector\" node instead");
269
270 node_rna(ntype.rna_ext.srna);
271}
273
274} // namespace blender::nodes::node_fn_align_euler_to_vector_cc
#define NODE_CLASS_CONVERTER
Definition BKE_node.hh:410
#define M_PI
void mul_v3_m3v3(float r[3], const float M[3][3], const float a[3])
void mul_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3])
void eul_to_mat3(float mat[3][3], const float eul[3])
void mat3_to_eul(float eul[3], const float mat[3][3])
void axis_angle_to_mat3(float R[3][3], const float axis[3], float angle)
float angle_signed_on_axis_v3v3_v3(const float v1[3], const float v2[3], const float axis[3]) ATTR_WARN_UNUSED_RESULT
float angle_normalized_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT
#define IFACE_(msgid)
@ FN_NODE_ALIGN_EULER_TO_VECTOR_AXIS_Z
@ FN_NODE_ALIGN_EULER_TO_VECTOR_AXIS_Y
@ FN_NODE_ALIGN_EULER_TO_VECTOR_AXIS_X
@ FN_NODE_ALIGN_EULER_TO_VECTOR_PIVOT_AXIS_Y
@ FN_NODE_ALIGN_EULER_TO_VECTOR_PIVOT_AXIS_AUTO
@ FN_NODE_ALIGN_EULER_TO_VECTOR_PIVOT_AXIS_X
@ FN_NODE_ALIGN_EULER_TO_VECTOR_PIVOT_AXIS_Z
#define NOD_REGISTER_NODE(REGISTER_FUNC)
#define NOD_inline_enum_accessors(member)
@ PROP_EULER
Definition RNA_types.hh:169
@ PROP_FACTOR
Definition RNA_types.hh:154
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
#define UI_ITEM_NONE
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
@ UI_ITEM_R_EXPAND
void set_signature(const Signature *signature)
void call(const IndexMask &mask, mf::Params params, mf::Context) const override
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
VecBase< float, 3 > cross_high_precision(const VecBase< float, 3 > &a, const VecBase< float, 3 > &b)
bool is_zero(const T &a)
MatBase< T, NumCol, NumRow > normalize(const MatBase< T, NumCol, NumRow > &a)
static void node_build_multi_function(NodeMultiFunctionBuilder &builder)
static void align_rotations_fixed_pivot(const IndexMask &mask, const VArray< float3 > &input_rotations, const VArray< float3 > &vectors, const VArray< float > &factors, const float3 local_main_axis, const float3 local_pivot_axis, MutableSpan< float3 > output_rotations)
static void align_rotations_auto_pivot(const IndexMask &mask, const VArray< float3 > &input_rotations, const VArray< float3 > &vectors, const VArray< float > &factors, const float3 local_main_axis, MutableSpan< float3 > output_rotations)
static void node_layout(uiLayout *layout, bContext *, PointerRNA *ptr)
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)
VecBase< float, 3 > float3
void fn_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
__int64 int64_t
Definition stdint.h:89
StructRNA * srna
Definition RNA_types.hh:780
Defines a node type.
Definition BKE_node.hh:218
NodeMultiFunctionBuildFunction build_multi_function
Definition BKE_node.hh:336
const char * deprecation_notice
Definition BKE_node.hh:397
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:238
NodeDeclareFunction declare
Definition BKE_node.hh:347
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4126