Blender V4.3
node_fn_axes_to_rotation.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BLI_math_matrix.hh"
6#include "BLI_math_rotation.h"
7
8#include "UI_interface.hh"
9#include "UI_resources.hh"
10
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>(N_("Primary Axis")).default_value(float3(0, 0, 1));
22 b.add_input<decl::Vector>(N_("Secondary Axis")).default_value(float3(1, 0, 0));
23 b.add_output<decl::Rotation>(N_("Rotation"));
24}
25
26static void node_init(bNodeTree * /*tree*/, bNode *node)
27{
28 node->custom1 = int(math::Axis::Z);
29 node->custom2 = int(math::Axis::X);
30}
31
32static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
33{
34 uiItemR(layout, ptr, "primary_axis", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
35 uiItemR(layout, ptr, "secondary_axis", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
36}
37
39{
41 if (v.x != -v.y) {
42 return float3{-v.y, v.x, 0.0f};
43 }
44 if (v.x != -v.z) {
45 return float3(-v.z, 0.0f, v.x);
46 }
47 return {0.0f, -v.z, v.y};
48}
49
51 private:
52 math::Axis primary_axis_;
53 math::Axis secondary_axis_;
54 math::Axis tertiary_axis_;
55
56 public:
57 AxesToRotationFunction(const math::Axis primary_axis, const math::Axis secondary_axis)
58 : primary_axis_(primary_axis), secondary_axis_(secondary_axis)
59 {
60 BLI_assert(primary_axis_ != secondary_axis_);
61
62 /* Through cancellation this will set the last axis to be the one that's neither the primary
63 * nor secondary axis. */
64 tertiary_axis_ = math::Axis::from_int((0 + 1 + 2) - primary_axis.as_int() -
65 secondary_axis.as_int());
66
67 static const mf::Signature signature = []() {
69 mf::SignatureBuilder builder{"Axes to Rotation", signature};
70 builder.single_input<float3>("Primary");
71 builder.single_input<float3>("Secondary");
72 builder.single_output<math::Quaternion>("Rotation");
73 return signature;
74 }();
75 this->set_signature(&signature);
76 }
77
78 void call(const IndexMask &mask, mf::Params params, mf::Context /*context*/) const override
79 {
80 const VArray<float3> primaries = params.readonly_single_input<float3>(0, "Primary");
81 const VArray<float3> secondaries = params.readonly_single_input<float3>(1, "Secondary");
82 MutableSpan r_rotations = params.uninitialized_single_output<math::Quaternion>(2, "Rotation");
83
84 /* Might have to invert the axis to make sure that the created matrix has determinant 1. */
85 const bool invert_tertiary = (secondary_axis_.as_int() + 1) % 3 == primary_axis_.as_int();
86 const float tertiary_factor = invert_tertiary ? -1.0f : 1.0f;
87
88 mask.foreach_index([&](const int64_t i) {
89 float3 primary = math::normalize(primaries[i]);
90 float3 secondary = secondaries[i];
91 float3 tertiary;
92
93 const bool primary_is_non_zero = !math::is_zero(primary);
94 const bool secondary_is_non_zero = !math::is_zero(secondary);
95 if (primary_is_non_zero && secondary_is_non_zero) {
96 tertiary = math::cross(primary, secondary);
97 if (math::is_zero(tertiary)) {
98 tertiary = get_orthogonal_of_non_zero_vector(primary);
99 }
100 tertiary = math::normalize(tertiary);
101 secondary = math::cross(tertiary, primary);
102 }
103 else if (primary_is_non_zero) {
104 secondary = get_orthogonal_of_non_zero_vector(primary);
105 secondary = math::normalize(secondary);
106 tertiary = math::cross(primary, secondary);
107 }
108 else if (secondary_is_non_zero) {
109 secondary = math::normalize(secondary);
110 primary = get_orthogonal_of_non_zero_vector(secondary);
111 primary = math::normalize(primary);
112 tertiary = math::cross(primary, secondary);
113 }
114 else {
115 r_rotations[i] = math::Quaternion::identity();
116 return;
117 }
118
119 float3x3 mat;
120 mat[primary_axis_.as_int()] = primary;
121 mat[secondary_axis_.as_int()] = secondary;
122 mat[tertiary_axis_.as_int()] = tertiary_factor * tertiary;
124 BLI_assert(std::abs(math::determinant(mat) - 1.0f) < 0.0001f);
125
126 r_rotations[i] = math::to_quaternion(mat);
127 });
128 };
129};
130
132{
133 const bNode &node = builder.node();
134 if (node.custom1 == node.custom2) {
135 return;
136 }
138 math::Axis::from_int(node.custom1), math::Axis::from_int(node.custom2));
139}
140
142{
143 if (params.node.custom1 == params.node.custom2) {
145 row.text = RPT_("Equal Axes");
146 row.tooltip = TIP_("The primary and secondary axis have to be different");
147 row.icon = ICON_ERROR;
148 params.rows.append(std::move(row));
149 }
150}
151
152static void node_rna(StructRNA *srna)
153{
154 static const EnumPropertyItem axis_items[] = {
155 {int(math::Axis::X), "X", ICON_NONE, "X", ""},
156 {int(math::Axis::Y), "Y", ICON_NONE, "Y", ""},
157 {int(math::Axis::Z), "Z", ICON_NONE, "Z", ""},
158 {0, nullptr, 0, nullptr, nullptr},
159 };
160
162 "primary_axis",
163 "Primary Axis",
164 "Axis that is aligned exactly to the provided primary direction",
165 axis_items,
168 srna,
169 "secondary_axis",
170 "Secondary Axis",
171 "Axis that is aligned as well as possible given the alignment of the primary axis",
172 axis_items,
174}
175
176static void node_register()
177{
178 static blender::bke::bNodeType ntype;
179 fn_node_type_base(&ntype, FN_NODE_AXES_TO_ROTATION, "Axes to Rotation", NODE_CLASS_CONVERTER);
180 ntype.declare = node_declare;
181 ntype.initfunc = node_init;
185 node_rna(ntype.rna_ext.srna);
187}
189
190} // namespace blender::nodes::node_fn_axes_to_rotation_cc
#define NODE_CLASS_CONVERTER
Definition BKE_node.hh:410
#define BLI_assert(a)
Definition BLI_assert.h:50
#define RPT_(msgid)
#define TIP_(msgid)
#define NOD_REGISTER_NODE(REGISTER_FUNC)
#define NOD_inline_enum_accessors(member)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
@ UI_ITEM_R_EXPAND
ATTR_WARN_UNUSED_RESULT const BMVert * v
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 override
AxesToRotationFunction(const math::Axis primary_axis, const math::Axis secondary_axis)
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)
bool is_orthonormal(const MatT &mat)
bool is_zero(const T &a)
AxisSigned cross(const AxisSigned a, const AxisSigned b)
MatBase< T, NumCol, NumRow > normalize(const MatBase< T, NumCol, NumRow > &a)
T determinant(const MatBase< T, Size, Size > &mat)
static void node_layout(uiLayout *layout, bContext *, PointerRNA *ptr)
static float3 get_orthogonal_of_non_zero_vector(const float3 &v)
static void node_build_multi_function(NodeMultiFunctionBuilder &builder)
static void node_declare(NodeDeclarationBuilder &b)
static void node_init(bNodeTree *, bNode *node)
static void node_extra_info(NodeExtraInfoParams &params)
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
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:267
NodeMultiFunctionBuildFunction build_multi_function
Definition BKE_node.hh:336
NodeExtraInfoFunction get_extra_info
Definition BKE_node.hh:366
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