Geometry Nodes: Add Rotate Euler Node

This commit introduces the Rotate Euler function node which modifies
an input euler rotation. The node replaces the "Point Rotate" node.

Addresses T91375.

Differential Revision: https://developer.blender.org/D12531
This commit is contained in:
Jarrett Johnson 2021-10-02 20:04:45 -05:00 committed by Hans Goudey
parent 34cf33eb12
commit c5c94e3eae
9 changed files with 200 additions and 1 deletions

View File

@ -624,6 +624,7 @@ geometry_node_categories = [
NodeItem("ShaderNodeClamp"),
NodeItem("ShaderNodeMath"),
NodeItem("FunctionNodeBooleanMath"),
NodeItem("FunctionNodeRotateEuler"),
NodeItem("FunctionNodeFloatCompare"),
NodeItem("FunctionNodeFloatToInt"),
NodeItem("GeometryNodeSwitch"),

View File

@ -1529,6 +1529,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define FN_NODE_STRING_SUBSTRING 1212
#define FN_NODE_INPUT_SPECIAL_CHARACTERS 1213
#define FN_NODE_RANDOM_VALUE 1214
#define FN_NODE_ROTATE_EULER 1215
/** \} */

View File

@ -5824,6 +5824,7 @@ static void registerFunctionNodes()
register_node_type_fn_input_string();
register_node_type_fn_input_vector();
register_node_type_fn_random_value();
register_node_type_fn_rotate_euler();
register_node_type_fn_string_length();
register_node_type_fn_string_substring();
register_node_type_fn_value_to_string();

View File

@ -2032,6 +2032,11 @@ typedef enum GeometryNodeRotatePointsType {
GEO_NODE_POINT_ROTATE_TYPE_AXIS_ANGLE = 1,
} GeometryNodeRotatePointsType;
typedef enum FunctionNodeRotatePointsType {
FN_NODE_ROTATE_EULER_TYPE_EULER = 0,
FN_NODE_ROTATE_EULER_TYPE_AXIS_ANGLE = 1,
} FunctionNodeRotatePointsType;
typedef enum GeometryNodeAttributeVectorRotateMode {
GEO_NODE_VECTOR_ROTATE_TYPE_AXIS = 0,
GEO_NODE_VECTOR_ROTATE_TYPE_AXIS_X = 1,
@ -2052,6 +2057,11 @@ typedef enum GeometryNodeRotatePointsSpace {
GEO_NODE_POINT_ROTATE_SPACE_POINT = 1,
} GeometryNodeRotatePointsSpace;
typedef enum FunctionNodeRotateEulerSpace {
FN_NODE_ROTATE_EULER_SPACE_OBJECT = 0,
FN_NODE_ROTATE_EULER_SPACE_POINT = 1,
} FunctionNodeRotateEulerSpace;
typedef enum GeometryNodeAlignRotationToVectorAxis {
GEO_NODE_ALIGN_ROTATION_TO_VECTOR_AXIS_X = 0,
GEO_NODE_ALIGN_ROTATION_TO_VECTOR_AXIS_Y = 1,

View File

@ -9818,6 +9818,51 @@ static void def_geo_point_rotate(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
static void def_fn_rotate_euler(StructRNA *srna)
{
static const EnumPropertyItem type_items[] = {
{FN_NODE_ROTATE_EULER_TYPE_AXIS_ANGLE,
"AXIS_ANGLE",
ICON_NONE,
"Axis Angle",
"Rotate around an axis by an angle"},
{FN_NODE_ROTATE_EULER_TYPE_EULER,
"EULER",
ICON_NONE,
"Euler",
"Rotate around the X, Y, and Z axes"},
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem space_items[] = {
{FN_NODE_ROTATE_EULER_SPACE_OBJECT,
"OBJECT",
ICON_NONE,
"Object",
"Rotate the input rotation in the local space of the object"},
{FN_NODE_ROTATE_EULER_SPACE_POINT,
"POINT",
ICON_NONE,
"Point",
"Rotate the input rotation in its local space"},
{0, NULL, 0, NULL, NULL},
};
PropertyRNA *prop;
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, type_items);
RNA_def_property_ui_text(prop, "Type", "Method used to describe the rotation");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
prop = RNA_def_property(srna, "space", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom2");
RNA_def_property_enum_items(prop, space_items);
RNA_def_property_ui_text(prop, "Space", "Base orientation of the points");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
static void def_geo_align_rotation_to_vector(StructRNA *srna)
{
static const EnumPropertyItem axis_items[] = {

View File

@ -142,6 +142,7 @@ set(SRC
function/nodes/node_fn_input_string.cc
function/nodes/node_fn_input_vector.cc
function/nodes/node_fn_random_value.cc
function/nodes/node_fn_rotate_euler.cc
function/nodes/node_fn_string_length.cc
function/nodes/node_fn_string_substring.cc
function/nodes/node_fn_value_to_string.cc

View File

@ -29,6 +29,7 @@ void register_node_type_fn_input_special_characters(void);
void register_node_type_fn_input_string(void);
void register_node_type_fn_input_vector(void);
void register_node_type_fn_random_value(void);
void register_node_type_fn_rotate_euler(void);
void register_node_type_fn_string_length(void);
void register_node_type_fn_string_substring(void);
void register_node_type_fn_value_to_string(void);

View File

@ -272,9 +272,10 @@ DefNode(FunctionNode, FN_NODE_INPUT_SPECIAL_CHARACTERS, 0, "INPUT_SPECIAL_CHARAC
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_RANDOM_VALUE, def_fn_random_value, "RANDOM_VALUE", RandomValue, "Random Value", "")
DefNode(FunctionNode, FN_NODE_VALUE_TO_STRING, 0, "VALUE_TO_STRING", ValueToString, "Value to String", "")
DefNode(FunctionNode, FN_NODE_ROTATE_EULER, def_fn_rotate_euler, "ROTATE_EULER", RotateEuler, "Rotate Euler", "")
DefNode(FunctionNode, FN_NODE_STRING_LENGTH, 0, "STRING_LENGTH", StringLength, "String Length", "")
DefNode(FunctionNode, FN_NODE_STRING_SUBSTRING, 0, "STRING_SUBSTRING", StringSubstring, "String Substring", "")
DefNode(FunctionNode, FN_NODE_VALUE_TO_STRING, 0, "VALUE_TO_STRING", ValueToString, "Value to String", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_ALIGN_ROTATION_TO_VECTOR, def_geo_align_rotation_to_vector, "LEGACY_ALIGN_ROTATION_TO_VECTOR", LegacyAlignRotationToVector, "Align Rotation to Vector", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_CLAMP, def_geo_attribute_clamp, "LEGACY_ATTRIBUTE_CLAMP", LegacyAttributeClamp, "Attribute Clamp", "")

View File

@ -0,0 +1,138 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "RNA_enum_types.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "node_function_util.hh"
namespace blender::nodes {
static void fn_node_rotate_euler_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
b.add_input<decl::Vector>("Rotation").subtype(PROP_EULER).hide_value();
b.add_input<decl::Vector>("Rotate By").subtype(PROP_EULER);
b.add_input<decl::Vector>("Axis").default_value({0.0, 0.0, 1.0}).subtype(PROP_XYZ);
b.add_input<decl::Float>("Angle").subtype(PROP_ANGLE);
b.add_output<decl::Vector>("Rotation");
};
static void fn_node_rotate_euler_update(bNodeTree *UNUSED(ntree), bNode *node)
{
bNodeSocket *rotate_by_socket = static_cast<bNodeSocket *>(BLI_findlink(&node->inputs, 1));
bNodeSocket *axis_socket = static_cast<bNodeSocket *>(BLI_findlink(&node->inputs, 2));
bNodeSocket *angle_socket = static_cast<bNodeSocket *>(BLI_findlink(&node->inputs, 3));
nodeSetSocketAvailability(rotate_by_socket,
ELEM(node->custom1, FN_NODE_ROTATE_EULER_TYPE_EULER));
nodeSetSocketAvailability(axis_socket,
ELEM(node->custom1, FN_NODE_ROTATE_EULER_TYPE_AXIS_ANGLE));
nodeSetSocketAvailability(angle_socket,
ELEM(node->custom1, FN_NODE_ROTATE_EULER_TYPE_AXIS_ANGLE));
}
static void fn_node_rotate_euler_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "type", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
uiItemR(layout, ptr, "space", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
static const fn::MultiFunction *get_multi_function(bNode &bnode)
{
static fn::CustomMF_SI_SI_SO<float3, float3, float3> obj_euler_rot{
"Rotate Euler by Euler/Object", [](const float3 &input, const float3 &rotation) {
float input_mat[3][3];
eul_to_mat3(input_mat, input);
float rot_mat[3][3];
eul_to_mat3(rot_mat, rotation);
float mat_res[3][3];
mul_m3_m3m3(mat_res, rot_mat, input_mat);
float3 result;
mat3_to_eul(result, mat_res);
return result;
}};
static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> obj_AA_rot{
"Rotate Euler by AxisAngle/Object",
[](const float3 &input, const float3 &axis, float angle) {
float input_mat[3][3];
eul_to_mat3(input_mat, input);
float rot_mat[3][3];
axis_angle_to_mat3(rot_mat, axis, angle);
float mat_res[3][3];
mul_m3_m3m3(mat_res, rot_mat, input_mat);
float3 result;
mat3_to_eul(result, mat_res);
return result;
}};
static fn::CustomMF_SI_SI_SO<float3, float3, float3> point_euler_rot{
"Rotate Euler by Euler/Point", [](const float3 &input, const float3 &rotation) {
float input_mat[3][3];
eul_to_mat3(input_mat, input);
float rot_mat[3][3];
eul_to_mat3(rot_mat, rotation);
float mat_res[3][3];
mul_m3_m3m3(mat_res, input_mat, rot_mat);
float3 result;
mat3_to_eul(result, mat_res);
return result;
}};
static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> point_AA_rot{
"Rotate Euler by AxisAngle/Point", [](const float3 &input, const float3 &axis, float angle) {
float input_mat[3][3];
eul_to_mat3(input_mat, input);
float rot_mat[3][3];
axis_angle_to_mat3(rot_mat, axis, angle);
float mat_res[3][3];
mul_m3_m3m3(mat_res, input_mat, rot_mat);
float3 result;
mat3_to_eul(result, mat_res);
return result;
}};
short type = bnode.custom1;
short space = bnode.custom2;
if (type == FN_NODE_ROTATE_EULER_TYPE_AXIS_ANGLE) {
return space == FN_NODE_ROTATE_EULER_SPACE_OBJECT ? &obj_AA_rot : &point_AA_rot;
}
if (type == FN_NODE_ROTATE_EULER_TYPE_EULER) {
return space == FN_NODE_ROTATE_EULER_SPACE_OBJECT ? &obj_euler_rot : &point_euler_rot;
}
BLI_assert_unreachable();
return nullptr;
}
static void fn_node_rotate_euler_build_multi_function(NodeMultiFunctionBuilder &builder)
{
const fn::MultiFunction *fn = get_multi_function(builder.node());
builder.set_matching_fn(fn);
}
} // namespace blender::nodes
void register_node_type_fn_rotate_euler()
{
static bNodeType ntype;
fn_node_type_base(&ntype, FN_NODE_ROTATE_EULER, "Rotate Euler", NODE_CLASS_CONVERTER, 0);
ntype.declare = blender::nodes::fn_node_rotate_euler_declare;
ntype.draw_buttons = blender::nodes::fn_node_rotate_euler_layout;
node_type_update(&ntype, blender::nodes::fn_node_rotate_euler_update);
ntype.build_multi_function = blender::nodes::fn_node_rotate_euler_build_multi_function;
nodeRegisterType(&ntype);
}