Geometry Nodes: Matrix socket type, attribute type, and initial nodes #116166

Merged
Hans Goudey merged 47 commits from HooglyBoogly/blender:nodes-matrix-socket into main 2024-02-13 18:59:46 +01:00
11 changed files with 188 additions and 132 deletions
Showing only changes of commit 4a0953c4c0 - Show all commits

View File

@ -588,14 +588,13 @@ class NODE_MT_category_utilities_matrix(Menu):
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "FunctionNodeTransformVector")
node_add_menu.add_node_type(layout, "FunctionNodeTransformDirection")
node_add_menu.add_node_type(layout, "FunctionNodeProjectVector")
node_add_menu.add_node_type(layout, "FunctionNodeMatrixMultiply")
node_add_menu.add_node_type(layout, "FunctionNodeLocationToTransform")
node_add_menu.add_node_type(layout, "FunctionNodeRotationToTransform")
node_add_menu.add_node_type(layout, "FunctionNodeScaleToTransform")
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, "FunctionNodeProjectVector")
node_add_menu.add_node_type(layout, "FunctionNodeSeparateTransform")
node_add_menu.add_node_type(layout, "FunctionNodeTransformDirection")
node_add_menu.add_node_type(layout, "FunctionNodeTransformVector")
node_add_menu.add_node_type(layout, "FunctionNodeTransposeMatrix")
node_add_menu.draw_assets_for_catalog(layout, "Utilities/Matrix")

View File

@ -1365,11 +1365,10 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
#define FN_NODE_TRANSFORM_DIRECTION 1233
#define FN_NODE_PROJECT_VECTOR 1234
#define FN_NODE_MATRIX_MULTIPLY 1235
#define FN_NODE_LOCATION_TO_TRANSFORM 1236
#define FN_NODE_ROTATION_TO_TRANSFORM 1237
#define FN_NODE_SCALE_TO_TRANSFORM 1238
#define FN_NODE_INVERT_MATRIX 1239
#define FN_NODE_TRANSPOSE_MATRIX 1240
#define FN_NODE_COMBINE_TRANSFORM 1236
#define FN_NODE_SEPARATE_TRANSFORM 1237
#define FN_NODE_INVERT_MATRIX 1238
#define FN_NODE_TRANSPOSE_MATRIX 1239
/** \} */

View File

@ -799,6 +799,7 @@ void BKE_mesh_eval_delete(Mesh *mesh_eval)
Mesh *BKE_mesh_copy_for_eval(const Mesh *source)
{
BLI_assert(source != nullptr);
return reinterpret_cast<Mesh *>(
BKE_id_copy_ex(nullptr, &source->id, nullptr, LIB_ID_COPY_LOCALIZE));
}

View File

@ -45,8 +45,7 @@ static void add_values_to_text_cache(const GVArray &values,
const T &value = values_typed[i];
char numstr[32];
size_t numstr_len;
size_t numstr_len = 0;
if constexpr (std::is_same_v<T, bool>) {
numstr_len = SNPRINTF_RLEN(numstr, "%s", value ? "True" : "False");
}

View File

@ -266,6 +266,7 @@ DefNode(FunctionNode, FN_NODE_ALIGN_EULER_TO_VECTOR, 0, "ALIGN_EULER_TO_VECTOR",
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_QUATERNION_TO_ROTATION, 0, "QUATERNION_TO_ROTATION", QuaternionToRotation, "Quaternion to Rotation", "")
DefNode(FunctionNode, FN_NODE_COMPARE, 0, "COMPARE", Compare, "Compare", "")
DefNode(FunctionNode, FN_NODE_EULER_TO_ROTATION, 0, "EULER_TO_ROTATION", EulerToRotation, "Euler to Rotation", "")
DefNode(FunctionNode, FN_NODE_FLOAT_TO_INT, def_float_to_int, "FLOAT_TO_INT", FloatToInt, "Float to Integer", "")
@ -277,20 +278,18 @@ DefNode(FunctionNode, FN_NODE_INPUT_STRING, def_fn_input_string, "INPUT_STRING",
DefNode(FunctionNode, FN_NODE_INPUT_VECTOR, def_fn_input_vector, "INPUT_VECTOR", InputVector, "Vector", "")
DefNode(FunctionNode, FN_NODE_INVERT_MATRIX, 0, "INVERT_MATRIX", InvertMatrix, "Invert Matrix", "")
DefNode(FunctionNode, FN_NODE_INVERT_ROTATION, 0, "INVERT_ROTATION", InvertRotation, "Invert Rotation", "")
DefNode(FunctionNode, FN_NODE_LOCATION_TO_TRANSFORM, 0, "LOCATION_TO_TRANSFORM", LocationToTransform, "Location to Transform", "")
DefNode(FunctionNode, FN_NODE_COMBINE_TRANSFORM, 0, "COMBINE_TRANSFORM", CombineTransform, "Combine Transform", "")
DefNode(FunctionNode, FN_NODE_MATRIX_MULTIPLY, 0, "MATRIX_MULTIPLY", MatrixMultiply, "Matrix Multiply", "")
DefNode(FunctionNode, FN_NODE_PROJECT_VECTOR, 0, "PROJECT_VECTOR", ProjectVector, "Project Vector", "")
DefNode(FunctionNode, FN_NODE_QUATERNION_TO_ROTATION, 0, "QUATERNION_TO_ROTATION", QuaternionToRotation, "Quaternion to Rotation", "")
DefNode(FunctionNode, FN_NODE_RANDOM_VALUE, def_fn_random_value, "RANDOM_VALUE", RandomValue, "Random Value", "")
DefNode(FunctionNode, FN_NODE_REPLACE_STRING, 0, "REPLACE_STRING", ReplaceString, "Replace String", "")
DefNode(FunctionNode, FN_NODE_ROTATE_EULER, def_fn_rotate_euler, "ROTATE_EULER", RotateEuler, "Rotate Euler", "")
DefNode(FunctionNode, FN_NODE_ROTATE_VECTOR, 0, "ROTATE_VECTOR", RotateVector, "Rotate Vector", "")
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_ROTATION_TO_QUATERNION, 0, "ROTATION_TO_QUATERNION", RotationToQuaternion, "Rotation to Quaternion", "")
DefNode(FunctionNode, FN_NODE_ROTATION_TO_TRANSFORM, 0, "ROTATION_TO_TRANSFORM", RotationToTransform, "Rotation to Transform", "")
DefNode(FunctionNode, FN_NODE_SCALE_TO_TRANSFORM, 0, "SCALE_TO_TRANSFORM", ScaleToTransform, "Scale to Transform", "")
DefNode(FunctionNode, FN_NODE_SEPARATE_COLOR, 0, "SEPARATE_COLOR", SeparateColor, "Separate Color", "")
DefNode(FunctionNode, FN_NODE_SEPARATE_TRANSFORM, 0, "SEPARATE_TRANSFORM", SeparateTransform, "Separate Transform", "")
DefNode(FunctionNode, FN_NODE_ROTATION_TO_QUATERNION, 0, "ROTATION_TO_QUATERNION", RotationToQuaternion, "Rotation to Quaternion", "")
DefNode(FunctionNode, FN_NODE_SLICE_STRING, 0, "SLICE_STRING", SliceString, "Slice String", "")
DefNode(FunctionNode, FN_NODE_STRING_LENGTH, 0, "STRING_LENGTH", StringLength, "String Length", "")
DefNode(FunctionNode, FN_NODE_TRANSFORM_DIRECTION, 0, "TRANSFORM_DIRECTION", TransformDirection, "Transform Direction", "")
HooglyBoogly marked this conversation as resolved Outdated

Some missing renames.

Some missing renames.

View File

@ -33,7 +33,7 @@ set(SRC
nodes/node_fn_input_vector.cc
nodes/node_fn_invert_matrix.cc
nodes/node_fn_invert_rotation.cc
nodes/node_fn_location_to_transform.cc
nodes/node_fn_combine_transform.cc
nodes/node_fn_matrix_multiply.cc
nodes/node_fn_project_vector.cc
nodes/node_fn_quaternion_to_rotation.cc
@ -44,9 +44,8 @@ set(SRC
nodes/node_fn_rotation_to_axis_angle.cc
nodes/node_fn_rotation_to_euler.cc
nodes/node_fn_rotation_to_quaternion.cc
nodes/node_fn_rotation_to_transform.cc
nodes/node_fn_scale_to_transform.cc
nodes/node_fn_separate_color.cc
nodes/node_fn_separate_transform.cc
nodes/node_fn_slice_string.cc
nodes/node_fn_string_length.cc
nodes/node_fn_transform_direction.cc

View File

@ -0,0 +1,88 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_math_matrix.hh"
#include "BLI_math_rotation.hh"
#include "node_function_util.hh"
namespace blender::nodes::node_fn_combine_transform_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
b.add_input<decl::Vector>("Location").subtype(PROP_TRANSLATION);
b.add_input<decl::Rotation>("Rotation");
b.add_input<decl::Vector>("Scale").default_value(float3(1)).subtype(PROP_XYZ);
b.add_output<decl::Matrix>("Transform");
};
class CombineTransformFunction : public mf::MultiFunction {
public:
CombineTransformFunction()
{
static const mf::Signature signature = []() {
mf::Signature signature;
mf::SignatureBuilder builder{"Combine Transform", signature};
builder.single_input<float3>("Location");
builder.single_input<math::Quaternion>("Rotation");
builder.single_input<float3>("Scale");
builder.single_output<float4x4>("Transform");
return signature;
}();
this->set_signature(&signature);
}
void call(const IndexMask &mask, mf::Params params, mf::Context /*context*/) const override
{
const VArray location = params.readonly_single_input<float3>(0, "Location");
const VArray rotation = params.readonly_single_input<math::Quaternion>(1, "Rotation");
const VArray scale = params.readonly_single_input<float3>(2, "Scale");
MutableSpan transforms = params.uninitialized_single_output<float4x4>(3, "Transform");
const std::optional<float3> location_single = location.get_if_single();
const std::optional<math::Quaternion> rotation_single = rotation.get_if_single();
const std::optional<float3> scale_single = scale.get_if_single();
const bool no_translation = location_single && math::is_zero(*location_single);
const bool no_rotation = rotation_single && math::angle_of(*rotation_single).radian() < 1e-7f;
const bool no_scale = scale_single && math::is_equal(*scale_single, float3(1), 1e-7f);
if (no_rotation && no_scale) {
mask.foreach_index(
[&](const int64_t i) { transforms[i] = math::from_location<float4x4>(location[i]); });
}
else if (no_translation && no_scale) {
mask.foreach_index(
[&](const int64_t i) { transforms[i] = math::from_rotation<float4x4>(rotation[i]); });
}
else if (no_translation && no_rotation) {
mask.foreach_index(
[&](const int64_t i) { transforms[i] = math::from_scale<float4x4>(scale[i]); });
}

mask.foreach_index -> mask.foreach_index_optimized<int>.
const int64_t i -> const int i.
Same in other nodes.

I hope will find time for the benchmarks for the last loop to check if devirtualize_varray and foreach_index_optimized makes sense too, then this will be in main.

`mask.foreach_index` -> `mask.foreach_index_optimized<int>`. `const int64_t i` -> `const int i`. Same in other nodes. I hope will find time for the benchmarks for the last loop to check if `devirtualize_varray` and `foreach_index_optimized` makes sense too, then this will be in main.
Review

Unless I can prove it's faster I don't think this is worth it.

Unless I can prove it's faster I don't think this is worth it.
else {
mask.foreach_index([&](const int64_t i) {
transforms[i] = math::from_loc_rot_scale<float4x4>(location[i], rotation[i], scale[i]);
});
}
}
};
static void node_build_multi_function(NodeMultiFunctionBuilder &builder)
{
static CombineTransformFunction fn;
builder.set_matching_fn(fn);
}
static void node_register()
{
static bNodeType ntype;
fn_node_type_base(&ntype, FN_NODE_COMBINE_TRANSFORM, "Combine Transform", 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_transform_cc

View File

@ -1,37 +0,0 @@
/* SPDX-FileCopyrightText: 2023 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_location_to_transform_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
b.add_input<decl::Vector>("Location").subtype(PROP_TRANSLATION);
b.add_output<decl::Matrix>("Transform");
};
static void node_build_multi_function(NodeMultiFunctionBuilder &builder)
{
static auto fn = mf::build::SI1_SO<float3, float4x4>(
"Location to Transform",
[](float3 location) { return math::from_location<float4x4>(location); });
builder.set_matching_fn(fn);
}
static void node_register()
{
static bNodeType ntype;
fn_node_type_base(
&ntype, FN_NODE_LOCATION_TO_TRANSFORM, "Location to Transform", 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_location_to_transform_cc

View File

@ -1,37 +0,0 @@
/* SPDX-FileCopyrightText: 2023 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_rotation_to_transform_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
b.add_input<decl::Rotation>("Rotation");
b.add_output<decl::Matrix>("Transform");
};
static void node_build_multi_function(NodeMultiFunctionBuilder &builder)
{
static auto fn = mf::build::SI1_SO<math::Quaternion, float4x4>(
"Rotation to Transform",
[](math::Quaternion quat) { return math::from_rotation<float4x4>(quat); });
builder.set_matching_fn(fn);
}
static void node_register()
{
static bNodeType ntype;
fn_node_type_base(
&ntype, FN_NODE_ROTATION_TO_TRANSFORM, "Rotation to Transform", 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_rotation_to_transform_cc

View File

@ -1,36 +0,0 @@
/* SPDX-FileCopyrightText: 2023 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_scale_to_transform_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
b.add_input<decl::Vector>("Scale").subtype(PROP_XYZ);
b.add_output<decl::Matrix>("Transform");
};
static void node_build_multi_function(NodeMultiFunctionBuilder &builder)
{
static auto fn = mf::build::SI1_SO<float3, float4x4>(
"Scale to Transform", [](float3 scale) { return math::from_scale<float4x4>(scale); });
builder.set_matching_fn(fn);
}
static void node_register()
{
static bNodeType ntype;
fn_node_type_base(
&ntype, FN_NODE_SCALE_TO_TRANSFORM, "Scale to Transform", 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_scale_to_transform_cc

View File

@ -0,0 +1,82 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_math_matrix.hh"
#include "BLI_math_rotation.hh"
#include "node_function_util.hh"
namespace blender::nodes::node_fn_separate_transform_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
b.add_input<decl::Matrix>("Transform");
b.add_output<decl::Vector>("Location").subtype(PROP_TRANSLATION);
b.add_output<decl::Rotation>("Rotation");
b.add_output<decl::Vector>("Scale").subtype(PROP_XYZ);
};
class SeparateTransformFunction : public mf::MultiFunction {
public:
SeparateTransformFunction()
{
static const mf::Signature signature = []() {
mf::Signature signature;
mf::SignatureBuilder builder{"Separate Transform", signature};
builder.single_input<float4x4>("Transform");
builder.single_output<float3>("Location", mf::ParamFlag::SupportsUnusedOutput);
builder.single_output<math::Quaternion>("Rotation", mf::ParamFlag::SupportsUnusedOutput);
builder.single_output<float3>("Scale", mf::ParamFlag::SupportsUnusedOutput);
return signature;
}();
this->set_signature(&signature);
}
void call(const IndexMask &mask, mf::Params params, mf::Context /*context*/) const override
{
const VArraySpan transforms = params.readonly_single_input<float4x4>(0, "Transform");
MutableSpan location = params.uninitialized_single_output_if_required<float3>(1, "Location");
MutableSpan rotation = params.uninitialized_single_output_if_required<math::Quaternion>(
2, "Rotation");
MutableSpan scale = params.uninitialized_single_output_if_required<float3>(3, "Scale");
if (!location.is_empty()) {
mask.foreach_index_optimized<int64_t>(
[&](const int64_t i) { location[i] = transforms[i].location(); });
}
if (rotation.is_empty() && !scale.is_empty()) {
mask.foreach_index([&](const int64_t i) { location[i] = math::to_scale(transforms[i]); });
}
else if (!rotation.is_empty() && scale.is_empty()) {
mask.foreach_index(
[&](const int64_t i) { rotation[i] = math::to_quaternion(transforms[i]); });
}
else if (!rotation.is_empty() && !scale.is_empty()) {
mask.foreach_index([&](const int64_t i) {
math::to_rot_scale(float3x3(transforms[i]), rotation[i], scale[i]);
});
}
}
};
static void node_build_multi_function(NodeMultiFunctionBuilder &builder)
{
static SeparateTransformFunction fn;
builder.set_matching_fn(fn);
}
static void node_register()
{
static bNodeType ntype;
fn_node_type_base(
&ntype, FN_NODE_SEPARATE_TRANSFORM, "Separate Transform", 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_transform_cc