Blender V5.0
node_fn_separate_matrix.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
7
9
11
13{
14 b.is_function_node();
15 b.use_custom_socket_order();
16 b.allow_any_socket_order();
17
18 PanelDeclarationBuilder &column_a = b.add_panel("Column 1").default_closed(true);
19 column_a.add_output<decl::Float>("Column 1 Row 1");
20 column_a.add_output<decl::Float>("Column 1 Row 2");
21 column_a.add_output<decl::Float>("Column 1 Row 3");
22 column_a.add_output<decl::Float>("Column 1 Row 4");
23
24 PanelDeclarationBuilder &column_b = b.add_panel("Column 2").default_closed(true);
25 column_b.add_output<decl::Float>("Column 2 Row 1");
26 column_b.add_output<decl::Float>("Column 2 Row 2");
27 column_b.add_output<decl::Float>("Column 2 Row 3");
28 column_b.add_output<decl::Float>("Column 2 Row 4");
29
30 PanelDeclarationBuilder &column_c = b.add_panel("Column 3").default_closed(true);
31 column_c.add_output<decl::Float>("Column 3 Row 1");
32 column_c.add_output<decl::Float>("Column 3 Row 2");
33 column_c.add_output<decl::Float>("Column 3 Row 3");
34 column_c.add_output<decl::Float>("Column 3 Row 4");
35
36 PanelDeclarationBuilder &column_d = b.add_panel("Column 4").default_closed(true);
37 column_d.add_output<decl::Float>("Column 4 Row 1");
38 column_d.add_output<decl::Float>("Column 4 Row 2");
39 column_d.add_output<decl::Float>("Column 4 Row 3");
40 column_d.add_output<decl::Float>("Column 4 Row 4");
41
42 b.add_input<decl::Matrix>("Matrix");
43}
44
45static void copy_with_stride(const IndexMask &mask,
46 const Span<float> src,
47 const int64_t src_step,
48 const int64_t src_begin,
49 const int64_t dst_step,
50 const int64_t dst_begin,
52{
53 if (dst.is_empty()) {
54 return;
55 }
56 BLI_assert(src_begin < src_step);
57 BLI_assert(dst_begin < dst_step);
58 mask.foreach_index_optimized<int>([&](const int64_t index) {
59 dst[dst_begin + dst_step * index] = src[src_begin + src_step * index];
60 });
61}
62
63class SeparateMatrixFunction : public mf::MultiFunction {
64 public:
66 {
67 static const mf::Signature signature = []() {
68 mf::Signature signature;
69 mf::SignatureBuilder builder{"Separate Matrix", signature};
70 builder.single_input<float4x4>("Matrix");
71
72 builder.single_output<float>("Column 1 Row 1", mf::ParamFlag::SupportsUnusedOutput);
73 builder.single_output<float>("Column 1 Row 2", mf::ParamFlag::SupportsUnusedOutput);
74 builder.single_output<float>("Column 1 Row 3", mf::ParamFlag::SupportsUnusedOutput);
75 builder.single_output<float>("Column 1 Row 4", mf::ParamFlag::SupportsUnusedOutput);
76
77 builder.single_output<float>("Column 2 Row 1", mf::ParamFlag::SupportsUnusedOutput);
78 builder.single_output<float>("Column 2 Row 2", mf::ParamFlag::SupportsUnusedOutput);
79 builder.single_output<float>("Column 2 Row 3", mf::ParamFlag::SupportsUnusedOutput);
80 builder.single_output<float>("Column 2 Row 4", mf::ParamFlag::SupportsUnusedOutput);
81
82 builder.single_output<float>("Column 3 Row 1", mf::ParamFlag::SupportsUnusedOutput);
83 builder.single_output<float>("Column 3 Row 2", mf::ParamFlag::SupportsUnusedOutput);
84 builder.single_output<float>("Column 3 Row 3", mf::ParamFlag::SupportsUnusedOutput);
85 builder.single_output<float>("Column 3 Row 4", mf::ParamFlag::SupportsUnusedOutput);
86
87 builder.single_output<float>("Column 4 Row 1", mf::ParamFlag::SupportsUnusedOutput);
88 builder.single_output<float>("Column 4 Row 2", mf::ParamFlag::SupportsUnusedOutput);
89 builder.single_output<float>("Column 4 Row 3", mf::ParamFlag::SupportsUnusedOutput);
90 builder.single_output<float>("Column 4 Row 4", mf::ParamFlag::SupportsUnusedOutput);
91 return signature;
92 }();
93 this->set_signature(&signature);
94 }
95
96 void call(const IndexMask &mask, mf::Params params, mf::Context /*context*/) const override
97 {
98 const VArray<float4x4> matrices = params.readonly_single_input<float4x4>(0, "Matrix");
99
100 MutableSpan<float> column_1_row_1 = params.uninitialized_single_output_if_required<float>(
101 1, "Column 1 Row 1");
102 MutableSpan<float> column_1_row_2 = params.uninitialized_single_output_if_required<float>(
103 2, "Column 1 Row 2");
104 MutableSpan<float> column_1_row_3 = params.uninitialized_single_output_if_required<float>(
105 3, "Column 1 Row 3");
106 MutableSpan<float> column_1_row_4 = params.uninitialized_single_output_if_required<float>(
107 4, "Column 1 Row 4");
108
109 MutableSpan<float> column_2_row_1 = params.uninitialized_single_output_if_required<float>(
110 5, "Column 2 Row 1");
111 MutableSpan<float> column_2_row_2 = params.uninitialized_single_output_if_required<float>(
112 6, "Column 2 Row 2");
113 MutableSpan<float> column_2_row_3 = params.uninitialized_single_output_if_required<float>(
114 7, "Column 2 Row 3");
115 MutableSpan<float> column_2_row_4 = params.uninitialized_single_output_if_required<float>(
116 8, "Column 2 Row 4");
117
118 MutableSpan<float> column_3_row_1 = params.uninitialized_single_output_if_required<float>(
119 9, "Column 3 Row 1");
120 MutableSpan<float> column_3_row_2 = params.uninitialized_single_output_if_required<float>(
121 10, "Column 3 Row 2");
122 MutableSpan<float> column_3_row_3 = params.uninitialized_single_output_if_required<float>(
123 11, "Column 3 Row 3");
124 MutableSpan<float> column_3_row_4 = params.uninitialized_single_output_if_required<float>(
125 12, "Column 3 Row 4");
126
127 MutableSpan<float> column_4_row_1 = params.uninitialized_single_output_if_required<float>(
128 13, "Column 4 Row 1");
129 MutableSpan<float> column_4_row_2 = params.uninitialized_single_output_if_required<float>(
130 14, "Column 4 Row 2");
131 MutableSpan<float> column_4_row_3 = params.uninitialized_single_output_if_required<float>(
132 15, "Column 4 Row 3");
133 MutableSpan<float> column_4_row_4 = params.uninitialized_single_output_if_required<float>(
134 16, "Column 4 Row 4");
135
136 if (const std::optional<float4x4> single = matrices.get_if_single()) {
137 const float4x4 matrix = *single;
138 column_1_row_1.fill(matrix[0][0]);
139 column_1_row_2.fill(matrix[0][1]);
140 column_1_row_3.fill(matrix[0][2]);
141 column_1_row_4.fill(matrix[0][3]);
142
143 column_2_row_1.fill(matrix[1][0]);
144 column_2_row_2.fill(matrix[1][1]);
145 column_2_row_3.fill(matrix[1][2]);
146 column_2_row_4.fill(matrix[1][3]);
147
148 column_3_row_1.fill(matrix[2][0]);
149 column_3_row_2.fill(matrix[2][1]);
150 column_3_row_3.fill(matrix[2][2]);
151 column_3_row_4.fill(matrix[2][3]);
152
153 column_4_row_1.fill(matrix[3][0]);
154 column_4_row_2.fill(matrix[3][1]);
155 column_4_row_3.fill(matrix[3][2]);
156 column_4_row_4.fill(matrix[3][3]);
157 return;
158 }
159
160 const VArraySpan<float4x4> span_matrices(matrices);
161 const Span<float> components = span_matrices.cast<float>();
162
163 copy_with_stride(mask, components, 16, 0, 1, 0, column_1_row_1);
164 copy_with_stride(mask, components, 16, 1, 1, 0, column_1_row_2);
165 copy_with_stride(mask, components, 16, 2, 1, 0, column_1_row_3);
166 copy_with_stride(mask, components, 16, 3, 1, 0, column_1_row_4);
167
168 copy_with_stride(mask, components, 16, 4, 1, 0, column_2_row_1);
169 copy_with_stride(mask, components, 16, 5, 1, 0, column_2_row_2);
170 copy_with_stride(mask, components, 16, 6, 1, 0, column_2_row_3);
171 copy_with_stride(mask, components, 16, 7, 1, 0, column_2_row_4);
172
173 copy_with_stride(mask, components, 16, 8, 1, 0, column_3_row_1);
174 copy_with_stride(mask, components, 16, 9, 1, 0, column_3_row_2);
175 copy_with_stride(mask, components, 16, 10, 1, 0, column_3_row_3);
176 copy_with_stride(mask, components, 16, 11, 1, 0, column_3_row_4);
177
178 copy_with_stride(mask, components, 16, 12, 1, 0, column_4_row_1);
179 copy_with_stride(mask, components, 16, 13, 1, 0, column_4_row_2);
180 copy_with_stride(mask, components, 16, 14, 1, 0, column_4_row_3);
181 copy_with_stride(mask, components, 16, 15, 1, 0, column_4_row_4);
182 }
183};
184
186{
187 const static SeparateMatrixFunction fn;
188 builder.set_matching_fn(fn);
189}
190
192{
193 using namespace value_elem;
194 const MatrixElem matrix_elem = params.get_input_elem<MatrixElem>("Matrix");
195 std::array<std::array<FloatElem, 4>, 4> output_elems;
196
197 output_elems[3][0] = matrix_elem.translation.x;
198 output_elems[3][1] = matrix_elem.translation.y;
199 output_elems[3][2] = matrix_elem.translation.z;
200
201 if (matrix_elem.rotation || matrix_elem.scale) {
202 for (const int col : IndexRange(3)) {
203 for (const int row : IndexRange(3)) {
204 output_elems[col][row] = FloatElem::all();
205 }
206 }
207 }
208
209 if (matrix_elem.any_non_transform) {
210 for (const int col : IndexRange(4)) {
211 output_elems[col][3] = FloatElem::all();
212 }
213 }
214
215 for (const int col : IndexRange(4)) {
216 for (const int row : IndexRange(4)) {
217 const bNodeSocket &socket = params.node.output_socket(col * 4 + row);
218 params.set_output_elem(socket.identifier, output_elems[col][row]);
219 }
220 }
221}
222
224{
225 using namespace value_elem;
226
227 std::array<std::array<FloatElem, 4>, 4> output_elems;
228 for (const int col : IndexRange(4)) {
229 for (const int row : IndexRange(4)) {
230 const bNodeSocket &socket = params.node.output_socket(col * 4 + row);
231 output_elems[col][row] = params.get_output_elem<FloatElem>(socket.identifier);
232 }
233 }
234
235 MatrixElem matrix_elem;
236 matrix_elem.translation.x = output_elems[3][0];
237 matrix_elem.translation.y = output_elems[3][1];
238 matrix_elem.translation.z = output_elems[3][2];
239
240 bool any_inner_3x3 = false;
241 for (const int col : IndexRange(3)) {
242 for (const int row : IndexRange(3)) {
243 any_inner_3x3 |= output_elems[col][row];
244 }
245 }
246
247 if (any_inner_3x3) {
248 matrix_elem.rotation = RotationElem::all();
249 matrix_elem.scale = VectorElem::all();
250 }
251
252 const bool any_non_transform = output_elems[0][3] || output_elems[1][3] || output_elems[2][3] ||
253 output_elems[3][3];
254 if (any_non_transform) {
255 matrix_elem.any_non_transform = FloatElem::all();
256 }
257
258 params.set_input_elem("Matrix", matrix_elem);
259}
260
262{
263 float4x4 matrix;
264 for (const int col : IndexRange(4)) {
265 for (const int row : IndexRange(4)) {
266 const bNodeSocket &socket = params.node.output_socket(col * 4 + row);
267 matrix[col][row] = params.get_output<float>(socket.identifier);
268 }
269 }
270 params.set_input("Matrix", matrix);
271}
272
273static void node_register()
274{
275 static blender::bke::bNodeType ntype;
276 fn_node_type_base(&ntype, "FunctionNodeSeparateMatrix", FN_NODE_SEPARATE_MATRIX);
277 ntype.ui_name = "Separate Matrix";
278 ntype.ui_description = "Split a 4x4 matrix into its individual values";
279 ntype.enum_name_legacy = "SEPARATE_MATRIX";
281 ntype.declare = node_declare;
287}
289
290} // namespace blender::nodes::node_fn_separate_matrix_cc
#define NODE_CLASS_CONVERTER
Definition BKE_node.hh:453
#define FN_NODE_SEPARATE_MATRIX
#define BLI_assert(a)
Definition BLI_assert.h:46
#define NOD_REGISTER_NODE(REGISTER_FUNC)
long long int int64_t
constexpr bool is_empty() const
Definition BLI_span.hh:509
Span< NewT > constexpr cast() const
Definition BLI_span.hh:418
std::optional< T > get_if_single() const
void set_signature(const Signature *signature)
DeclType::Builder & add_output(StringRef name, StringRef identifier="")
void set_matching_fn(const mf::MultiFunction *fn)
void call(const IndexMask &mask, mf::Params params, mf::Context) const override
uint col
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
void node_register_type(bNodeType &ntype)
Definition node.cc:2416
static void node_build_multi_function(NodeMultiFunctionBuilder &builder)
static void node_eval_inverse_elem(value_elem::InverseElemEvalParams &params)
static void node_eval_elem(value_elem::ElemEvalParams &params)
static void node_declare(NodeDeclarationBuilder &b)
static void copy_with_stride(const IndexMask &mask, const Span< float > src, const int64_t src_step, const int64_t src_begin, const int64_t dst_step, const int64_t dst_begin, MutableSpan< float > dst)
static void node_eval_inverse(inverse_eval::InverseEvalParams &params)
MatBase< float, 4, 4 > float4x4
void fn_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
char identifier[64]
Defines a node type.
Definition BKE_node.hh:238
NodeInverseElemEvalFunction eval_inverse_elem
Definition BKE_node.hh:403
NodeInverseEvalFunction eval_inverse
Definition BKE_node.hh:410
std::string ui_description
Definition BKE_node.hh:244
NodeElemEvalFunction eval_elem
Definition BKE_node.hh:397
NodeMultiFunctionBuildFunction build_multi_function
Definition BKE_node.hh:351
const char * enum_name_legacy
Definition BKE_node.hh:247
NodeDeclareFunction declare
Definition BKE_node.hh:362