Blender V4.3
node_fn_align_rotation_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.hh"
8#include "BLI_math_vector.h"
9#include "BLI_math_vector.hh"
10
11#include "UI_interface.hh"
12#include "UI_resources.hh"
13
14#include "NOD_rna_define.hh"
15
16#include "node_function_util.hh"
17
19
21{
22 b.is_function_node();
23 b.add_input<decl::Rotation>("Rotation").hide_value();
24 b.add_input<decl::Float>("Factor").default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
25 b.add_input<decl::Vector>("Vector").default_value({0.0, 0.0, 1.0}).subtype(PROP_XYZ);
26 b.add_output<decl::Rotation>("Rotation");
27}
28
29static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
30{
31 uiItemR(layout, ptr, "axis", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
32 uiLayoutSetPropSep(layout, true);
33 uiLayoutSetPropDecorate(layout, false);
34 uiItemR(layout, ptr, "pivot_axis", UI_ITEM_NONE, IFACE_("Pivot"), ICON_NONE);
35}
36
37static void node_init(bNodeTree * /*tree*/, bNode *node)
38{
39 node->custom1 = int16_t(math::Axis::Z);
40}
41
42static void align_rotations_auto_pivot(const IndexMask &mask,
43 const VArray<math::Quaternion> &input_rotations,
44 const VArray<float3> &vectors,
45 const VArray<float> &factors,
46 const float3 local_main_axis,
47 MutableSpan<math::Quaternion> output_rotations)
48{
49 mask.foreach_index([&](const int64_t i) {
50 const math::Quaternion old_rotation = input_rotations[i];
51 const float3 vector = vectors[i];
52 if (math::is_zero(vector)) {
53 output_rotations[i] = old_rotation;
54 return;
55 }
56
57 const float3 old_axis = math::transform_point(old_rotation, local_main_axis);
58
59 const float3 new_axis = math::normalize(vector);
60 float3 rotation_axis = math::cross_high_precision(old_axis, new_axis);
61 if (math::is_zero(rotation_axis)) {
62 /* The vectors are linearly dependent, so we fall back to another axis. */
63 rotation_axis = math::cross_high_precision(old_axis, float3(1, 0, 0));
64 if (math::is_zero(rotation_axis)) {
65 /* This is now guaranteed to not be zero. */
66 rotation_axis = math::cross_high_precision(old_axis, float3(0, 1, 0));
67 }
68 }
69
70 const float full_angle = angle_normalized_v3v3(old_axis, new_axis);
71 const float angle = factors[i] * full_angle;
72
73 const math::AxisAngle axis_angle = math::AxisAngle(math::normalize(rotation_axis), angle);
74 output_rotations[i] = math::to_quaternion(axis_angle) * old_rotation;
75 });
76}
77
78static void align_rotations_fixed_pivot(const IndexMask &mask,
79 const VArray<math::Quaternion> &input_rotations,
80 const VArray<float3> &vectors,
81 const VArray<float> &factors,
82 const float3 local_main_axis,
83 const float3 local_pivot_axis,
84 MutableSpan<math::Quaternion> output_rotations)
85{
86 mask.foreach_index([&](const int64_t i) {
87 const math::Quaternion old_rotation = input_rotations[i];
88 if (local_main_axis == local_pivot_axis) {
89 /* Can't compute any meaningful rotation angle in this case. */
90 output_rotations[i] = old_rotation;
91 return;
92 }
93
94 const float3 vector = vectors[i];
95 if (math::is_zero(vector)) {
96 output_rotations[i] = old_rotation;
97 return;
98 }
99
100 const float3 old_axis = math::transform_point(old_rotation, local_main_axis);
101 const float3 pivot_axis = math::transform_point(old_rotation, local_pivot_axis);
102
103 float full_angle = angle_signed_on_axis_v3v3_v3(vector, old_axis, pivot_axis);
104 if (full_angle > M_PI) {
105 /* Make sure the point is rotated as little as possible. */
106 full_angle -= 2.0f * M_PI;
107 }
108 const float angle = factors[i] * full_angle;
109
110 const math::AxisAngle axis_angle = math::AxisAngle(math::normalize(pivot_axis), angle);
111 output_rotations[i] = math::to_quaternion(axis_angle) * old_rotation;
112 });
113}
114
116 math::Axis main_axis_mode_;
117 NodeAlignEulerToVectorPivotAxis pivot_axis_mode_;
118
119 public:
121 const NodeAlignEulerToVectorPivotAxis pivot_axis_mode)
122 : main_axis_mode_(main_axis_mode), pivot_axis_mode_(pivot_axis_mode)
123 {
124 static const mf::Signature signature = []() {
126 mf::SignatureBuilder builder{"Align Rotation to Vector", signature};
127 builder.single_input<math::Quaternion>("Rotation");
128 builder.single_input<float>("Factor");
129 builder.single_input<float3>("Vector");
130 builder.single_output<math::Quaternion>("Rotation");
131 return signature;
132 }();
133 this->set_signature(&signature);
134 }
135
136 void call(const IndexMask &mask, mf::Params params, mf::Context /*context*/) const final
137 {
138 const VArray input_rotations = params.readonly_single_input<math::Quaternion>(0, "Rotation");
139 const VArray<float> factors = params.readonly_single_input<float>(1, "Factor");
140 const VArray<float3> vectors = params.readonly_single_input<float3>(2, "Vector");
141
142 MutableSpan output_rotations = params.uninitialized_single_output<math::Quaternion>(
143 3, "Rotation");
144
145 float3 local_main_axis = {0.0f, 0.0f, 0.0f};
146 local_main_axis[main_axis_mode_.as_int()] = 1.0f;
147
148 if (pivot_axis_mode_ == FN_NODE_ALIGN_EULER_TO_VECTOR_PIVOT_AXIS_AUTO) {
150 mask, input_rotations, vectors, factors, local_main_axis, output_rotations);
151 }
152 else {
153 float3 local_pivot_axis = {0.0f, 0.0f, 0.0f};
154 local_pivot_axis[pivot_axis_mode_ - 1] = 1;
156 input_rotations,
157 vectors,
158 factors,
159 local_main_axis,
160 local_pivot_axis,
161 output_rotations);
162 }
163 }
164
166 {
167 ExecutionHints hints;
168 hints.min_grain_size = 512;
169 return hints;
170 }
171};
172
174{
175 const bNode &node = builder.node();
177 math::Axis::from_int(node.custom1), NodeAlignEulerToVectorPivotAxis(node.custom2));
178}
179
180static void node_rna(StructRNA *srna)
181{
182 static const EnumPropertyItem axis_items[] = {
183 {int(math::Axis::X), "X", ICON_NONE, "X", "Align the X axis with the vector"},
184 {int(math::Axis::Y), "Y", ICON_NONE, "Y", "Align the Y axis with the vector"},
185 {int(math::Axis::Z), "Z", ICON_NONE, "Z", "Align the Z axis with the vector"},
186 {0, nullptr, 0, nullptr, nullptr},
187 };
188
190 "axis",
191 "Axis",
192 "Axis to align to the vector",
193 axis_items,
195
196 static const EnumPropertyItem pivot_axis_items[] = {
198 "AUTO",
199 ICON_NONE,
200 "Auto",
201 "Automatically detect the best rotation axis to rotate towards the vector"},
203 "X",
204 ICON_NONE,
205 "X",
206 "Rotate around the local X axis"},
208 "Y",
209 ICON_NONE,
210 "Y",
211 "Rotate around the local Y axis"},
213 "Z",
214 ICON_NONE,
215 "Z",
216 "Rotate around the local Z axis"},
217 {0, nullptr, 0, nullptr, nullptr},
218 };
219
221 "pivot_axis",
222 "Pivot Axis",
223 "Axis to rotate around",
224 pivot_axis_items,
226}
227
228static void node_register()
229{
230 static blender::bke::bNodeType ntype;
231
233 &ntype, FN_NODE_ALIGN_ROTATION_TO_VECTOR, "Align Rotation to Vector", NODE_CLASS_CONVERTER);
234 ntype.declare = node_declare;
235 ntype.initfunc = node_init;
239
240 node_rna(ntype.rna_ext.srna);
241}
243
244} // namespace blender::nodes::node_fn_align_rotation_to_vector_cc
#define NODE_CLASS_CONVERTER
Definition BKE_node.hh:410
#define M_PI
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)
NodeAlignEulerToVectorPivotAxis
@ 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_XYZ
Definition RNA_types.hh:172
@ 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)
constexpr int as_int() const
static constexpr Value Z
static constexpr Axis from_int(const int axis_int)
static constexpr Value X
static constexpr Value Y
void call(const IndexMask &mask, mf::Params params, mf::Context) const final
AlignRotationToVectorFunction(const math::Axis main_axis_mode, const NodeAlignEulerToVectorPivotAxis pivot_axis_mode)
local_group_size(16, 16) .push_constant(Type b
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void node_register_type(bNodeType *ntype)
Definition node.cc:1708
QuaternionBase< T > to_quaternion(const AxisAngleBase< T, AngleT > &axis_angle)
VecBase< float, 3 > cross_high_precision(const VecBase< float, 3 > &a, const VecBase< float, 3 > &b)
AxisAngleBase< float, AngleRadianBase< float > > AxisAngle
bool is_zero(const T &a)
MatBase< T, NumCol, NumRow > normalize(const MatBase< T, NumCol, NumRow > &a)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
static void align_rotations_auto_pivot(const IndexMask &mask, const VArray< math::Quaternion > &input_rotations, const VArray< float3 > &vectors, const VArray< float > &factors, const float3 local_main_axis, MutableSpan< math::Quaternion > output_rotations)
static void node_layout(uiLayout *layout, bContext *, PointerRNA *ptr)
static void align_rotations_fixed_pivot(const IndexMask &mask, const VArray< math::Quaternion > &input_rotations, const VArray< float3 > &vectors, const VArray< float > &factors, const float3 local_main_axis, const float3 local_pivot_axis, MutableSpan< math::Quaternion > output_rotations)
static void node_build_multi_function(NodeMultiFunctionBuilder &builder)
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)
signed short int16_t
Definition stdint.h:76
__int64 int64_t
Definition stdint.h:89
StructRNA * srna
Definition RNA_types.hh:780
Defines a node type.
Definition BKE_node.hh:218
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:267
NodeMultiFunctionBuildFunction build_multi_function
Definition BKE_node.hh:336
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:238
NodeDeclareFunction declare
Definition BKE_node.hh:347
PointerRNA * ptr
Definition wm_files.cc:4126