Geometry Nodes: support working with raw matrix values

These nodes allow working with the raw values that make up a matrix.
This can be used to construct a 4x4 matrix directly, without using the
`Combine Transform` node. This allows building transforms with arbitrary
skew, or projection matrices.

Pull Request: https://projects.blender.org/blender/blender/pulls/121283
This commit is contained in:
Iliya Katueshenock
2024-05-01 21:31:08 +02:00
committed by Jacques Lucke
parent 17cc5d694c
commit 831e91c357
6 changed files with 372 additions and 0 deletions

View File

@@ -612,10 +612,12 @@ class NODE_MT_category_utilities_matrix(Menu):
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "FunctionNodeCombineMatrix")
node_add_menu.add_node_type(layout, "FunctionNodeCombineTransform")
node_add_menu.add_node_type(layout, "FunctionNodeInvertMatrix")
node_add_menu.add_node_type(layout, "FunctionNodeMatrixMultiply")
node_add_menu.add_node_type(layout, "FunctionNodeProjectPoint")
node_add_menu.add_node_type(layout, "FunctionNodeSeparateMatrix")
node_add_menu.add_node_type(layout, "FunctionNodeSeparateTransform")
node_add_menu.add_node_type(layout, "FunctionNodeTransformDirection")
node_add_menu.add_node_type(layout, "FunctionNodeTransformPoint")

View File

@@ -1333,6 +1333,8 @@ void BKE_nodetree_remove_layer_n(bNodeTree *ntree, Scene *scene, int layer_index
#define FN_NODE_TRANSPOSE_MATRIX 1238
#define FN_NODE_PROJECT_POINT 1239
#define FN_NODE_ALIGN_ROTATION_TO_VECTOR 1240
#define FN_NODE_COMBINE_MATRIX 1241
#define FN_NODE_SEPARATE_MATRIX 1242
/** \} */

View File

@@ -268,6 +268,7 @@ DefNode(FunctionNode, FN_NODE_ALIGN_ROTATION_TO_VECTOR, 0, "ALIGN_ROTATION_TO_VE
DefNode(FunctionNode, FN_NODE_AXIS_ANGLE_TO_ROTATION, 0, "AXIS_ANGLE_TO_ROTATION", AxisAngleToRotation, "Axis Angle to Rotation", "")
DefNode(FunctionNode, FN_NODE_BOOLEAN_MATH, 0, "BOOLEAN_MATH", BooleanMath, "Boolean Math", "")
DefNode(FunctionNode, FN_NODE_COMBINE_COLOR, 0, "COMBINE_COLOR", CombineColor, "Combine Color", "")
DefNode(FunctionNode, FN_NODE_COMBINE_MATRIX, 0, "COMBINE_MATRIX", CombineMatrix, "Combine Matrix", "Construct a 4x4 matrix from its individual values")
DefNode(FunctionNode, FN_NODE_QUATERNION_TO_ROTATION, 0, "QUATERNION_TO_ROTATION", QuaternionToRotation, "Quaternion to Rotation", "")
DefNode(FunctionNode, FN_NODE_COMBINE_TRANSFORM, 0, "COMBINE_TRANSFORM", CombineTransform, "Combine Transform", "")
DefNode(FunctionNode, FN_NODE_COMPARE, 0, "COMPARE", Compare, "Compare", "")
@@ -291,6 +292,7 @@ DefNode(FunctionNode, FN_NODE_ROTATE_VECTOR, 0, "ROTATE_VECTOR", RotateVector, "
DefNode(FunctionNode, FN_NODE_ROTATION_TO_AXIS_ANGLE, 0, "ROTATION_TO_AXIS_ANGLE", RotationToAxisAngle, "Rotation to Axis Angle", "")
DefNode(FunctionNode, FN_NODE_ROTATION_TO_EULER, 0, "ROTATION_TO_EULER", RotationToEuler, "Rotation to Euler", "")
DefNode(FunctionNode, FN_NODE_SEPARATE_COLOR, 0, "SEPARATE_COLOR", SeparateColor, "Separate Color", "")
DefNode(FunctionNode, FN_NODE_SEPARATE_MATRIX, 0, "SEPARATE_MATRIX", SeparateMatrix, "Separate Matrix", "Split a 4x4 matrix into its individual values")
DefNode(FunctionNode, FN_NODE_ROTATION_TO_QUATERNION, 0, "ROTATION_TO_QUATERNION", RotationToQuaternion, "Rotation to Quaternion", "")
DefNode(FunctionNode, FN_NODE_SEPARATE_TRANSFORM, 0, "SEPARATE_TRANSFORM", SeparateTransform, "Separate Transform", "")
DefNode(FunctionNode, FN_NODE_SLICE_STRING, 0, "SLICE_STRING", SliceString, "Slice String", "")

View File

@@ -23,6 +23,7 @@ set(SRC
nodes/node_fn_axis_angle_to_rotation.cc
nodes/node_fn_boolean_math.cc
nodes/node_fn_combine_color.cc
nodes/node_fn_combine_matrix.cc
nodes/node_fn_combine_transform.cc
nodes/node_fn_compare.cc
nodes/node_fn_euler_to_rotation.cc
@@ -47,6 +48,7 @@ set(SRC
nodes/node_fn_rotation_to_euler.cc
nodes/node_fn_rotation_to_quaternion.cc
nodes/node_fn_separate_color.cc
nodes/node_fn_separate_matrix.cc
nodes/node_fn_separate_transform.cc
nodes/node_fn_slice_string.cc
nodes/node_fn_string_length.cc

View File

@@ -0,0 +1,163 @@
/* SPDX-FileCopyrightText: 2024 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_math_matrix.hh"
#include "node_function_util.hh"
namespace blender::nodes::node_fn_combine_matrix_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
b.use_custom_socket_order();
b.add_output<decl::Matrix>("Matrix");
PanelDeclarationBuilder &column_a = b.add_panel("Column 1").default_closed(true);
column_a.add_input<decl::Float>("Column 1 Row 1").default_value(1.0f);
column_a.add_input<decl::Float>("Column 1 Row 2");
column_a.add_input<decl::Float>("Column 1 Row 3");
column_a.add_input<decl::Float>("Column 1 Row 4");
PanelDeclarationBuilder &column_b = b.add_panel("Column 2").default_closed(true);
column_b.add_input<decl::Float>("Column 2 Row 1");
column_b.add_input<decl::Float>("Column 2 Row 2").default_value(1.0f);
column_b.add_input<decl::Float>("Column 2 Row 3");
column_b.add_input<decl::Float>("Column 2 Row 4");
PanelDeclarationBuilder &column_c = b.add_panel("Column 3").default_closed(true);
column_c.add_input<decl::Float>("Column 3 Row 1");
column_c.add_input<decl::Float>("Column 3 Row 2");
column_c.add_input<decl::Float>("Column 3 Row 3").default_value(1.0f);
column_c.add_input<decl::Float>("Column 3 Row 4");
PanelDeclarationBuilder &column_d = b.add_panel("Column 4").default_closed(true);
column_d.add_input<decl::Float>("Column 4 Row 1");
column_d.add_input<decl::Float>("Column 4 Row 2");
column_d.add_input<decl::Float>("Column 4 Row 3");
column_d.add_input<decl::Float>("Column 4 Row 4").default_value(1.0f);
}
static void copy_with_stride(const IndexMask &mask,
const VArray<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)
{
BLI_assert(src_begin < src_step);
BLI_assert(dst_begin < dst_step);
BLI_assert(src.size() / src_step == dst.size() / dst_step);
devirtualize_varray(src, [&](const auto src) {
mask.foreach_index_optimized<int>([&](const int64_t index) {
dst[dst_begin + dst_step * index] = src[src_begin + src_step * index];
});
});
}
class CombineMatrixFunction : public mf::MultiFunction {
public:
CombineMatrixFunction()
{
static const mf::Signature signature = []() {
mf::Signature signature;
mf::SignatureBuilder builder{"Combine Matrix", signature};
builder.single_input<float>("Column 1 Row 1");
builder.single_input<float>("Column 1 Row 2");
builder.single_input<float>("Column 1 Row 3");
builder.single_input<float>("Column 1 Row 4");
builder.single_input<float>("Column 2 Row 1");
builder.single_input<float>("Column 2 Row 2");
builder.single_input<float>("Column 2 Row 3");
builder.single_input<float>("Column 2 Row 4");
builder.single_input<float>("Column 3 Row 1");
builder.single_input<float>("Column 3 Row 2");
builder.single_input<float>("Column 3 Row 3");
builder.single_input<float>("Column 3 Row 4");
builder.single_input<float>("Column 4 Row 1");
builder.single_input<float>("Column 4 Row 2");
builder.single_input<float>("Column 4 Row 3");
builder.single_input<float>("Column 4 Row 4");
builder.single_output<float4x4>("Matrix");
return signature;
}();
this->set_signature(&signature);
}
void call(const IndexMask &mask, mf::Params params, mf::Context /*context*/) const override
{
const VArray<float> &column_1_row_1 = params.readonly_single_input<float>(0, "Column 1 Row 1");
const VArray<float> &column_1_row_2 = params.readonly_single_input<float>(1, "Column 1 Row 2");
const VArray<float> &column_1_row_3 = params.readonly_single_input<float>(2, "Column 1 Row 3");
const VArray<float> &column_1_row_4 = params.readonly_single_input<float>(3, "Column 1 Row 4");
const VArray<float> &column_2_row_1 = params.readonly_single_input<float>(4, "Column 2 Row 1");
const VArray<float> &column_2_row_2 = params.readonly_single_input<float>(5, "Column 2 Row 2");
const VArray<float> &column_2_row_3 = params.readonly_single_input<float>(6, "Column 2 Row 3");
const VArray<float> &column_2_row_4 = params.readonly_single_input<float>(7, "Column 2 Row 4");
const VArray<float> &column_3_row_1 = params.readonly_single_input<float>(8, "Column 3 Row 1");
const VArray<float> &column_3_row_2 = params.readonly_single_input<float>(9, "Column 3 Row 2");
const VArray<float> &column_3_row_3 = params.readonly_single_input<float>(10,
"Column 3 Row 3");
const VArray<float> &column_3_row_4 = params.readonly_single_input<float>(11,
"Column 3 Row 4");
const VArray<float> &column_4_row_1 = params.readonly_single_input<float>(12,
"Column 4 Row 1");
const VArray<float> &column_4_row_2 = params.readonly_single_input<float>(13,
"Column 4 Row 2");
const VArray<float> &column_4_row_3 = params.readonly_single_input<float>(14,
"Column 4 Row 3");
const VArray<float> &column_4_row_4 = params.readonly_single_input<float>(15,
"Column 4 Row 4");
MutableSpan<float4x4> matrices = params.uninitialized_single_output<float4x4>(16, "Matrix");
MutableSpan<float> components = matrices.cast<float>();
copy_with_stride(mask, column_1_row_1, 1, 0, 16, 0, components);
copy_with_stride(mask, column_1_row_2, 1, 0, 16, 1, components);
copy_with_stride(mask, column_1_row_3, 1, 0, 16, 2, components);
copy_with_stride(mask, column_1_row_4, 1, 0, 16, 3, components);
copy_with_stride(mask, column_2_row_1, 1, 0, 16, 4, components);
copy_with_stride(mask, column_2_row_2, 1, 0, 16, 5, components);
copy_with_stride(mask, column_2_row_3, 1, 0, 16, 6, components);
copy_with_stride(mask, column_2_row_4, 1, 0, 16, 7, components);
copy_with_stride(mask, column_3_row_1, 1, 0, 16, 8, components);
copy_with_stride(mask, column_3_row_2, 1, 0, 16, 9, components);
copy_with_stride(mask, column_3_row_3, 1, 0, 16, 10, components);
copy_with_stride(mask, column_3_row_4, 1, 0, 16, 11, components);
copy_with_stride(mask, column_4_row_1, 1, 0, 16, 12, components);
copy_with_stride(mask, column_4_row_2, 1, 0, 16, 13, components);
copy_with_stride(mask, column_4_row_3, 1, 0, 16, 14, components);
copy_with_stride(mask, column_4_row_4, 1, 0, 16, 15, components);
}
};
static void node_build_multi_function(NodeMultiFunctionBuilder &builder)
{
const static CombineMatrixFunction fn;
builder.set_matching_fn(fn);
}
static void node_register()
{
static bNodeType ntype;
fn_node_type_base(&ntype, FN_NODE_COMBINE_MATRIX, "Combine Matrix", NODE_CLASS_CONVERTER);
ntype.declare = node_declare;
ntype.build_multi_function = node_build_multi_function;
nodeRegisterType(&ntype);
}
NOD_REGISTER_NODE(node_register)
} // namespace blender::nodes::node_fn_combine_matrix_cc

View File

@@ -0,0 +1,201 @@
/* SPDX-FileCopyrightText: 2024 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_math_matrix.hh"
#include "node_function_util.hh"
namespace blender::nodes::node_fn_separate_matrix_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
b.use_custom_socket_order();
b.allow_any_socket_order();
PanelDeclarationBuilder &column_a = b.add_panel("Column 1").default_closed(true);
column_a.add_output<decl::Float>("Column 1 Row 1");
column_a.add_output<decl::Float>("Column 1 Row 2");
column_a.add_output<decl::Float>("Column 1 Row 3");
column_a.add_output<decl::Float>("Column 1 Row 4");
PanelDeclarationBuilder &column_b = b.add_panel("Column 2").default_closed(true);
column_b.add_output<decl::Float>("Column 2 Row 1");
column_b.add_output<decl::Float>("Column 2 Row 2");
column_b.add_output<decl::Float>("Column 2 Row 3");
column_b.add_output<decl::Float>("Column 2 Row 4");
PanelDeclarationBuilder &column_c = b.add_panel("Column 3").default_closed(true);
column_c.add_output<decl::Float>("Column 3 Row 1");
column_c.add_output<decl::Float>("Column 3 Row 2");
column_c.add_output<decl::Float>("Column 3 Row 3");
column_c.add_output<decl::Float>("Column 3 Row 4");
PanelDeclarationBuilder &column_d = b.add_panel("Column 4").default_closed(true);
column_d.add_output<decl::Float>("Column 4 Row 1");
column_d.add_output<decl::Float>("Column 4 Row 2");
column_d.add_output<decl::Float>("Column 4 Row 3");
column_d.add_output<decl::Float>("Column 4 Row 4");
b.add_input<decl::Matrix>("Matrix");
}
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)
{
if (dst.is_empty()) {
return;
}
BLI_assert(src_begin < src_step);
BLI_assert(dst_begin < dst_step);
BLI_assert(src.size() / src_step == dst.size() / dst_step);
mask.foreach_index_optimized<int>([&](const int64_t index) {
dst[dst_begin + dst_step * index] = src[src_begin + src_step * index];
});
}
class SeparateMatrixFunction : public mf::MultiFunction {
public:
SeparateMatrixFunction()
{
static const mf::Signature signature = []() {
mf::Signature signature;
mf::SignatureBuilder builder{"Separate Matrix", signature};
builder.single_input<float4x4>("Matrix");
builder.single_output<float>("Column 1 Row 1", mf::ParamFlag::SupportsUnusedOutput);
builder.single_output<float>("Column 1 Row 2", mf::ParamFlag::SupportsUnusedOutput);
builder.single_output<float>("Column 1 Row 3", mf::ParamFlag::SupportsUnusedOutput);
builder.single_output<float>("Column 1 Row 4", mf::ParamFlag::SupportsUnusedOutput);
builder.single_output<float>("Column 2 Row 1", mf::ParamFlag::SupportsUnusedOutput);
builder.single_output<float>("Column 2 Row 2", mf::ParamFlag::SupportsUnusedOutput);
builder.single_output<float>("Column 2 Row 3", mf::ParamFlag::SupportsUnusedOutput);
builder.single_output<float>("Column 2 Row 4", mf::ParamFlag::SupportsUnusedOutput);
builder.single_output<float>("Column 3 Row 1", mf::ParamFlag::SupportsUnusedOutput);
builder.single_output<float>("Column 3 Row 2", mf::ParamFlag::SupportsUnusedOutput);
builder.single_output<float>("Column 3 Row 3", mf::ParamFlag::SupportsUnusedOutput);
builder.single_output<float>("Column 3 Row 4", mf::ParamFlag::SupportsUnusedOutput);
builder.single_output<float>("Column 4 Row 1", mf::ParamFlag::SupportsUnusedOutput);
builder.single_output<float>("Column 4 Row 2", mf::ParamFlag::SupportsUnusedOutput);
builder.single_output<float>("Column 4 Row 3", mf::ParamFlag::SupportsUnusedOutput);
builder.single_output<float>("Column 4 Row 4", mf::ParamFlag::SupportsUnusedOutput);
return signature;
}();
this->set_signature(&signature);
}
void call(const IndexMask &mask, mf::Params params, mf::Context /*context*/) const override
{
const VArray<float4x4> matrices = params.readonly_single_input<float4x4>(0, "Matrix");
MutableSpan<float> column_1_row_1 = params.uninitialized_single_output_if_required<float>(
1, "Column 1 Row 1");
MutableSpan<float> column_1_row_2 = params.uninitialized_single_output_if_required<float>(
2, "Column 1 Row 2");
MutableSpan<float> column_1_row_3 = params.uninitialized_single_output_if_required<float>(
3, "Column 1 Row 3");
MutableSpan<float> column_1_row_4 = params.uninitialized_single_output_if_required<float>(
4, "Column 1 Row 4");
MutableSpan<float> column_2_row_1 = params.uninitialized_single_output_if_required<float>(
5, "Column 2 Row 1");
MutableSpan<float> column_2_row_2 = params.uninitialized_single_output_if_required<float>(
6, "Column 2 Row 2");
MutableSpan<float> column_2_row_3 = params.uninitialized_single_output_if_required<float>(
7, "Column 2 Row 3");
MutableSpan<float> column_2_row_4 = params.uninitialized_single_output_if_required<float>(
8, "Column 2 Row 4");
MutableSpan<float> column_3_row_1 = params.uninitialized_single_output_if_required<float>(
9, "Column 3 Row 1");
MutableSpan<float> column_3_row_2 = params.uninitialized_single_output_if_required<float>(
10, "Column 3 Row 2");
MutableSpan<float> column_3_row_3 = params.uninitialized_single_output_if_required<float>(
11, "Column 3 Row 3");
MutableSpan<float> column_3_row_4 = params.uninitialized_single_output_if_required<float>(
12, "Column 3 Row 4");
MutableSpan<float> column_4_row_1 = params.uninitialized_single_output_if_required<float>(
13, "Column 4 Row 1");
MutableSpan<float> column_4_row_2 = params.uninitialized_single_output_if_required<float>(
14, "Column 4 Row 2");
MutableSpan<float> column_4_row_3 = params.uninitialized_single_output_if_required<float>(
15, "Column 4 Row 3");
MutableSpan<float> column_4_row_4 = params.uninitialized_single_output_if_required<float>(
16, "Column 4 Row 4");
if (const std::optional<float4x4> single = matrices.get_if_single()) {
const float4x4 matrix = *single;
column_1_row_1.fill(matrix[0][0]);
column_1_row_2.fill(matrix[0][1]);
column_1_row_3.fill(matrix[0][2]);
column_1_row_4.fill(matrix[0][3]);
column_2_row_1.fill(matrix[1][0]);
column_2_row_2.fill(matrix[1][1]);
column_2_row_3.fill(matrix[1][2]);
column_2_row_4.fill(matrix[1][3]);
column_3_row_1.fill(matrix[2][0]);
column_3_row_2.fill(matrix[2][1]);
column_3_row_3.fill(matrix[2][2]);
column_3_row_4.fill(matrix[2][3]);
column_4_row_1.fill(matrix[3][0]);
column_4_row_2.fill(matrix[3][1]);
column_4_row_3.fill(matrix[3][2]);
column_4_row_4.fill(matrix[3][3]);
return;
}
const VArraySpan<float4x4> span_matrices(matrices);
const Span<float> components = span_matrices.cast<float>();
copy_with_stride(mask, components, 16, 0, 1, 0, column_1_row_1);
copy_with_stride(mask, components, 16, 1, 1, 0, column_1_row_2);
copy_with_stride(mask, components, 16, 2, 1, 0, column_1_row_3);
copy_with_stride(mask, components, 16, 3, 1, 0, column_1_row_4);
copy_with_stride(mask, components, 16, 4, 1, 0, column_2_row_1);
copy_with_stride(mask, components, 16, 5, 1, 0, column_2_row_2);
copy_with_stride(mask, components, 16, 6, 1, 0, column_2_row_3);
copy_with_stride(mask, components, 16, 7, 1, 0, column_2_row_4);
copy_with_stride(mask, components, 16, 8, 1, 0, column_3_row_1);
copy_with_stride(mask, components, 16, 9, 1, 0, column_3_row_2);
copy_with_stride(mask, components, 16, 10, 1, 0, column_3_row_3);
copy_with_stride(mask, components, 16, 11, 1, 0, column_3_row_4);
copy_with_stride(mask, components, 16, 12, 1, 0, column_4_row_1);
copy_with_stride(mask, components, 16, 13, 1, 0, column_4_row_2);
copy_with_stride(mask, components, 16, 14, 1, 0, column_4_row_3);
copy_with_stride(mask, components, 16, 15, 1, 0, column_4_row_4);
}
};
static void node_build_multi_function(NodeMultiFunctionBuilder &builder)
{
const static SeparateMatrixFunction fn;
builder.set_matching_fn(fn);
}
static void node_register()
{
static bNodeType ntype;
fn_node_type_base(&ntype, FN_NODE_SEPARATE_MATRIX, "Separate Matrix", NODE_CLASS_CONVERTER);
ntype.declare = node_declare;
ntype.build_multi_function = node_build_multi_function;
nodeRegisterType(&ntype);
}
NOD_REGISTER_NODE(node_register)
} // namespace blender::nodes::node_fn_separate_matrix_cc