diff --git a/scripts/startup/bl_ui/node_add_menu_geometry.py b/scripts/startup/bl_ui/node_add_menu_geometry.py index 26589f94428..5fbbae6fe45 100644 --- a/scripts/startup/bl_ui/node_add_menu_geometry.py +++ b/scripts/startup/bl_ui/node_add_menu_geometry.py @@ -564,7 +564,15 @@ class NODE_MT_category_GEO_UTILITIES_ROTATION(Menu): def draw(self, _context): layout = self.layout node_add_menu.add_node_type(layout, "FunctionNodeAlignEulerToVector") + node_add_menu.add_node_type(layout, "FunctionNodeAxisAngleToRotation") + node_add_menu.add_node_type(layout, "FunctionNodeEulerToRotation") + node_add_menu.add_node_type(layout, "FunctionNodeInvertRotation") node_add_menu.add_node_type(layout, "FunctionNodeRotateEuler") + node_add_menu.add_node_type(layout, "FunctionNodeRotateVector") + node_add_menu.add_node_type(layout, "FunctionNodeRotationToAxisAngle") + node_add_menu.add_node_type(layout, "FunctionNodeRotationToEuler") + node_add_menu.add_node_type(layout, "FunctionNodeRotationToQuaternion") + node_add_menu.add_node_type(layout, "FunctionNodeQuaternionToRotation") node_add_menu.draw_assets_for_catalog(layout, self.bl_label) diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index a93fb9a75cf..da7f9727ebd 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -1348,6 +1348,15 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i #define FN_NODE_INPUT_INT 1220 #define FN_NODE_SEPARATE_COLOR 1221 #define FN_NODE_COMBINE_COLOR 1222 +#define FN_NODE_AXIS_ANGLE_TO_ROTATION 1223 +#define FN_NODE_EULER_TO_ROTATION 1224 +#define FN_NODE_QUATERNION_TO_ROTATION 1225 +#define FN_NODE_ROTATION_TO_AXIS_ANGLE 1226 +#define FN_NODE_ROTATION_TO_EULER 1227 +#define FN_NODE_ROTATION_TO_QUATERNION 1228 +#define FN_NODE_ROTATE_VECTOR 1229 +#define FN_NODE_ROTATE_ROTATION 1230 +#define FN_NODE_INVERT_ROTATION 1231 /** \} */ diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 4aea7f70f14..b741233b075 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -264,9 +264,12 @@ DefNode(TextureNode, TEX_NODE_PROC+TEX_STUCCI, 0, "TEX_ST DefNode(TextureNode, TEX_NODE_PROC+TEX_DISTNOISE, 0, "TEX_DISTNOISE", TexDistNoise, "Distorted Noise", "" ) DefNode(FunctionNode, FN_NODE_ALIGN_EULER_TO_VECTOR, 0, "ALIGN_EULER_TO_VECTOR", AlignEulerToVector, "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", "") DefNode(FunctionNode, FN_NODE_INPUT_BOOL, def_fn_input_bool, "INPUT_BOOL", InputBool, "Boolean", "") DefNode(FunctionNode, FN_NODE_INPUT_COLOR, def_fn_input_color, "INPUT_COLOR", InputColor, "Color", "") @@ -274,10 +277,15 @@ DefNode(FunctionNode, FN_NODE_INPUT_INT, def_fn_input_int, "INPUT_INT", InputInt DefNode(FunctionNode, FN_NODE_INPUT_SPECIAL_CHARACTERS, 0, "INPUT_SPECIAL_CHARACTERS", InputSpecialCharacters, "Special Characters", "") DefNode(FunctionNode, FN_NODE_INPUT_STRING, def_fn_input_string, "INPUT_STRING", InputString, "String", "") DefNode(FunctionNode, FN_NODE_INPUT_VECTOR, def_fn_input_vector, "INPUT_VECTOR", InputVector, "Vector", "") +DefNode(FunctionNode, FN_NODE_INVERT_ROTATION, 0, "INVERT_ROTATION", InvertRotation, "Invert 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_SEPARATE_COLOR, 0, "SEPARATE_COLOR", SeparateColor, "Separate Color", "") +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_VALUE_TO_STRING, 0, "VALUE_TO_STRING", ValueToString, "Value to String", "") diff --git a/source/blender/nodes/function/CMakeLists.txt b/source/blender/nodes/function/CMakeLists.txt index a7ec4c7dacf..4de72835da4 100644 --- a/source/blender/nodes/function/CMakeLists.txt +++ b/source/blender/nodes/function/CMakeLists.txt @@ -19,9 +19,11 @@ set(INC_SYS set(SRC nodes/node_fn_align_euler_to_vector.cc + nodes/node_fn_axis_angle_to_rotation.cc nodes/node_fn_boolean_math.cc nodes/node_fn_combine_color.cc nodes/node_fn_compare.cc + nodes/node_fn_euler_to_rotation.cc nodes/node_fn_float_to_int.cc nodes/node_fn_input_bool.cc nodes/node_fn_input_color.cc @@ -29,9 +31,15 @@ set(SRC nodes/node_fn_input_special_characters.cc nodes/node_fn_input_string.cc nodes/node_fn_input_vector.cc + nodes/node_fn_invert_rotation.cc + nodes/node_fn_quaternion_to_rotation.cc nodes/node_fn_random_value.cc nodes/node_fn_replace_string.cc nodes/node_fn_rotate_euler.cc + nodes/node_fn_rotate_vector.cc + 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_separate_color.cc nodes/node_fn_slice_string.cc nodes/node_fn_string_length.cc diff --git a/source/blender/nodes/function/nodes/node_fn_axis_angle_to_rotation.cc b/source/blender/nodes/function/nodes/node_fn_axis_angle_to_rotation.cc new file mode 100644 index 00000000000..ad7f6e71a14 --- /dev/null +++ b/source/blender/nodes/function/nodes/node_fn_axis_angle_to_rotation.cc @@ -0,0 +1,45 @@ +/* SPDX-FileCopyrightText: 2023 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BLI_math_axis_angle.hh" +#include "BLI_math_quaternion.hh" + +#include "node_function_util.hh" + +namespace blender::nodes::node_fn_axis_angle_to_rotation_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.is_function_node(); + b.add_input("Axis").default_value({0.0f, 0.0f, 1.0f}); + b.add_input("Angle").subtype(PROP_ANGLE); + b.add_output("Rotation"); +}; + +static void node_build_multi_function(NodeMultiFunctionBuilder &builder) +{ + static auto fn = mf::build::SI2_SO( + "Axis Angle to Quaternion", [](float3 axis, float angle) { + if (UNLIKELY(math::is_zero(axis))) { + return math::Quaternion::identity(); + } + const float3 axis_normalized = math::normalize(axis); + const math::AxisAngle axis_angle = math::AxisAngle(axis_normalized, angle); + return math::to_quaternion(axis_angle); + }); + builder.set_matching_fn(fn); +} + +static void node_register() +{ + static bNodeType ntype; + fn_node_type_base( + &ntype, FN_NODE_AXIS_ANGLE_TO_ROTATION, "Axis Angle to Rotation", 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_axis_angle_to_rotation_cc \ No newline at end of file diff --git a/source/blender/nodes/function/nodes/node_fn_euler_to_rotation.cc b/source/blender/nodes/function/nodes/node_fn_euler_to_rotation.cc new file mode 100644 index 00000000000..3dfc25ee667 --- /dev/null +++ b/source/blender/nodes/function/nodes/node_fn_euler_to_rotation.cc @@ -0,0 +1,36 @@ +/* SPDX-FileCopyrightText: 2023 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BLI_math_euler.hh" + +#include "node_function_util.hh" + +namespace blender::nodes::node_fn_euler_to_rotation_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.is_function_node(); + b.add_input("Euler").subtype(PROP_EULER); + b.add_output("Rotation"); +}; + +static void node_build_multi_function(NodeMultiFunctionBuilder &builder) +{ + static auto fn = mf::build::SI1_SO( + "Euler XYZ to Quaternion", + [](float3 euler) { return math::to_quaternion(math::EulerXYZ(euler)); }); + builder.set_matching_fn(fn); +} + +static void node_register() +{ + static bNodeType ntype; + fn_node_type_base(&ntype, FN_NODE_EULER_TO_ROTATION, "Euler to Rotation", 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_euler_to_rotation_cc \ No newline at end of file diff --git a/source/blender/nodes/function/nodes/node_fn_invert_rotation.cc b/source/blender/nodes/function/nodes/node_fn_invert_rotation.cc new file mode 100644 index 00000000000..e7db12744a4 --- /dev/null +++ b/source/blender/nodes/function/nodes/node_fn_invert_rotation.cc @@ -0,0 +1,35 @@ +/* SPDX-FileCopyrightText: 2023 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BLI_math_quaternion.hh" + +#include "node_function_util.hh" + +namespace blender::nodes::node_fn_invert_rotation_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.is_function_node(); + b.add_input("Rotation"); + b.add_output("Rotation"); +}; + +static void node_build_multi_function(NodeMultiFunctionBuilder &builder) +{ + static auto fn = mf::build::SI1_SO( + "Invert Quaternion", [](math::Quaternion quat) { return math::invert(quat); }); + builder.set_matching_fn(fn); +} + +static void node_register() +{ + static bNodeType ntype; + fn_node_type_base(&ntype, FN_NODE_INVERT_ROTATION, "Invert Rotation", 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_invert_rotation_cc \ No newline at end of file diff --git a/source/blender/nodes/function/nodes/node_fn_quaternion_to_rotation.cc b/source/blender/nodes/function/nodes/node_fn_quaternion_to_rotation.cc new file mode 100644 index 00000000000..3e49bea0951 --- /dev/null +++ b/source/blender/nodes/function/nodes/node_fn_quaternion_to_rotation.cc @@ -0,0 +1,42 @@ +/* SPDX-FileCopyrightText: 2023 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BLI_math_quaternion.hh" + +#include "node_function_util.hh" + +namespace blender::nodes::node_fn_quaternion_to_rotation_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.is_function_node(); + b.add_input("W").default_value(1.0f); + b.add_input("X").default_value(0.0f); + b.add_input("Y").default_value(0.0f); + b.add_input("Z").default_value(0.0f); + b.add_output("Rotation"); +}; + +static void node_build_multi_function(NodeMultiFunctionBuilder &builder) +{ + static auto fn = mf::build::SI4_SO( + "Quaternion to Rotation", [](float w, float x, float y, float z) { + math::Quaternion combined(w, x, y, z); + return math::normalize(combined); + }); + builder.set_matching_fn(fn); +} + +static void node_register() +{ + static bNodeType ntype; + fn_node_type_base( + &ntype, FN_NODE_QUATERNION_TO_ROTATION, "Quaternion to Rotation", 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_quaternion_to_rotation_cc \ No newline at end of file diff --git a/source/blender/nodes/function/nodes/node_fn_rotate_vector.cc b/source/blender/nodes/function/nodes/node_fn_rotate_vector.cc new file mode 100644 index 00000000000..ed9fbb6223a --- /dev/null +++ b/source/blender/nodes/function/nodes/node_fn_rotate_vector.cc @@ -0,0 +1,37 @@ +/* SPDX-FileCopyrightText: 2023 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BLI_math_quaternion.hh" + +#include "node_function_util.hh" + +namespace blender::nodes::node_fn_rotate_vector_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.is_function_node(); + b.add_input("Vector"); + b.add_input("Rotation"); + b.add_output("Vector"); +}; + +static void node_build_multi_function(NodeMultiFunctionBuilder &builder) +{ + static auto fn = mf::build::SI2_SO( + "Rotate Vector", + [](float3 vector, math::Quaternion quat) { return math::transform_point(quat, vector); }); + builder.set_matching_fn(fn); +} + +static void node_register() +{ + static bNodeType ntype; + fn_node_type_base(&ntype, FN_NODE_ROTATE_VECTOR, "Rotate Vector", 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_rotate_vector_cc \ No newline at end of file diff --git a/source/blender/nodes/function/nodes/node_fn_rotation_to_axis_angle.cc b/source/blender/nodes/function/nodes/node_fn_rotation_to_axis_angle.cc new file mode 100644 index 00000000000..2841be2fdda --- /dev/null +++ b/source/blender/nodes/function/nodes/node_fn_rotation_to_axis_angle.cc @@ -0,0 +1,63 @@ +/* SPDX-FileCopyrightText: 2023 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BLI_math_axis_angle.hh" +#include "BLI_math_quaternion.hh" + +#include "node_function_util.hh" + +namespace blender::nodes::node_fn_rotation_to_axis_angle_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.is_function_node(); + b.add_input("Rotation"); + b.add_output("Axis"); + b.add_output("Angle").subtype(PROP_ANGLE); +}; + +class QuaterniontoAxisAngleFunction : public mf::MultiFunction { + public: + QuaterniontoAxisAngleFunction() + { + static mf::Signature signature_; + mf::SignatureBuilder builder{"Quaternion to Axis Angle", signature_}; + builder.single_input("Quaternion"); + builder.single_output("Axis"); + builder.single_output("Angle"); + this->set_signature(&signature_); + } + + void call(const IndexMask &mask, mf::Params params, mf::Context /*context*/) const override + { + const VArraySpan quaternions = + params.readonly_single_input(0, "Quaternion"); + MutableSpan axes = params.uninitialized_single_output(1, "Axis"); + MutableSpan angles = params.uninitialized_single_output(2, "Angle"); + mask.foreach_index([&](const int64_t i) { + const math::AxisAngle axis_angle = math::to_axis_angle(quaternions[i]); + axes[i] = axis_angle.axis(); + angles[i] = axis_angle.angle().radian(); + }); + } +}; + +static void node_build_multi_function(NodeMultiFunctionBuilder &builder) +{ + static QuaterniontoAxisAngleFunction fn; + builder.set_matching_fn(fn); +} + +static void node_register() +{ + static bNodeType ntype; + fn_node_type_base( + &ntype, FN_NODE_ROTATION_TO_AXIS_ANGLE, "Rotation to Axis Angle", 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_axis_angle_cc \ No newline at end of file diff --git a/source/blender/nodes/function/nodes/node_fn_rotation_to_euler.cc b/source/blender/nodes/function/nodes/node_fn_rotation_to_euler.cc new file mode 100644 index 00000000000..eeb4bb5a286 --- /dev/null +++ b/source/blender/nodes/function/nodes/node_fn_rotation_to_euler.cc @@ -0,0 +1,35 @@ +/* SPDX-FileCopyrightText: 2023 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BLI_math_euler.hh" + +#include "node_function_util.hh" + +namespace blender::nodes::node_fn_rotation_to_euler_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.is_function_node(); + b.add_input("Rotation"); + b.add_output("Euler").subtype(PROP_EULER); +}; + +static void node_build_multi_function(NodeMultiFunctionBuilder &builder) +{ + static auto fn = mf::build::SI1_SO( + "Quaternion to Euler XYZ", [](math::Quaternion quat) { return math::to_euler(quat); }); + builder.set_matching_fn(fn); +} + +static void node_register() +{ + static bNodeType ntype; + fn_node_type_base(&ntype, FN_NODE_ROTATION_TO_EULER, "Rotation to Euler", 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_euler_cc \ No newline at end of file diff --git a/source/blender/nodes/function/nodes/node_fn_rotation_to_quaternion.cc b/source/blender/nodes/function/nodes/node_fn_rotation_to_quaternion.cc new file mode 100644 index 00000000000..657ea8616dc --- /dev/null +++ b/source/blender/nodes/function/nodes/node_fn_rotation_to_quaternion.cc @@ -0,0 +1,70 @@ +/* SPDX-FileCopyrightText: 2023 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BLI_math_quaternion_types.hh" + +#include "node_function_util.hh" + +namespace blender::nodes::node_fn_rotation_to_quaternion_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.is_function_node(); + b.add_input("Rotation"); + b.add_output("W"); + b.add_output("X"); + b.add_output("Y"); + b.add_output("Z"); +}; + +class SeparateQuaternionFunction : public mf::MultiFunction { + public: + SeparateQuaternionFunction() + { + static mf::Signature signature_; + mf::SignatureBuilder builder{"Rotation to Quaternion", signature_}; + builder.single_input("Quaternion"); + builder.single_output("W"); + builder.single_output("X"); + builder.single_output("Y"); + builder.single_output("Z"); + this->set_signature(&signature_); + } + + void call(const IndexMask &mask, mf::Params params, mf::Context /*context*/) const override + { + const VArraySpan quats = params.readonly_single_input( + 0, "Quaternion"); + MutableSpan w = params.uninitialized_single_output(1, "W"); + MutableSpan x = params.uninitialized_single_output(2, "X"); + MutableSpan y = params.uninitialized_single_output(3, "Y"); + MutableSpan z = params.uninitialized_single_output(4, "Z"); + mask.foreach_index([&](const int64_t i) { + const math::Quaternion quat = quats[i]; + w[i] = quat.w; + x[i] = quat.x; + y[i] = quat.y; + z[i] = quat.z; + }); + } +}; + +static void node_build_multi_function(NodeMultiFunctionBuilder &builder) +{ + static SeparateQuaternionFunction fn; + builder.set_matching_fn(fn); +} + +static void node_register() +{ + static bNodeType ntype; + fn_node_type_base( + &ntype, FN_NODE_ROTATION_TO_QUATERNION, "Rotation to Quaternion", 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_quaternion_cc \ No newline at end of file