Matrix operations and sockets for geometry nodes #105408

Closed
Lukas Tönne wants to merge 37 commits from LukasTonne/blender:nodes-matrix-types into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
35 changed files with 1709 additions and 8 deletions

View File

@ -246,6 +246,7 @@ class NODE_MT_geometry_node_GEO_INPUT_CONSTANT(Menu):
node_add_menu.add_node_type(layout, "GeometryNodeInputImage")
node_add_menu.add_node_type(layout, "FunctionNodeInputInt")
node_add_menu.add_node_type(layout, "GeometryNodeInputMaterial")
node_add_menu.add_node_type(layout, "FunctionNodeInputMatrix")
node_add_menu.add_node_type(layout, "FunctionNodeInputString")
node_add_menu.add_node_type(layout, "ShaderNodeValue")
node_add_menu.add_node_type(layout, "FunctionNodeInputVector")
@ -504,6 +505,7 @@ class NODE_MT_category_GEO_UTILITIES(Menu):
layout.separator()
layout.menu("NODE_MT_category_GEO_UTILITIES_FIELD")
layout.menu("NODE_MT_category_GEO_UTILITIES_MATH")
layout.menu("NODE_MT_category_GEO_UTILITIES_MATRIX")
layout.menu("NODE_MT_category_GEO_UTILITIES_ROTATION")
layout.separator()
node_add_menu.add_node_type(layout, "FunctionNodeRandomValue")
@ -551,6 +553,23 @@ class NODE_MT_category_GEO_UTILITIES_MATH(Menu):
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_category_GEO_UTILITIES_MATRIX(Menu):
bl_idname = "NODE_MT_category_GEO_UTILITIES_MATRIX"
bl_label = "Matrix"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "FunctionNodeCombineMatrix")
node_add_menu.add_node_type(layout, "FunctionNodeSeparateMatrix")
node_add_menu.add_node_type(layout, "FunctionNodeDecomposeMatrix")
node_add_menu.add_node_type(layout, "FunctionNodeMatrixMath")
node_add_menu.add_node_type(layout, "FunctionNodeMatrixTransform")
node_add_menu.add_node_type(layout, "FunctionNodeRotateMatrix")
node_add_menu.add_node_type(layout, "FunctionNodeScaleMatrix")
node_add_menu.add_node_type(layout, "FunctionNodeTranslateMatrix")
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_category_GEO_UV(Menu):
bl_idname = "NODE_MT_category_GEO_UV"
bl_label = "UV"
@ -679,6 +698,7 @@ classes = (
NODE_MT_category_GEO_VECTOR,
NODE_MT_category_GEO_UTILITIES_FIELD,
NODE_MT_category_GEO_UTILITIES_MATH,
NODE_MT_category_GEO_UTILITIES_MATRIX,
NODE_MT_category_GEO_UTILITIES_ROTATION,
NODE_MT_category_GEO_GROUP,
NODE_MT_category_GEO_LAYOUT,

View File

@ -1575,6 +1575,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_INPUT_MATRIX 1224
#define FN_NODE_SEPARATE_MATRIX 1225
#define FN_NODE_COMBINE_MATRIX 1226
#define FN_NODE_MATRIX_MATH 1227
#define FN_NODE_DECOMPOSE_MATRIX 1228
#define FN_NODE_ROTATE_MATRIX 1229
#define FN_NODE_SCALE_MATRIX 1230
#define FN_NODE_TRANSLATE_MATRIX 1231
#define FN_NODE_MATRIX_TRANSFORM 1232
/** \} */

View File

@ -94,6 +94,10 @@ static int attribute_data_type_complexity(const eCustomDataType data_type)
return 6;
case CD_PROP_COLOR:
return 7;
case CD_PROP_FLOAT3X3:
return 8;
case CD_PROP_FLOAT4X4:
return 9;
#if 0 /* These attribute types are not supported yet. */
case CD_PROP_STRING:
return 6;

View File

@ -24,6 +24,7 @@
#include "BLI_math.h"
#include "BLI_math_color_blend.h"
#include "BLI_math_vector.hh"
#include "BLI_math_matrix_types.hh"
#include "BLI_mempool.h"
#include "BLI_path_util.h"
#include "BLI_set.hh"
@ -1575,6 +1576,165 @@ static void layerInterp_propbool(const void **sources,
*(bool *)dest = result;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Callbacks for ('float2x2', #CD_PROP_FLOAT2X2)
* \{ */
static void layerInterp_propfloat2x2(const void **sources,
const float *weights,
const float * /*sub_weights*/,
int count,
void *dest)
{
float result[2][2] = {0.0f, 0.0f};
for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
const float (*src)[2] = static_cast<const float (*)[2]>(sources[i]);
madd_v4_v4fl((float *)result, (const float *)src, interp_weight);
}
copy_v4_v4((float *)dest, (float *)result);
}
static void layerMultiply_propfloat2x2(void *data, const float fac)
{
mul_v4_fl((float *)data, fac);
}
static void layerAdd_propfloat2x2(void *data1, const void *data2)
{
add_v4_v4((float *)data1, (const float *)data2);
}
static bool layerValidate_propfloat2x2(void *data, const uint totitems, const bool do_fixes)
{
float *values = static_cast<float *>(data);
bool has_errors = false;
for (int i = 0; i < totitems * 4; i++) {
if (!isfinite(values[i])) {
if (do_fixes) {
values[i] = 0.0f;
}
has_errors = true;
}
}
return has_errors;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Callbacks for ('float3x3', #CD_PROP_FLOAT3X3)
* \{ */
static void layerInterp_propfloat3x3(const void **sources,
const float *weights,
const float * /*sub_weights*/,
int count,
void *dest)
{
using blender::float3x3;
float3x3 result = float3x3::zero();
for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
const float3x3 *src = static_cast<const float3x3 *>(sources[i]);
madd_m3_m3m3fl(result.ptr(), result.ptr(), src->ptr(), interp_weight);
}
*static_cast<float3x3 *>(dest) = result.view();
}
static void layerMultiply_propfloat3x3(void *data, const float fac)
{
using blender::float3x3;
float3x3 *mat = static_cast<float3x3 *>(data);
mul_m3_fl(mat->ptr(), fac);
}
static void layerAdd_propfloat3x3(void *data1, const void *data2)
{
using blender::float3x3;
float3x3 *mat1 = static_cast<float3x3 *>(data1);
const float3x3 *mat2 = static_cast<const float3x3 *>(data2);
add_m3_m3m3(mat1->ptr(), mat1->ptr(), mat2->ptr());
}
static bool layerValidate_propfloat3x3(void *data, const uint totitems, const bool do_fixes)
{
float *values = static_cast<float *>(data);
bool has_errors = false;
for (int i = 0; i < totitems * 9; i++) {
if (!isfinite(values[i])) {
if (do_fixes) {
values[i] = 0.0f;
}
has_errors = true;
}
}
return has_errors;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Callbacks for ('float4x4', #CD_PROP_FLOAT4X4)
* \{ */
static void layerInterp_propfloat4x4(const void **sources,
const float *weights,
const float * /*sub_weights*/,
int count,
void *dest)
{
using blender::float4x4;
float4x4 result;
zero_m4(result.ptr());
for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
const float4x4 *src = static_cast<const float4x4 *>(sources[i]);
madd_m4_m4m4fl(result.ptr(), result.ptr(), src->ptr(), interp_weight);
}
*static_cast<float4x4 *>(dest) = result.view();
}
static void layerMultiply_propfloat4x4(void *data, const float fac)
{
using blender::float4x4;
float4x4 *mat = static_cast<float4x4 *>(data);
mul_m4_fl(mat->ptr(), fac);
}
static void layerAdd_propfloat4x4(void *data1, const void *data2)
{
using blender::float4x4;
float4x4 *mat1 = static_cast<float4x4 *>(data1);
const float4x4 *mat2 = static_cast<const float4x4 *>(data2);
add_m4_m4m4(mat1->ptr(), mat1->ptr(), mat2->ptr());
}
static bool layerValidate_propfloat4x4(void *data, const uint totitems, const bool do_fixes)
{
float *values = static_cast<float *>(data);
bool has_errors = false;
for (int i = 0; i < totitems * 16; i++) {
if (!isfinite(values[i])) {
if (do_fixes) {
values[i] = 0.0f;
}
has_errors = true;
}
}
return has_errors;
}
/** \} */
static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
/* 0: CD_MVERT */ /* DEPRECATED */
{sizeof(MVert), "MVert", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
@ -1966,6 +2126,54 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
nullptr},
/* 51: CD_HAIRLENGTH */
{sizeof(float), "float", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 52: CD_PROP_FLOAT2X2 */
{sizeof(float[2][2]),
"float2x2",
1,
N_("Float2x2"),
nullptr,
nullptr,
layerInterp_propfloat2x2,
nullptr,
nullptr,
nullptr,
layerValidate_propfloat2x2,
nullptr,
layerMultiply_propfloat2x2,
nullptr,
layerAdd_propfloat2x2},
/* 53: CD_PROP_FLOAT3X3 */
{sizeof(float[3][3]),
"float3x3",
1,
N_("Float3x3"),
nullptr,
nullptr,
layerInterp_propfloat3x3,
nullptr,
nullptr,
nullptr,
layerValidate_propfloat3x3,
nullptr,
layerMultiply_propfloat3x3,
nullptr,
layerAdd_propfloat3x3},
/* 54: CD_PROP_FLOAT4X4 */
{sizeof(float[4][4]),
"float4x4",
1,
N_("Float4x4"),
nullptr,
nullptr,
layerInterp_propfloat4x4,
nullptr,
nullptr,
nullptr,
layerValidate_propfloat4x4,
nullptr,
layerMultiply_propfloat4x4,
nullptr,
layerAdd_propfloat4x4},
};
static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
@ -2023,6 +2231,9 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
"CDPropFloat2",
"CDPropBoolean",
"CDHairLength",
"CDPropFloat2x2",
"CDPropFloat3x3",
"CDPropFloat4x4",
};
const CustomData_MeshMasks CD_MASK_BAREMESH = {
@ -5161,6 +5372,10 @@ const blender::CPPType *custom_data_type_to_cpp_type(const eCustomDataType type)
return &CPPType::get<float2>();
case CD_PROP_FLOAT3:
return &CPPType::get<float3>();
case CD_PROP_FLOAT3X3:
return &CPPType::get<float3x3>();
case CD_PROP_FLOAT4X4:
return &CPPType::get<float4x4>();
case CD_PROP_INT32:
return &CPPType::get<int>();
case CD_PROP_COLOR:
@ -5189,6 +5404,12 @@ eCustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type)
if (type.is<float3>()) {
return CD_PROP_FLOAT3;
}
if (type.is<float3x3>()) {
return CD_PROP_FLOAT3X3;
}
if (type.is<float4x4>()) {
return CD_PROP_FLOAT4X4;
}
if (type.is<int>()) {
return CD_PROP_INT32;
}

View File

@ -317,6 +317,7 @@ static void library_foreach_node_socket(LibraryForeachIDData *data, bNodeSocket
case SOCK_CUSTOM:
case SOCK_SHADER:
case SOCK_GEOMETRY:
case SOCK_MATRIX:
break;
}
}
@ -456,6 +457,9 @@ static void write_node_socket_default_value(BlendWriter *writer, bNodeSocket *so
case SOCK_MATERIAL:
BLO_write_struct(writer, bNodeSocketValueMaterial, sock->default_value);
break;
case SOCK_MATRIX:
BLO_write_struct(writer, bNodeSocketValueMatrix, sock->default_value);
break;
case SOCK_CUSTOM:
/* Custom node sockets where default_value is defined uses custom properties for storage. */
break;
@ -881,6 +885,7 @@ static void lib_link_node_socket(BlendLibReader *reader, Library *lib, bNodeSock
case SOCK_CUSTOM:
case SOCK_SHADER:
case SOCK_GEOMETRY:
case SOCK_MATRIX:
break;
}
}
@ -980,6 +985,7 @@ static void expand_node_socket(BlendExpander *expander, bNodeSocket *sock)
case SOCK_CUSTOM:
case SOCK_SHADER:
case SOCK_GEOMETRY:
case SOCK_MATRIX:
break;
}
}
@ -1596,6 +1602,7 @@ static void socket_id_user_increment(bNodeSocket *sock)
case SOCK_CUSTOM:
case SOCK_SHADER:
case SOCK_GEOMETRY:
case SOCK_MATRIX:
break;
}
}
@ -1655,6 +1662,7 @@ static bool socket_id_user_decrement(bNodeSocket *sock)
case SOCK_CUSTOM:
case SOCK_SHADER:
case SOCK_GEOMETRY:
case SOCK_MATRIX:
break;
}
return false;
@ -1799,6 +1807,8 @@ const char *nodeStaticSocketType(const int type, const int subtype)
return "NodeSocketTexture";
case SOCK_MATERIAL:
return "NodeSocketMaterial";
case SOCK_MATRIX:
return "NodeSocketMatrix";
}
return nullptr;
}
@ -1876,6 +1886,8 @@ const char *nodeStaticSocketInterfaceType(const int type, const int subtype)
return "NodeSocketInterfaceTexture";
case SOCK_MATERIAL:
return "NodeSocketInterfaceMaterial";
case SOCK_MATRIX:
return "NodeSocketInterfaceMatrix";
}
return nullptr;
}
@ -1909,6 +1921,8 @@ const char *nodeStaticSocketLabel(const int type, const int /*subtype*/)
return "Texture";
case SOCK_MATERIAL:
return "Material";
case SOCK_MATRIX:
return "Matrix";
}
return nullptr;
}

View File

@ -20,7 +20,7 @@ using nodes::SocketDeclaration;
static bool is_field_socket_type(eNodeSocketDatatype type)
{
return ELEM(type, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_VECTOR, SOCK_RGBA);
return ELEM(type, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_VECTOR, SOCK_RGBA, SOCK_MATRIX);
}
static bool is_field_socket_type(const bNodeSocket &socket)

View File

@ -47,6 +47,7 @@ BLI_CPP_TYPE_MAKE(bool, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(float, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(blender::float2, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(blender::float3, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(blender::float3x3, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(blender::float4x4, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(int8_t, CPPTypeFlags::BasicType)
@ -75,6 +76,7 @@ void register_cpp_types()
BLI_CPP_TYPE_REGISTER(float);
BLI_CPP_TYPE_REGISTER(blender::float2);
BLI_CPP_TYPE_REGISTER(blender::float3);
BLI_CPP_TYPE_REGISTER(blender::float3x3);
BLI_CPP_TYPE_REGISTER(blender::float4x4);
BLI_CPP_TYPE_REGISTER(int8_t);

View File

@ -5823,7 +5823,7 @@ void uiLayoutSetTooltipFunc(uiLayout *layout,
}
}
if (!arg_used) {
if (!arg_used && free_arg) {
/* Free the original copy of arg in case the layout is empty. */
free_arg(arg);
}

View File

@ -1200,6 +1200,7 @@ static const float std_node_socket_colors[][4] = {
{0.96, 0.96, 0.96, 1.0}, /* SOCK_COLLECTION */
{0.62, 0.31, 0.64, 1.0}, /* SOCK_TEXTURE */
{0.92, 0.46, 0.51, 1.0}, /* SOCK_MATERIAL */
{0.01, 0.61, 0.66, 1.0}, /* SOCK_MATRIX */
};
/* common color callbacks for standard types */
@ -1321,6 +1322,15 @@ static void std_node_socket_draw(
}
}
break;
case SOCK_MATRIX:
if (sock->flag & SOCK_COMPACT) {
uiTemplateComponentMenu(layout, ptr, "default_value", text);
}
else {
uiLayout *column = uiLayoutColumn(layout, true);
uiItemR(column, ptr, "default_value", DEFAULT_FLAGS, text, ICON_NONE);
}
break;
case SOCK_RGBA: {
if (text[0] == '\0') {
uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, "", 0);
@ -1451,6 +1461,13 @@ static void std_node_socket_interface_draw(bContext * /*C*/, uiLayout *layout, P
uiItemR(sub, ptr, "max_value", DEFAULT_FLAGS, IFACE_("Max"), ICON_NONE);
break;
}
case SOCK_MATRIX: {
uiItemR(col, ptr, "default_value", DEFAULT_FLAGS, IFACE_("Default"), ICON_NONE);
uiLayout *sub = uiLayoutColumn(col, true);
uiItemR(sub, ptr, "min_value", DEFAULT_FLAGS, IFACE_("Min"), ICON_NONE);
uiItemR(sub, ptr, "max_value", DEFAULT_FLAGS, IFACE_("Max"), ICON_NONE);
break;
}
case SOCK_BOOLEAN:
case SOCK_RGBA:
case SOCK_STRING:

View File

@ -448,6 +448,8 @@ static eCustomDataType socket_type_to_custom_data_type(const eNodeSocketDatatype
return CD_PROP_INT32;
case SOCK_VECTOR:
return CD_PROP_FLOAT3;
case SOCK_MATRIX:
return CD_PROP_FLOAT4X4;
case SOCK_BOOLEAN:
return CD_PROP_BOOL;
case SOCK_RGBA:
@ -2212,6 +2214,7 @@ static int get_main_socket_priority(const bNodeSocket *socket)
case SOCK_COLLECTION:
case SOCK_TEXTURE:
case SOCK_MATERIAL:
case SOCK_MATRIX:
return 6;
}
return -1;

View File

@ -381,6 +381,9 @@ static Vector<NodeLinkItem> ui_node_link_items(NodeLinkArg *arg,
else if (dynamic_cast<const decl::Vector *>(&socket_decl)) {
item.socket_type = SOCK_VECTOR;
}
else if (dynamic_cast<const decl::Matrix *>(&socket_decl)) {
item.socket_type = SOCK_MATRIX;
}
else if (dynamic_cast<const decl::Color *>(&socket_decl)) {
item.socket_type = SOCK_RGBA;
}
@ -861,6 +864,7 @@ static void ui_node_draw_input(
else {
switch (input.type) {
case SOCK_VECTOR:
case SOCK_MATRIX:
uiItemS(sub);
sub = uiLayoutColumn(sub, true);
ATTR_FALLTHROUGH;

View File

@ -12,6 +12,8 @@
FN_FIELD_CPP_TYPE_MAKE(float);
FN_FIELD_CPP_TYPE_MAKE(blender::float2);
FN_FIELD_CPP_TYPE_MAKE(blender::float3);
FN_FIELD_CPP_TYPE_MAKE(blender::float3x3);
FN_FIELD_CPP_TYPE_MAKE(blender::float4x4);
FN_FIELD_CPP_TYPE_MAKE(blender::ColorGeometry4f);
FN_FIELD_CPP_TYPE_MAKE(blender::ColorGeometry4b);
FN_FIELD_CPP_TYPE_MAKE(bool);
@ -26,6 +28,8 @@ void FN_register_cpp_types()
FN_FIELD_CPP_TYPE_REGISTER(float);
FN_FIELD_CPP_TYPE_REGISTER(blender::float2);
FN_FIELD_CPP_TYPE_REGISTER(blender::float3);
FN_FIELD_CPP_TYPE_REGISTER(blender::float3x3);
FN_FIELD_CPP_TYPE_REGISTER(blender::float4x4);
FN_FIELD_CPP_TYPE_REGISTER(blender::ColorGeometry4f);
FN_FIELD_CPP_TYPE_REGISTER(blender::ColorGeometry4b);
FN_FIELD_CPP_TYPE_REGISTER(bool);

View File

@ -76,8 +76,7 @@ typedef struct CustomData {
* MUST be >= CD_NUMTYPES, but we can't use a define here.
* Correct size is ensured in CustomData_update_typemap assert().
*/
int typemap[52];
char _pad[4];
int typemap[55];
/** Number of layers, size of layers array. */
int totlayer, maxlayer;
/** In editmode, total size of all data layers. */
@ -163,7 +162,11 @@ typedef enum eCustomDataType {
CD_HAIRLENGTH = 51,
CD_NUMTYPES = 52,
CD_PROP_FLOAT2X2 = 52,
CD_PROP_FLOAT3X3 = 53,
CD_PROP_FLOAT4X4 = 54,
CD_NUMTYPES = 55,
} eCustomDataType;
/* Bits for eCustomDataMask */
@ -216,6 +219,10 @@ typedef enum eCustomDataType {
#define CD_MASK_HAIRLENGTH (1ULL << CD_HAIRLENGTH)
#define CD_MASK_FLOAT2X2 (1ULL << CD_PROP_FLOAT2X2)
#define CD_MASK_FLOAT3X3 (1ULL << CD_PROP_FLOAT3X3)
#define CD_MASK_FLOAT4X4 (1ULL << CD_PROP_FLOAT4X4)
/** Multi-resolution loop data. */
#define CD_MASK_MULTIRES_GRIDS (CD_MASK_MDISPS | CD_GRID_PAINT_MASK)
@ -226,7 +233,7 @@ typedef enum eCustomDataType {
#define CD_MASK_PROP_ALL \
(CD_MASK_PROP_FLOAT | CD_MASK_PROP_FLOAT2 | CD_MASK_PROP_FLOAT3 | CD_MASK_PROP_INT32 | \
CD_MASK_PROP_COLOR | CD_MASK_PROP_STRING | CD_MASK_PROP_BYTE_COLOR | CD_MASK_PROP_BOOL | \
CD_MASK_PROP_INT8)
CD_MASK_PROP_INT8 | CD_MASK_FLOAT2X2 | CD_MASK_FLOAT3X3 | CD_MASK_FLOAT4X4)
/* All color attributes */
#define CD_MASK_COLOR_ALL (CD_MASK_PROP_COLOR | CD_MASK_PROP_BYTE_COLOR)

View File

@ -235,6 +235,7 @@ typedef enum eNodeSocketDatatype {
SOCK_COLLECTION = 11,
SOCK_TEXTURE = 12,
SOCK_MATERIAL = 13,
SOCK_MATRIX = 14,
} eNodeSocketDatatype;
/** Socket shape. */
@ -714,6 +715,11 @@ typedef struct bNodeSocketValueVector {
float min, max;
} bNodeSocketValueVector;
typedef struct bNodeSocketValueMatrix {
float value[4][4];
float min, max;
} bNodeSocketValueMatrix;
typedef struct bNodeSocketValueRGBA {
float value[4];
} bNodeSocketValueRGBA;
@ -1620,6 +1626,10 @@ typedef struct NodeShaderMix {
char _pad[3];
} NodeShaderMix;
typedef struct NodeInputMatrix {
float matrix[4][4];
} NodeInputMatrix;
/* script node mode */
#define NODE_SCRIPT_INTERNAL 0
#define NODE_SCRIPT_EXTERNAL 1
@ -1895,6 +1905,26 @@ typedef enum NodeVectorMathOperation {
NODE_VECTOR_MATH_MULTIPLY_ADD = 26,
} NodeVectorMathOperation;
typedef enum NodeMatrixMathOperation {
NODE_MATRIX_MATH_ADD = 0,
NODE_MATRIX_MATH_SUBTRACT = 1,
NODE_MATRIX_MATH_SCALAR_MULTIPLY = 2,
NODE_MATRIX_MATH_MULTIPLY = 3,
NODE_MATRIX_MATH_TRANSPOSE = 4,
NODE_MATRIX_MATH_INVERSE = 5,
NODE_MATRIX_MATH_DETERMINANT = 6,
NODE_MATRIX_MATH_TRACE = 7,
//NODE_MATRIX_MATH_IS_SYMMETRIC = 8,
//NODE_MATRIX_MATH_IS_ANTI_SYMMETRIC = 9,
//NODE_MATRIX_MATH_IS_ORTHOGONAL = 10,
} NodeMatrixMathOperation;
typedef enum NodeMatrixTransformVectorMode {
NODE_MATRIX_TRANSFORM_POINT = 0,
NODE_MATRIX_TRANSFORM_DIRECTION = 1,
NODE_MATRIX_TRANSFORM_NORMAL = 2,
} NodeMatrixTransformVectorMode;
typedef enum NodeBooleanMathOperation {
NODE_BOOLEAN_MATH_AND = 0,
NODE_BOOLEAN_MATH_OR = 1,
@ -2397,3 +2427,9 @@ typedef enum NodeCombSepColorMode {
NODE_COMBSEP_COLOR_HSV = 1,
NODE_COMBSEP_COLOR_HSL = 2,
} NodeCombSepColorMode;
typedef enum NodeCombSepMatrixMode {
NODE_COMBSEP_MATRIX_COLUMNS = 0,
NODE_COMBSEP_MATRIX_ROWS = 1,
NODE_COMBSEP_MATRIX_ELEMENTS = 2,
} NodeCombSepMatrixMode;

View File

@ -62,6 +62,7 @@ static const EnumPropertyItem node_socket_data_type_items[] = {
{SOCK_INT, "INT", 0, "Integer", ""},
{SOCK_BOOLEAN, "BOOLEAN", 0, "Boolean", ""},
{SOCK_VECTOR, "VECTOR", 0, "Vector", ""},
{SOCK_MATRIX, "MATRIX", 0, "Matrix", ""},
{SOCK_STRING, "STRING", 0, "String", ""},
{SOCK_RGBA, "RGBA", 0, "Color", ""},
{SOCK_OBJECT, "OBJECT", 0, "Object", ""},
@ -89,6 +90,7 @@ static const EnumPropertyItem node_socket_type_items[] = {
{SOCK_INT, "INT", 0, "Integer", ""},
{SOCK_BOOLEAN, "BOOLEAN", 0, "Boolean", ""},
{SOCK_VECTOR, "VECTOR", 0, "Vector", ""},
{SOCK_MATRIX, "MATRIX", 0, "Matrix", ""},
{SOCK_STRING, "STRING", 0, "String", ""},
{SOCK_RGBA, "RGBA", 0, "RGBA", ""},
{SOCK_SHADER, "SHADER", 0, "Shader", ""},
@ -288,6 +290,31 @@ const EnumPropertyItem rna_enum_node_vec_math_items[] = {
{0, NULL, 0, NULL, NULL},
};
const EnumPropertyItem rna_enum_node_matrix_math_items[] = {
{NODE_MATRIX_MATH_ADD, "ADD", 0, "Add", ""},
{NODE_MATRIX_MATH_SUBTRACT, "SUBTRACT", 0, "Subtract", ""},
{NODE_MATRIX_MATH_SCALAR_MULTIPLY, "SCALAR_MULTIPLY", 0, "Scalar Multiply", ""},
{NODE_MATRIX_MATH_MULTIPLY, "MULTIPLY", 0, "Multiply", ""},
RNA_ENUM_ITEM_SEPR,
{NODE_MATRIX_MATH_TRANSPOSE, "TRANSPOSE", 0, "Transpose", ""},
{NODE_MATRIX_MATH_INVERSE, "INVERSE", 0, "Inverse", ""},
RNA_ENUM_ITEM_SEPR,
{NODE_MATRIX_MATH_DETERMINANT, "DETERMINANT", 0, "Determinant", ""},
{NODE_MATRIX_MATH_TRACE, "TRACE", 0, "Trace", ""},
//RNA_ENUM_ITEM_SEPR,
//{NODE_MATRIX_MATH_IS_SYMMETRIC, "IS_SYMMETRIC", 0, "Is Symmetric", ""},
//{NODE_MATRIX_MATH_IS_ANTI_SYMMETRIC, "IS_ANTI_SYMMETRIC", 0, "Is Anti-Symmetric", ""},
//{NODE_MATRIX_MATH_IS_ORTHOGONAL, "IS_ORTHOGONAL", 0, "Is Orthogonal", ""},
{0, NULL, 0, NULL, NULL},
};
const EnumPropertyItem rna_enum_node_matrix_transform_vector_mode_items[] = {
{NODE_MATRIX_TRANSFORM_POINT, "POINT", 0, "Point", "Apply translation, rotation and scale"},
{NODE_MATRIX_TRANSFORM_DIRECTION, "DIRECTION", 0, "Direction", "Apply only rotation and scale"},
{NODE_MATRIX_TRANSFORM_NORMAL, "NORMAL", 0, "Normal", "Apply inverse transpose of the matrix for surface normals"},
{0, NULL, 0, NULL, NULL},
};
const EnumPropertyItem rna_enum_node_boolean_math_items[] = {
{NODE_BOOLEAN_MATH_AND, "AND", 0, "And", "True when both inputs are true"},
{NODE_BOOLEAN_MATH_OR, "OR", 0, "Or", "True when at least one input is true"},
@ -499,6 +526,13 @@ static const EnumPropertyItem rna_node_combsep_color_items[] = {
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem rna_node_combsep_matrix_items[] = {
{NODE_COMBSEP_MATRIX_COLUMNS, "COLUMNS", ICON_NONE, "Columns", "Use vectors as matrix columns"},
{NODE_COMBSEP_MATRIX_ROWS, "ROWS", ICON_NONE, "Rows", "Use vectors as matrix rows"},
{NODE_COMBSEP_MATRIX_ELEMENTS, "ELEMENTS", ICON_NONE, "Elements", "Use individual matrix elements"},
{0, NULL, 0, NULL, NULL},
};
#ifndef RNA_RUNTIME
static const EnumPropertyItem node_sampler_type_items[] = {
{0, "NEAREST", 0, "Nearest", ""},
@ -3263,6 +3297,22 @@ static void rna_NodeSocketStandard_vector_range(
*softmax = dval->max;
}
static void rna_NodeSocketStandard_matrix_range(
PointerRNA *ptr, float *min, float *max, float *softmin, float *softmax)
{
bNodeSocket *sock = ptr->data;
bNodeSocketValueMatrix *dval = sock->default_value;
if (dval->max < dval->min) {
dval->max = dval->min;
}
*min = -FLT_MAX;
*max = FLT_MAX;
*softmin = dval->min;
*softmax = dval->max;
}
/* using a context update function here, to avoid searching the node if possible */
static void rna_NodeSocketStandard_value_update(struct bContext *C, PointerRNA *ptr)
{
@ -5193,6 +5243,71 @@ static void def_fn_combsep_color(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
static void def_fn_input_matrix(StructRNA *srna)
{
static const float default_elements[] = {
1.0f,
0.0f,
0.0f,
0.0f,
0.0f,
1.0f,
0.0f,
0.0f,
0.0f,
0.0f,
1.0f,
0.0f,
0.0f,
0.0f,
0.0f,
1.0f,
};
PropertyRNA *prop;
RNA_def_struct_sdna_from(srna, "NodeInputMatrix", "storage");
prop = RNA_def_property(srna, "matrix", PROP_FLOAT, PROP_MATRIX);
RNA_def_property_float_sdna(prop, NULL, "matrix");
RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4);
RNA_def_property_float_array_default(prop, default_elements);
RNA_def_property_ui_text(prop, "Matrix", "Input value used for unconnected socket");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
static void def_fn_combsep_matrix(StructRNA *srna)
{
PropertyRNA *prop;
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, rna_node_combsep_matrix_items);
RNA_def_property_ui_text(prop, "Mode", "Mode of matrix composition");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
static void def_fn_matrix_math(StructRNA *srna)
{
PropertyRNA *prop;
prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, rna_enum_node_matrix_math_items);
RNA_def_property_ui_text(prop, "Operation", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
static void def_fn_matrix_transform(StructRNA *srna)
{
PropertyRNA *prop;
prop = RNA_def_property(srna, "vector_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, rna_enum_node_matrix_transform_vector_mode_items);
RNA_def_property_ui_text(prop, "Vector Mode", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
/* -- Shader Nodes ---------------------------------------------------------- */
static void def_sh_output(StructRNA *srna)
@ -11558,6 +11673,74 @@ static void rna_def_node_socket_vector(BlenderRNA *brna,
RNA_def_struct_sdna_from(srna, "bNodeSocket", NULL);
}
static void rna_def_node_socket_matrix(BlenderRNA *brna,
const char *identifier,
const char *interface_idname)
{
StructRNA *srna;
PropertyRNA *prop;
const float value_default[] = {1.0f,
0.0f,
0.0f,
0.0f,
0.0f,
1.0f,
0.0f,
0.0f,
0.0f,
0.0f,
1.0f,
0.0f,
0.0f,
0.0f,
0.0f,
1.0f};
srna = RNA_def_struct(brna, identifier, "NodeSocketStandard");
RNA_def_struct_ui_text(srna, "Matrix Node Socket", "Matrix socket of a node");
RNA_def_struct_sdna(srna, "bNodeSocket");
RNA_def_struct_sdna_from(srna, "bNodeSocketValueMatrix", "default_value");
prop = RNA_def_property(srna, "default_value", PROP_FLOAT, PROP_MATRIX);
RNA_def_property_float_sdna(prop, NULL, "value");
RNA_def_property_float_array_default(prop, value_default);
RNA_def_property_float_funcs(prop, NULL, NULL, "rna_NodeSocketStandard_matrix_range");
RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketStandard_value_update");
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_struct_sdna_from(srna, "bNodeSocket", NULL);
/* socket interface */
srna = RNA_def_struct(brna, interface_idname, "NodeSocketInterfaceStandard");
RNA_def_struct_ui_text(srna, "Matrix Node Socket Interface", "Matrix socket of a node");
RNA_def_struct_sdna(srna, "bNodeSocket");
RNA_def_struct_sdna_from(srna, "bNodeSocketValueMatrix", "default_value");
prop = RNA_def_property(srna, "default_value", PROP_FLOAT, PROP_MATRIX);
RNA_def_property_float_sdna(prop, NULL, "value");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_float_funcs(prop, NULL, NULL, "rna_NodeSocketStandard_matrix_range");
RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update");
prop = RNA_def_property(srna, "min_value", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "min");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop, "Minimum Value", "Minimum value");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update");
prop = RNA_def_property(srna, "max_value", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "max");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop, "Maximum Value", "Maximum value");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update");
RNA_def_struct_sdna_from(srna, "bNodeSocket", NULL);
}
static void rna_def_node_socket_color(BlenderRNA *brna,
const char *identifier,
const char *interface_idname)
@ -11999,6 +12182,8 @@ static void rna_def_node_socket_standard_types(BlenderRNA *brna)
rna_def_node_socket_vector(
brna, "NodeSocketVectorXYZ", "NodeSocketInterfaceVectorXYZ", PROP_XYZ);
rna_def_node_socket_matrix(brna, "NodeSocketMatrix", "NodeSocketInterfaceMatrix");
rna_def_node_socket_color(brna, "NodeSocketColor", "NodeSocketInterfaceColor");
rna_def_node_socket_string(brna, "NodeSocketString", "NodeSocketInterfaceString");

View File

@ -13,6 +13,7 @@
#include "BLI_array.hh"
#include "BLI_listbase.h"
#include "BLI_math_matrix_types.hh"
#include "BLI_math_vector_types.hh"
#include "BLI_multi_value_map.hh"
#include "BLI_set.hh"
@ -100,6 +101,8 @@ using blender::ColorGeometry4f;
using blender::CPPType;
using blender::destruct_ptr;
using blender::float3;
using blender::float3x3;
using blender::float4x4;
using blender::FunctionRef;
using blender::GMutablePointer;
using blender::GMutableSpan;
@ -416,7 +419,7 @@ static const std::string attribute_name_suffix = "_attribute_name";
*/
static bool socket_type_has_attribute_toggle(const bNodeSocket &socket)
{
return ELEM(socket.type, SOCK_FLOAT, SOCK_VECTOR, SOCK_BOOLEAN, SOCK_RGBA, SOCK_INT);
return ELEM(socket.type, SOCK_FLOAT, SOCK_VECTOR, SOCK_BOOLEAN, SOCK_RGBA, SOCK_INT, SOCK_MATRIX);
}
/**
@ -474,6 +477,22 @@ id_property_create_from_socket(const bNodeSocket &socket)
}
return property;
}
case SOCK_MATRIX: {
const bNodeSocketValueMatrix *value = static_cast<const bNodeSocketValueMatrix *>(
socket.default_value);
const Span<float> default_value_span((float *)value->value, 16);
auto property = bke::idprop::create(socket.identifier, default_value_span);
IDPropertyUIDataFloat *ui_data = (IDPropertyUIDataFloat *)IDP_ui_data_ensure(property.get());
ui_data->base.rna_subtype = PROP_MATRIX;
ui_data->min = ui_data->soft_min = double(value->min);
ui_data->max = ui_data->soft_max = double(value->max);
ui_data->default_array = (double *)MEM_mallocN(sizeof(double[16]), "mod_prop_default");
ui_data->default_array_len = 16;
for (const int i : IndexRange(16)) {
ui_data->default_array[i] = double(default_value_span[i]);
}
return property;
}
case SOCK_RGBA: {
const bNodeSocketValueRGBA *value = static_cast<const bNodeSocketValueRGBA *>(
socket.default_value);
@ -551,6 +570,8 @@ static bool id_property_type_matches_socket(const bNodeSocket &socket, const IDP
return property.type == IDP_INT;
case SOCK_VECTOR:
return property.type == IDP_ARRAY && property.subtype == IDP_FLOAT && property.len == 3;
case SOCK_MATRIX:
return property.type == IDP_ARRAY && property.subtype == IDP_FLOAT && property.len == 16;
case SOCK_RGBA:
return property.type == IDP_ARRAY && property.subtype == IDP_FLOAT && property.len == 4;
case SOCK_BOOLEAN:
@ -595,6 +616,12 @@ static void init_socket_cpp_value_from_property(const IDProperty &property,
new (r_value) ValueOrField<float3>(value);
break;
}
case SOCK_MATRIX: {
float4x4 value;
copy_m4_m4(value.ptr(), (const float(*)[4])IDP_Array(&property));
new (r_value) ValueOrField<float4x4>(value);
break;
}
case SOCK_RGBA: {
blender::ColorGeometry4f value;
copy_v4_v4((float *)value, (const float *)IDP_Array(&property));

View File

@ -7,6 +7,7 @@
#include "RNA_types.h"
#include "BLI_color.hh"
#include "BLI_math_matrix_types.hh"
#include "BLI_math_vector_types.hh"
namespace blender::nodes::decl {
@ -93,6 +94,32 @@ class VectorBuilder : public SocketDeclarationBuilder<Vector> {
VectorBuilder &compact();
};
class MatrixBuilder;
class Matrix : public SocketDeclaration {
private:
float4x4 default_value_ = float4x4::identity();
float soft_min_value_ = -FLT_MAX;
float soft_max_value_ = FLT_MAX;
friend MatrixBuilder;
public:
using Builder = MatrixBuilder;
bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
bool matches(const bNodeSocket &socket) const override;
bNodeSocket &update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const override;
bool can_connect(const bNodeSocket &socket) const override;
};
class MatrixBuilder : public SocketDeclarationBuilder<Matrix> {
public:
MatrixBuilder &default_value(const float4x4 &value);
MatrixBuilder &min(float min);
MatrixBuilder &max(float max);
};
class BoolBuilder;
class Bool : public SocketDeclaration {
@ -343,6 +370,30 @@ inline VectorBuilder &VectorBuilder::compact()
/** \} */
/* -------------------------------------------------------------------- */
/** \name #MatrixBuilder Inline Methods
* \{ */
inline MatrixBuilder &MatrixBuilder::default_value(const float4x4 &value)
{
decl_->default_value_ = value;
return *this;
}
inline MatrixBuilder &MatrixBuilder::min(const float min)
{
decl_->soft_min_value_ = min;
return *this;
}
inline MatrixBuilder &MatrixBuilder::max(const float max)
{
decl_->soft_max_value_ = max;
return *this;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name #BoolBuilder Inline Methods
* \{ */

View File

@ -264,20 +264,29 @@ DefNode(TextureNode, TEX_NODE_PROC+TEX_DISTNOISE, 0, "TEX_DI
DefNode(FunctionNode, FN_NODE_ALIGN_EULER_TO_VECTOR, def_fn_align_euler_to_vector, "ALIGN_EULER_TO_VECTOR", AlignEulerToVector, "Align Euler to Vector", "")
DefNode(FunctionNode, FN_NODE_BOOLEAN_MATH, def_boolean_math, "BOOLEAN_MATH", BooleanMath, "Boolean Math", "")
DefNode(FunctionNode, FN_NODE_COMBINE_COLOR, def_fn_combsep_color, "COMBINE_COLOR", CombineColor, "Combine Color", "")
DefNode(FunctionNode, FN_NODE_COMBINE_MATRIX, def_fn_combsep_matrix, "COMBINE_MATRIX", CombineMatrix, "Combine Matrix", "")
DefNode(FunctionNode, FN_NODE_COMPARE, def_compare, "COMPARE", Compare, "Compare", "")
DefNode(FunctionNode, FN_NODE_DECOMPOSE_MATRIX, 0, "DECOMPOSE_MATRIX", DecomposeMatrix, "Decompose Matrix", "")
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", "")
DefNode(FunctionNode, FN_NODE_INPUT_INT, def_fn_input_int, "INPUT_INT", InputInt, "Integer", "")
DefNode(FunctionNode, FN_NODE_INPUT_MATRIX, def_fn_input_matrix, "INPUT_MATRIX", InputMatrix, "Matrix", "")
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_MATRIX_MATH, def_fn_matrix_math, "MATRIX_MATH", MatrixMath, "Matrix Math", "")
DefNode(FunctionNode, FN_NODE_MATRIX_TRANSFORM, def_fn_matrix_transform, "MATRIX_TRANSFORM", MatrixTransform, "Matrix Transform", "")
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_MATRIX, 0, "ROTATE_MATRIX", RotateMatrix, "Rotate Matrix", "")
DefNode(FunctionNode, FN_NODE_SCALE_MATRIX, 0, "SCALE_MATRIX", ScaleMatrix, "Scale Matrix", "")
DefNode(FunctionNode, FN_NODE_SEPARATE_COLOR, def_fn_combsep_color, "SEPARATE_COLOR", SeparateColor, "Separate Color", "")
DefNode(FunctionNode, FN_NODE_SEPARATE_MATRIX, def_fn_combsep_matrix, "SEPARATE_MATRIX", SeparateMatrix, "Separate Matrix", "")
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_TRANSLATE_MATRIX, 0, "TRANSLATE_MATRIX", TranslateMatrix, "Translate Matrix", "")
DefNode(FunctionNode, FN_NODE_VALUE_TO_STRING, 0, "VALUE_TO_STRING", ValueToString, "Value to String", "")
DefNode(GeometryNode, GEO_NODE_ACCUMULATE_FIELD, def_geo_accumulate_field, "ACCUMULATE_FIELD", AccumulateField, "Accumulate Field", "Add the values of an evaluated field together and output the running total for each element")

View File

@ -23,20 +23,29 @@ set(SRC
nodes/node_fn_align_euler_to_vector.cc
nodes/node_fn_boolean_math.cc
nodes/node_fn_combine_color.cc
nodes/node_fn_combine_matrix.cc
nodes/node_fn_compare.cc
nodes/node_fn_decompose_matrix.cc
nodes/node_fn_float_to_int.cc
nodes/node_fn_input_bool.cc
nodes/node_fn_input_color.cc
nodes/node_fn_input_int.cc
nodes/node_fn_input_matrix.cc
nodes/node_fn_input_special_characters.cc
nodes/node_fn_input_string.cc
nodes/node_fn_input_vector.cc
nodes/node_fn_matrix_math.cc
nodes/node_fn_matrix_transform.cc
nodes/node_fn_random_value.cc
nodes/node_fn_replace_string.cc
nodes/node_fn_rotate_euler.cc
nodes/node_fn_rotate_matrix.cc
nodes/node_fn_scale_matrix.cc
nodes/node_fn_separate_color.cc
nodes/node_fn_separate_matrix.cc
nodes/node_fn_slice_string.cc
nodes/node_fn_string_length.cc
nodes/node_fn_translate_matrix.cc
nodes/node_fn_value_to_string.cc
node_function_register.cc

View File

@ -9,19 +9,28 @@ void register_function_nodes()
register_node_type_fn_align_euler_to_vector();
register_node_type_fn_boolean_math();
register_node_type_fn_combine_color();
register_node_type_fn_combine_matrix();
register_node_type_fn_compare();
register_node_type_fn_decompose_matrix();
register_node_type_fn_float_to_int();
register_node_type_fn_input_bool();
register_node_type_fn_input_color();
register_node_type_fn_input_int();
register_node_type_fn_input_matrix();
register_node_type_fn_input_special_characters();
register_node_type_fn_input_string();
register_node_type_fn_input_vector();
register_node_type_fn_matrix_math();
register_node_type_fn_matrix_transform();
register_node_type_fn_random_value();
register_node_type_fn_replace_string();
register_node_type_fn_rotate_euler();
register_node_type_fn_rotate_matrix();
register_node_type_fn_scale_matrix();
register_node_type_fn_separate_color();
register_node_type_fn_separate_matrix();
register_node_type_fn_slice_string();
register_node_type_fn_string_length();
register_node_type_fn_translate_matrix();
register_node_type_fn_value_to_string();
}

View File

@ -5,18 +5,27 @@
void register_node_type_fn_align_euler_to_vector();
void register_node_type_fn_boolean_math();
void register_node_type_fn_combine_color();
void register_node_type_fn_combine_matrix();
void register_node_type_fn_compare();
void register_node_type_fn_decompose_matrix();
void register_node_type_fn_float_to_int();
void register_node_type_fn_input_bool();
void register_node_type_fn_input_color();
void register_node_type_fn_input_int();
void register_node_type_fn_input_matrix();
void register_node_type_fn_input_special_characters();
void register_node_type_fn_input_string();
void register_node_type_fn_input_vector();
void register_node_type_fn_matrix_math();
void register_node_type_fn_matrix_transform();
void register_node_type_fn_random_value();
void register_node_type_fn_replace_string();
void register_node_type_fn_rotate_euler();
void register_node_type_fn_rotate_matrix();
void register_node_type_fn_scale_matrix();
void register_node_type_fn_separate_color();
void register_node_type_fn_separate_matrix();
void register_node_type_fn_slice_string();
void register_node_type_fn_string_length();
void register_node_type_fn_translate_matrix();
void register_node_type_fn_value_to_string();

View File

@ -0,0 +1,181 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_function_util.hh"
#include "UI_interface.h"
#include "UI_resources.h"
namespace blender::nodes::node_fn_combine_matrix_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
b.add_input<decl::Vector>(N_("Vec0")).default_value({1.0f, 0.0f, 0.0f});
b.add_input<decl::Vector>(N_("Vec1")).default_value({0.0f, 1.0f, 0.0f});
b.add_input<decl::Vector>(N_("Vec2")).default_value({0.0f, 0.0f, 1.0f});
b.add_input<decl::Vector>(N_("Vec3")).default_value({0.0f, 0.0f, 0.0f});
b.add_input<decl::Float>(N_("Row 0 Col 0")).default_value(1.0f);
b.add_input<decl::Float>(N_("Row 1 Col 0")).default_value(0.0f);
b.add_input<decl::Float>(N_("Row 2 Col 0")).default_value(0.0f);
b.add_input<decl::Float>(N_("Row 3 Col 0")).default_value(0.0f);
b.add_input<decl::Float>(N_("Row 0 Col 1")).default_value(0.0f);
b.add_input<decl::Float>(N_("Row 1 Col 1")).default_value(1.0f);
b.add_input<decl::Float>(N_("Row 2 Col 1")).default_value(0.0f);
b.add_input<decl::Float>(N_("Row 3 Col 1")).default_value(0.0f);
b.add_input<decl::Float>(N_("Row 0 Col 2")).default_value(0.0f);
b.add_input<decl::Float>(N_("Row 1 Col 2")).default_value(0.0f);
b.add_input<decl::Float>(N_("Row 2 Col 2")).default_value(1.0f);
b.add_input<decl::Float>(N_("Row 3 Col 2")).default_value(0.0f);
b.add_input<decl::Float>(N_("Row 0 Col 3")).default_value(0.0f);
b.add_input<decl::Float>(N_("Row 1 Col 3")).default_value(0.0f);
b.add_input<decl::Float>(N_("Row 2 Col 3")).default_value(0.0f);
b.add_input<decl::Float>(N_("Row 3 Col 3")).default_value(1.0f);
b.add_output<decl::Matrix>(N_("Matrix"));
};
static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
}
static void node_update(bNodeTree *tree, bNode *node)
{
const NodeCombSepMatrixMode mode = (NodeCombSepMatrixMode)node->custom1;
const IndexRange vector_sockets(0, 4);
const IndexRange scalar_sockets(4, 16);
const bool show_vector_sockets = ELEM(
mode, NODE_COMBSEP_MATRIX_COLUMNS, NODE_COMBSEP_MATRIX_ROWS);
const bool show_scalar_sockets = ELEM(mode, NODE_COMBSEP_MATRIX_ELEMENTS);
for (const int i : vector_sockets) {
nodeSetSocketAvailability(
tree, (bNodeSocket *)BLI_findlink(&node->inputs, i), show_vector_sockets);
}
for (const int i : scalar_sockets) {
nodeSetSocketAvailability(
tree, (bNodeSocket *)BLI_findlink(&node->inputs, i), show_scalar_sockets);
}
switch (mode) {
case NODE_COMBSEP_MATRIX_COLUMNS:
node_sock_label((bNodeSocket *)BLI_findlink(&node->inputs, vector_sockets[0]), "Column 0");
node_sock_label((bNodeSocket *)BLI_findlink(&node->inputs, vector_sockets[1]), "Column 1");
node_sock_label((bNodeSocket *)BLI_findlink(&node->inputs, vector_sockets[2]), "Column 2");
node_sock_label((bNodeSocket *)BLI_findlink(&node->inputs, vector_sockets[3]), "Column 3");
break;
case NODE_COMBSEP_MATRIX_ROWS:
node_sock_label((bNodeSocket *)BLI_findlink(&node->inputs, vector_sockets[0]), "Row 0");
node_sock_label((bNodeSocket *)BLI_findlink(&node->inputs, vector_sockets[1]), "Row 1");
node_sock_label((bNodeSocket *)BLI_findlink(&node->inputs, vector_sockets[2]), "Row 2");
node_sock_label((bNodeSocket *)BLI_findlink(&node->inputs, vector_sockets[3]), "Row 3");
break;
case NODE_COMBSEP_MATRIX_ELEMENTS:
break;
}
}
static void node_init(bNodeTree * /*tree*/, bNode *node)
{
node->custom1 = NODE_COMBSEP_MATRIX_COLUMNS;
}
static const mf::MultiFunction *get_multi_function(const bNode &bnode)
{
const NodeCombSepMatrixMode mode = (NodeCombSepMatrixMode)bnode.custom1;
static auto columns_fn = mf::build::SI4_SO<float3, float3, float3, float3, float4x4>(
"columns_to_matrix",
[](const float3 &c0, const float3 &c1, const float3 &c2, const float3 &c3) {
float4x4 m;
m.view()[0] = float4(c0, 0.0f);
m.view()[1] = float4(c1, 0.0f);
m.view()[2] = float4(c2, 0.0f);
m.view()[3] = float4(c3, 1.0f);
return m;
});
static auto rows_fn = mf::build::SI4_SO<float3, float3, float3, float3, float4x4>(
"rows_to_matrix",
[](const float3 &r0, const float3 &r1, const float3 &r2, const float3 &r3) {
float4x4 m;
m[0][0] = r0[0];
m[0][1] = r1[0];
m[0][2] = r2[0];
m[0][3] = r3[0];
m[1][0] = r0[1];
m[1][1] = r1[1];
m[1][2] = r2[1];
m[1][3] = r3[1];
m[2][0] = r0[2];
m[2][1] = r1[2];
m[2][2] = r2[2];
m[2][3] = r3[2];
m[3][0] = 0.0f;
m[3][1] = 0.0f;
m[3][2] = 0.0f;
m[3][3] = 1.0f;
return m;
});
static auto exec_preset = mf::build::exec_presets::AllSpanOrSingle();
static auto elements_fn =
mf::build::detail::build_multi_function_with_n_inputs_one_output<float4x4>(
"elements_to_matrix",
[](float m00,
float m01,
float m02,
float m03,
float m10,
float m11,
float m12,
float m13,
float m20,
float m21,
float m22,
float m23,
float m30,
float m31,
float m32,
float m33) {
const float elements[] = {
m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33};
return float4x4(elements);
},
exec_preset,
TypeSequence<float, float, float, float, float, float, float, float, float, float, float, float, float, float, float, float>());
switch (mode) {
case NODE_COMBSEP_MATRIX_COLUMNS:
return &columns_fn;
case NODE_COMBSEP_MATRIX_ROWS:
return &rows_fn;
case NODE_COMBSEP_MATRIX_ELEMENTS:
return &elements_fn;
}
BLI_assert_unreachable();
return nullptr;
}
static void node_build_multi_function(NodeMultiFunctionBuilder &builder)
{
const mf::MultiFunction *fn = get_multi_function(builder.node());
builder.set_matching_fn(fn);
}
} // namespace blender::nodes::node_fn_combine_matrix_cc
void register_node_type_fn_combine_matrix(void)
{
namespace file_ns = blender::nodes::node_fn_combine_matrix_cc;
static bNodeType ntype;
fn_node_type_base(&ntype, FN_NODE_COMBINE_MATRIX, "Combine Matrix", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::node_declare;
ntype.updatefunc = file_ns::node_update;
ntype.initfunc = file_ns::node_init;
ntype.build_multi_function = file_ns::node_build_multi_function;
ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}

View File

@ -0,0 +1,71 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_function_util.hh"
#include "BLI_math_matrix.h"
#include "BLI_math_rotation.h"
#include "BLI_math_vector.h"
namespace blender::nodes::node_fn_decompose_matrix_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
b.add_input<decl::Matrix>(N_("Matrix"));
b.add_output<decl::Vector>(N_("Translation"));
b.add_output<decl::Vector>(N_("Rotation"));
b.add_output<decl::Vector>(N_("Scale"));
};
class DecomposeMatrixFunction : public mf::MultiFunction {
public:
DecomposeMatrixFunction()
{
static const mf::Signature signature = []() {
mf::Signature signature;
mf::SignatureBuilder builder{"Separate Matrix 3x3", signature};
builder.single_input<float4x4>("Matrix");
builder.single_output<float3>("Translation");
builder.single_output<float3>("Rotation");
builder.single_output<float3>("Scale");
return signature;
}();
this->set_signature(&signature);
}
void call(IndexMask mask, mf::Params params, mf::Context /*context*/) const override
{
const VArray<float4x4> &matrices = params.readonly_single_input<float4x4>(0, "Matrix");
MutableSpan<float3> translations = params.uninitialized_single_output<float3>(1, "Translation");
MutableSpan<float3> rotations = params.uninitialized_single_output<float3>(2, "Rotation");
MutableSpan<float3> scales = params.uninitialized_single_output<float3>(3, "Scale");
for (int64_t i : mask) {
const float4x4 &mat = matrices[i];
copy_v3_v3(translations[i], mat[3]);
mat4_to_eul(rotations[i], mat.ptr());
mat4_to_size(scales[i], mat.ptr());
}
}
};
static void node_build_multi_function(NodeMultiFunctionBuilder &builder)
{
static DecomposeMatrixFunction decompose_matrix_fn;
builder.set_matching_fn(&decompose_matrix_fn);
}
} // namespace blender::nodes::node_fn_decompose_matrix_cc
void register_node_type_fn_decompose_matrix(void)
{
namespace file_ns = blender::nodes::node_fn_decompose_matrix_cc;
static bNodeType ntype;
fn_node_type_base(&ntype, FN_NODE_DECOMPOSE_MATRIX, "Decompose Matrix", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::node_declare;
ntype.build_multi_function = file_ns::node_build_multi_function;
nodeRegisterType(&ntype);
}

View File

@ -0,0 +1,56 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_function_util.hh"
#include "BLI_math_matrix.h"
#include "UI_interface.h"
#include "UI_resources.h"
namespace blender::nodes::node_fn_input_matrix_cc {
NODE_STORAGE_FUNCS(NodeInputMatrix);
static void node_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Matrix>(N_("Matrix"));
};
static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "matrix", 0, "", ICON_NONE);
}
static void node_init(bNodeTree * /*tree*/, bNode *node)
{
NodeInputMatrix *data = MEM_new<NodeInputMatrix>(__func__);
unit_m4(data->matrix);
node->storage = data;
}
static void node_build_multi_function(NodeMultiFunctionBuilder &builder)
{
const NodeInputMatrix &storage = node_storage(builder.node());
builder.construct_and_set_matching_fn<mf::CustomMF_Constant<float4x4>>(float4x4{storage.matrix});
}
} // namespace blender::nodes::node_fn_input_matrix_cc
void register_node_type_fn_input_matrix(void)
{
namespace file_ns = blender::nodes::node_fn_input_matrix_cc;
static bNodeType ntype;
fn_node_type_base(&ntype, FN_NODE_INPUT_MATRIX, "Matrix", NODE_CLASS_INPUT);
node_type_storage(
&ntype, "NodeInputMatrix", node_free_standard_storage, node_copy_standard_storage);
ntype.declare = file_ns::node_declare;
ntype.initfunc = file_ns::node_init;
ntype.build_multi_function = file_ns::node_build_multi_function;
ntype.draw_buttons = file_ns::node_layout;
/* Matrix columns need more horizontal space */
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
nodeRegisterType(&ntype);
}

View File

@ -0,0 +1,158 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_function_util.hh"
#include "BLI_math_matrix.hh"
#include "NOD_socket_search_link.hh"
#include "UI_interface.h"
#include "UI_resources.h"
namespace blender::nodes::node_fn_matrix_math_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
b.add_input<decl::Matrix>(N_("Matrix"));
b.add_input<decl::Matrix>(N_("Matrix"), "Matrix_001");
b.add_input<decl::Float>(N_("Scale")).default_value(1.0f);
b.add_output<decl::Matrix>(N_("Matrix"));
b.add_output<decl::Float>(N_("Value"));
};
static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "operation", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
}
static void node_update(bNodeTree *tree, bNode *node)
{
const NodeMatrixMathOperation op = (NodeMatrixMathOperation)node->custom1;
bNodeSocket *in_matrix_a = (bNodeSocket *)BLI_findlink(&node->inputs, 0);
bNodeSocket *in_matrix_b = (bNodeSocket *)BLI_findlink(&node->inputs, 1);
bNodeSocket *in_scale = (bNodeSocket *)BLI_findlink(&node->inputs, 2);
bNodeSocket *out_matrix = (bNodeSocket *)BLI_findlink(&node->outputs, 0);
bNodeSocket *out_value = (bNodeSocket *)BLI_findlink(&node->outputs, 1);
nodeSetSocketAvailability(tree, in_matrix_a, true);
nodeSetSocketAvailability(
tree,
in_matrix_b,
ELEM(op, NODE_MATRIX_MATH_ADD, NODE_MATRIX_MATH_SUBTRACT, NODE_MATRIX_MATH_MULTIPLY));
nodeSetSocketAvailability(tree, in_scale, ELEM(op, NODE_MATRIX_MATH_SCALAR_MULTIPLY));
nodeSetSocketAvailability(tree,
out_matrix,
ELEM(op,
NODE_MATRIX_MATH_ADD,
NODE_MATRIX_MATH_SUBTRACT,
NODE_MATRIX_MATH_SCALAR_MULTIPLY,
NODE_MATRIX_MATH_MULTIPLY,
NODE_MATRIX_MATH_TRANSPOSE,
NODE_MATRIX_MATH_INVERSE));
nodeSetSocketAvailability(
tree, out_value, ELEM(op, NODE_MATRIX_MATH_DETERMINANT, NODE_MATRIX_MATH_TRACE));
/* Labels */
node_sock_label_clear(in_matrix_a);
node_sock_label_clear(in_matrix_b);
node_sock_label_clear(in_scale);
}
static void node_init(bNodeTree * /*tree*/, bNode *node)
{
node->custom1 = NODE_MATRIX_MATH_ADD;
}
static const mf::MultiFunction *get_multi_function(NodeMatrixMathOperation op)
{
static auto exec_preset = mf::build::exec_presets::AllSpanOrSingle();
switch (op) {
case NODE_MATRIX_MATH_ADD: {
static auto fn = mf::build::SI2_SO<float4x4, float4x4, float4x4>(
"add",
[](const float4x4 &a, const float4x4 &b) -> float4x4 { return a + b; },
exec_preset);
return &fn;
}
case NODE_MATRIX_MATH_SUBTRACT: {
static auto fn = mf::build::SI2_SO<float4x4, float4x4, float4x4>(
"subtract",
[](const float4x4 &a, const float4x4 &b) -> float4x4 { return a - b; },
exec_preset);
return &fn;
}
case NODE_MATRIX_MATH_SCALAR_MULTIPLY: {
static auto fn = mf::build::SI2_SO<float4x4, float, float4x4>(
"scalar_multiply",
[](const float4x4 &a, const float &s) -> float4x4 { return a * s; },
exec_preset);
return &fn;
}
case NODE_MATRIX_MATH_MULTIPLY: {
static auto fn = mf::build::SI2_SO<float4x4, float4x4, float4x4>(
"multiply",
[](const float4x4 &a, const float4x4 &b) -> float4x4 { return a * b; },
exec_preset);
return &fn;
}
case NODE_MATRIX_MATH_TRANSPOSE: {
static auto fn = mf::build::SI1_SO<float4x4, float4x4>(
"transpose",
[](const float4x4 &a) -> float4x4 { return math::transpose(a); },
exec_preset);
return &fn;
}
case NODE_MATRIX_MATH_INVERSE: {
static auto fn = mf::build::SI1_SO<float4x4, float4x4>(
"inverse",
[](const float4x4 &a) -> float4x4 { return math::invert(a); },
exec_preset);
return &fn;
}
case NODE_MATRIX_MATH_DETERMINANT: {
static auto fn = mf::build::SI1_SO<float4x4, float>(
"determinant",
[](const float4x4 &a) -> float { return math::determinant(a); },
exec_preset);
return &fn;
}
case NODE_MATRIX_MATH_TRACE: {
static auto fn = mf::build::SI1_SO<float4x4, float>(
"trace",
[](const float4x4 &a) -> float { return a[0][0] + a[1][1] + a[2][2] + a[3][3]; },
exec_preset);
return &fn;
}
}
return nullptr;
}
static void node_build_multi_function(NodeMultiFunctionBuilder &builder)
{
const NodeMatrixMathOperation op = (NodeMatrixMathOperation)builder.node().custom1;
const mf::MultiFunction *fn = get_multi_function(op);
builder.set_matching_fn(fn);
}
} // namespace blender::nodes::node_fn_matrix_math_cc
void register_node_type_fn_matrix_math(void)
{
namespace file_ns = blender::nodes::node_fn_matrix_math_cc;
static bNodeType ntype;
fn_node_type_base(&ntype, FN_NODE_MATRIX_MATH, "Matrix Math", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::node_declare;
ntype.updatefunc = file_ns::node_update;
ntype.initfunc = file_ns::node_init;
ntype.build_multi_function = file_ns::node_build_multi_function;
ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}

View File

@ -0,0 +1,87 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_function_util.hh"
#include "BLI_math_matrix.hh"
#include "UI_interface.h"
#include "UI_resources.h"
namespace blender::nodes::node_fn_matrix_transform_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
b.add_input<decl::Matrix>(N_("Matrix"));
b.add_input<decl::Vector>(N_("Vector"));
b.add_output<decl::Vector>(N_("Vector"));
};
static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "vector_mode", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
}
static void node_init(bNodeTree * /*tree*/, bNode *node)
{
node->custom1 = NODE_MATRIX_TRANSFORM_POINT;
}
static const mf::MultiFunction *get_multi_function(NodeMatrixTransformVectorMode vector_mode)
{
static auto exec_preset = mf::build::exec_presets::AllSpanOrSingle();
switch (vector_mode) {
case NODE_MATRIX_TRANSFORM_POINT: {
static auto fn = mf::build::SI2_SO<float4x4, float3, float3>(
"transform_point",
[](const float4x4 &m, const float3 &v) -> float3 { return math::transform_point(m, v); },
exec_preset);
return &fn;
}
case NODE_MATRIX_TRANSFORM_DIRECTION: {
static auto fn = mf::build::SI2_SO<float4x4, float3, float3>(
"transform_direction",
[](const float4x4 &m, const float3 &v) -> float3 { return math::transform_direction(m, v); },
exec_preset);
return &fn;
}
case NODE_MATRIX_TRANSFORM_NORMAL: {
static auto fn = mf::build::SI2_SO<float4x4, float3, float3>(
"transform_normal",
[](const float4x4 &m, const float3 &v) -> float3 {
const float3x3 transpose_inverse = math::transpose(
math::invert(float3x3(m.view<3, 3>())));
return math::transform_direction(transpose_inverse, v);
},
exec_preset);
return &fn;
}
}
return nullptr;
}
static void node_build_multi_function(NodeMultiFunctionBuilder &builder)
{
const NodeMatrixTransformVectorMode vector_mode = (NodeMatrixTransformVectorMode)builder.node().custom1;
const mf::MultiFunction *fn = get_multi_function(vector_mode);
builder.set_matching_fn(fn);
}
} // namespace blender::nodes::node_fn_matrix_transform_cc
void register_node_type_fn_matrix_transform(void)
{
namespace file_ns = blender::nodes::node_fn_matrix_transform_cc;
static bNodeType ntype;
fn_node_type_base(&ntype, FN_NODE_MATRIX_TRANSFORM, "Matrix Transform", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::node_declare;
ntype.initfunc = file_ns::node_init;
ntype.draw_buttons = file_ns::node_layout;
ntype.build_multi_function = file_ns::node_build_multi_function;
nodeRegisterType(&ntype);
}

View File

@ -0,0 +1,41 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_function_util.hh"
#include "BLI_math_rotation.h"
namespace blender::nodes::node_fn_rotate_matrix_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
b.add_input<decl::Matrix>(N_("Matrix"));
b.add_input<decl::Vector>(N_("Rotation"));
b.add_output<decl::Matrix>(N_("Matrix"));
};
static void node_build_multi_function(NodeMultiFunctionBuilder &builder)
{
static auto fn = mf::build::SI2_SO<float4x4, float3, float4x4>(
"rotate_matrix", [](const float4x4 &mat, const float3 &rot) {
float4x4 rot_mat;
eulO_to_mat4(rot_mat.ptr(), rot, EULER_ORDER_DEFAULT);
return rot_mat * mat;
});
builder.set_matching_fn(&fn);
}
} // namespace blender::nodes::node_fn_rotate_matrix_cc
void register_node_type_fn_rotate_matrix(void)
{
namespace file_ns = blender::nodes::node_fn_rotate_matrix_cc;
static bNodeType ntype;
fn_node_type_base(&ntype, FN_NODE_ROTATE_MATRIX, "Rotate Matrix", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::node_declare;
ntype.build_multi_function = file_ns::node_build_multi_function;
nodeRegisterType(&ntype);
}

View File

@ -0,0 +1,43 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_function_util.hh"
#include "BLI_math_vector.h"
namespace blender::nodes::node_fn_scale_matrix_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
b.add_input<decl::Matrix>(N_("Matrix"));
b.add_input<decl::Vector>(N_("Scale"));
b.add_output<decl::Matrix>(N_("Matrix"));
};
static void node_build_multi_function(NodeMultiFunctionBuilder &builder)
{
static auto fn = mf::build::SI2_SO<float4x4, float3, float4x4>(
"scale_matrix", [](const float4x4 &mat, const float3 &scale) {
float4x4 result;
mul_v3_v3fl(result.view()[0], mat[0], scale[0]);
mul_v3_v3fl(result.view()[1], mat[1], scale[1]);
mul_v3_v3fl(result.view()[2], mat[2], scale[2]);
return result;
});
builder.set_matching_fn(&fn);
}
} // namespace blender::nodes::node_fn_scale_matrix_cc
void register_node_type_fn_scale_matrix(void)
{
namespace file_ns = blender::nodes::node_fn_scale_matrix_cc;
static bNodeType ntype;
fn_node_type_base(&ntype, FN_NODE_SCALE_MATRIX, "Scale Matrix", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::node_declare;
ntype.build_multi_function = file_ns::node_build_multi_function;
nodeRegisterType(&ntype);
}

View File

@ -0,0 +1,267 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_function_util.hh"
#include "UI_interface.h"
#include "UI_resources.h"
namespace blender::nodes::node_fn_separate_matrix_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
b.add_input<decl::Matrix>(N_("Matrix")).default_value(float4x4::identity());
b.add_output<decl::Vector>(N_("Vec0"));
b.add_output<decl::Vector>(N_("Vec1"));
b.add_output<decl::Vector>(N_("Vec2"));
b.add_output<decl::Vector>(N_("Vec3"));
b.add_output<decl::Float>(N_("Row 0 Col 0"));
b.add_output<decl::Float>(N_("Row 1 Col 0"));
b.add_output<decl::Float>(N_("Row 2 Col 0"));
b.add_output<decl::Float>(N_("Row 3 Col 0"));
b.add_output<decl::Float>(N_("Row 0 Col 1"));
b.add_output<decl::Float>(N_("Row 1 Col 1"));
b.add_output<decl::Float>(N_("Row 2 Col 1"));
b.add_output<decl::Float>(N_("Row 3 Col 1"));
b.add_output<decl::Float>(N_("Row 0 Col 2"));
b.add_output<decl::Float>(N_("Row 1 Col 2"));
b.add_output<decl::Float>(N_("Row 2 Col 2"));
b.add_output<decl::Float>(N_("Row 3 Col 2"));
b.add_output<decl::Float>(N_("Row 0 Col 3"));
b.add_output<decl::Float>(N_("Row 1 Col 3"));
b.add_output<decl::Float>(N_("Row 2 Col 3"));
b.add_output<decl::Float>(N_("Row 3 Col 3"));
};
static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
}
static void node_update(bNodeTree *tree, bNode *node)
{
const NodeCombSepMatrixMode mode = (NodeCombSepMatrixMode)node->custom1;
const IndexRange vector_sockets(0, 4);
const IndexRange scalar_sockets(4, 16);
const bool show_vector_sockets = ELEM(
mode, NODE_COMBSEP_MATRIX_COLUMNS, NODE_COMBSEP_MATRIX_ROWS);
const bool show_scalar_sockets = ELEM(mode, NODE_COMBSEP_MATRIX_ELEMENTS);
for (const int i : vector_sockets) {
nodeSetSocketAvailability(
tree, (bNodeSocket *)BLI_findlink(&node->outputs, i), show_vector_sockets);
}
for (const int i : scalar_sockets) {
nodeSetSocketAvailability(
tree, (bNodeSocket *)BLI_findlink(&node->outputs, i), show_scalar_sockets);
}
switch (mode) {
case NODE_COMBSEP_MATRIX_COLUMNS:
node_sock_label((bNodeSocket *)BLI_findlink(&node->outputs, vector_sockets[0]), "Column 0");
node_sock_label((bNodeSocket *)BLI_findlink(&node->outputs, vector_sockets[1]), "Column 1");
node_sock_label((bNodeSocket *)BLI_findlink(&node->outputs, vector_sockets[2]), "Column 2");
node_sock_label((bNodeSocket *)BLI_findlink(&node->outputs, vector_sockets[3]), "Column 3");
break;
case NODE_COMBSEP_MATRIX_ROWS:
node_sock_label((bNodeSocket *)BLI_findlink(&node->outputs, vector_sockets[0]), "Row 0");
node_sock_label((bNodeSocket *)BLI_findlink(&node->outputs, vector_sockets[1]), "Row 1");
node_sock_label((bNodeSocket *)BLI_findlink(&node->outputs, vector_sockets[2]), "Row 2");
node_sock_label((bNodeSocket *)BLI_findlink(&node->outputs, vector_sockets[3]), "Row 3");
break;
case NODE_COMBSEP_MATRIX_ELEMENTS:
break;
}
}
static void node_init(bNodeTree * /*tree*/, bNode *node)
{
node->custom1 = NODE_COMBSEP_MATRIX_COLUMNS;
}
class SeparateColumnsFunction : public mf::MultiFunction {
public:
SeparateColumnsFunction()
{
static const mf::Signature signature = []() {
mf::Signature signature;
mf::SignatureBuilder builder{"Separate Matrix 4x4", signature};
builder.single_input<float4x4>("Matrix");
builder.single_output<float3>("Column0");
builder.single_output<float3>("Column1");
builder.single_output<float3>("Column2");
builder.single_output<float3>("Column3");
return signature;
}();
this->set_signature(&signature);
}
void call(IndexMask mask, mf::Params params, mf::Context /*context*/) const override
{
const VArray<float4x4> &matrices = params.readonly_single_input<float4x4>(0, "Matrix");
MutableSpan<float3> col0 = params.uninitialized_single_output<float3>(1, "Column0");
MutableSpan<float3> col1 = params.uninitialized_single_output<float3>(2, "Column1");
MutableSpan<float3> col2 = params.uninitialized_single_output<float3>(3, "Column2");
MutableSpan<float3> col3 = params.uninitialized_single_output<float3>(4, "Column3");
for (int64_t i : mask) {
const float4x4 &mat = matrices[i];
col0[i] = float3(mat[0]);
col1[i] = float3(mat[1]);
col2[i] = float3(mat[2]);
col3[i] = float3(mat[3]);
}
}
};
class SeparateRowsFunction : public mf::MultiFunction {
public:
SeparateRowsFunction()
{
static const mf::Signature signature = []() {
mf::Signature signature;
mf::SignatureBuilder builder{"Separate Matrix 4x4", signature};
builder.single_input<float4x4>("Matrix");
builder.single_output<float3>("Row0");
builder.single_output<float3>("Row1");
builder.single_output<float3>("Row2");
builder.single_output<float3>("Row3");
return signature;
}();
this->set_signature(&signature);
}
void call(IndexMask mask, mf::Params params, mf::Context /*context*/) const override
{
const VArray<float4x4> &matrices = params.readonly_single_input<float4x4>(0, "Matrix");
MutableSpan<float3> row0 = params.uninitialized_single_output<float3>(1, "Row0");
MutableSpan<float3> row1 = params.uninitialized_single_output<float3>(2, "Row1");
MutableSpan<float3> row2 = params.uninitialized_single_output<float3>(3, "Row2");
MutableSpan<float3> row3 = params.uninitialized_single_output<float3>(4, "Row3");
for (int64_t i : mask) {
const float4x4 &mat = matrices[i];
row0[i] = float3(mat[0][0], mat[1][0], mat[2][0]);
row1[i] = float3(mat[0][1], mat[1][1], mat[2][1]);
row2[i] = float3(mat[0][2], mat[1][2], mat[2][2]);
row3[i] = float3(mat[0][3], mat[1][3], mat[2][3]);
}
}
};
class SeparateElementsFunction : public mf::MultiFunction {
public:
SeparateElementsFunction()
{
static const mf::Signature signature = []() {
mf::Signature signature;
mf::SignatureBuilder builder{"Separate Matrix 4x4", signature};
builder.single_input<float4x4>("Matrix");
builder.single_output<float>("Row0Column0");
builder.single_output<float>("Row0Column1");
builder.single_output<float>("Row0Column2");
builder.single_output<float>("Row0Column3");
builder.single_output<float>("Row1Column0");
builder.single_output<float>("Row1Column1");
builder.single_output<float>("Row1Column2");
builder.single_output<float>("Row1Column3");
builder.single_output<float>("Row2Column0");
builder.single_output<float>("Row2Column1");
builder.single_output<float>("Row2Column2");
builder.single_output<float>("Row2Column3");
builder.single_output<float>("Row3Column0");
builder.single_output<float>("Row3Column1");
builder.single_output<float>("Row3Column2");
builder.single_output<float>("Row3Column3");
return signature;
}();
this->set_signature(&signature);
}
void call(IndexMask mask, mf::Params params, mf::Context /*context*/) const override
{
const VArray<float4x4> &matrices = params.readonly_single_input<float4x4>(0, "Matrix");
MutableSpan<float> m00 = params.uninitialized_single_output<float>(1, "Row0Column0");
MutableSpan<float> m10 = params.uninitialized_single_output<float>(2, "Row0Column1");
MutableSpan<float> m20 = params.uninitialized_single_output<float>(3, "Row0Column2");
MutableSpan<float> m30 = params.uninitialized_single_output<float>(4, "Row0Column3");
MutableSpan<float> m01 = params.uninitialized_single_output<float>(5, "Row1Column0");
MutableSpan<float> m11 = params.uninitialized_single_output<float>(6, "Row1Column1");
MutableSpan<float> m21 = params.uninitialized_single_output<float>(7, "Row1Column2");
MutableSpan<float> m31 = params.uninitialized_single_output<float>(8, "Row1Column3");
MutableSpan<float> m02 = params.uninitialized_single_output<float>(9, "Row2Column0");
MutableSpan<float> m12 = params.uninitialized_single_output<float>(10, "Row2Column1");
MutableSpan<float> m22 = params.uninitialized_single_output<float>(11, "Row2Column2");
MutableSpan<float> m32 = params.uninitialized_single_output<float>(12, "Row2Column3");
MutableSpan<float> m03 = params.uninitialized_single_output<float>(13, "Row3Column0");
MutableSpan<float> m13 = params.uninitialized_single_output<float>(14, "Row3Column1");
MutableSpan<float> m23 = params.uninitialized_single_output<float>(15, "Row3Column2");
MutableSpan<float> m33 = params.uninitialized_single_output<float>(16, "Row3Column3");
for (int64_t i : mask) {
const float4x4 &mat = matrices[i];
m00[i] = mat[0][0];
m01[i] = mat[0][1];
m02[i] = mat[0][2];
m03[i] = mat[0][3];
m10[i] = mat[1][0];
m11[i] = mat[1][1];
m12[i] = mat[1][2];
m13[i] = mat[1][3];
m20[i] = mat[2][0];
m21[i] = mat[2][1];
m22[i] = mat[2][2];
m23[i] = mat[2][3];
m30[i] = mat[3][0];
m31[i] = mat[3][1];
m32[i] = mat[3][2];
m33[i] = mat[3][3];
}
}
};
static void node_build_multi_function(NodeMultiFunctionBuilder &builder)
{
const NodeCombSepMatrixMode mode = (NodeCombSepMatrixMode)builder.node().custom1;
switch (mode) {
case NODE_COMBSEP_MATRIX_COLUMNS: {
static SeparateColumnsFunction fn;
builder.set_matching_fn(fn);
break;
}
case NODE_COMBSEP_MATRIX_ROWS: {
static SeparateRowsFunction fn;
builder.set_matching_fn(fn);
break;
}
case NODE_COMBSEP_MATRIX_ELEMENTS: {
static SeparateElementsFunction fn;
builder.set_matching_fn(fn);
break;
}
default: {
BLI_assert_unreachable();
break;
}
}
}
} // namespace blender::nodes::node_fn_separate_matrix_cc
void register_node_type_fn_separate_matrix(void)
{
namespace file_ns = blender::nodes::node_fn_separate_matrix_cc;
static bNodeType ntype;
fn_node_type_base(&ntype, FN_NODE_SEPARATE_MATRIX, "Separate Matrix", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::node_declare;
ntype.updatefunc = file_ns::node_update;
ntype.initfunc = file_ns::node_init;
ntype.build_multi_function = file_ns::node_build_multi_function;
ntype.draw_buttons = file_ns::node_layout;
nodeRegisterType(&ntype);
}

View File

@ -0,0 +1,42 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_function_util.hh"
namespace blender::nodes::node_fn_translate_matrix_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
b.add_input<decl::Matrix>(N_("Matrix"));
b.add_input<decl::Vector>(N_("Translation"));
b.add_output<decl::Matrix>(N_("Matrix"));
};
static void node_build_multi_function(NodeMultiFunctionBuilder &builder)
{
static auto fn = mf::build::SI2_SO<float4x4, float3, float4x4>(
"translate_matrix", [](const float4x4 &mat, const float3 &translation) {
float4x4 result;
result.view()[0] = mat.view()[0];
result.view()[1] = mat.view()[1];
result.view()[2] = mat.view()[2];
result.view()[3] = mat.view()[3] + float4(translation, 0.0f);
return result;
});
builder.set_matching_fn(&fn);
}
} // namespace blender::nodes::node_fn_translate_matrix_cc
void register_node_type_fn_translate_matrix(void)
{
namespace file_ns = blender::nodes::node_fn_translate_matrix_cc;
static bNodeType ntype;
fn_node_type_base(&ntype, FN_NODE_TRANSLATE_MATRIX, "Translate Matrix", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::node_declare;
ntype.build_multi_function = file_ns::node_build_multi_function;
nodeRegisterType(&ntype);
}

View File

@ -102,7 +102,8 @@ static bool geometry_node_tree_socket_type_valid(bNodeTreeType * /*treetype*/,
SOCK_COLLECTION,
SOCK_TEXTURE,
SOCK_IMAGE,
SOCK_MATERIAL);
SOCK_MATERIAL,
SOCK_MATRIX);
}
void register_node_tree_type_geo()

View File

@ -22,6 +22,8 @@ std::optional<eCustomDataType> node_data_type_to_custom_data_type(const eNodeSoc
return CD_PROP_FLOAT;
case SOCK_VECTOR:
return CD_PROP_FLOAT3;
case SOCK_MATRIX:
return CD_PROP_FLOAT4X4;
case SOCK_RGBA:
return CD_PROP_COLOR;
case SOCK_BOOLEAN:

View File

@ -148,6 +148,11 @@ static SocketDeclarationPtr declaration_for_interface_socket(const bNodeSocket &
dst = std::move(decl);
break;
}
case SOCK_MATRIX: {
std::unique_ptr<decl::Matrix> decl = std::make_unique<decl::Matrix>();
dst = std::move(decl);
break;
}
case SOCK_RGBA: {
const auto &value = *io_socket.default_value_typed<bNodeSocketValueRGBA>();
std::unique_ptr<decl::Color> decl = std::make_unique<decl::Color>();

View File

@ -11,6 +11,7 @@
#include "BLI_color.hh"
#include "BLI_listbase.h"
#include "BLI_math_matrix_types.hh"
#include "BLI_math_vector.h"
#include "BLI_math_vector_types.hh"
#include "BLI_string.h"
@ -79,6 +80,28 @@ struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree,
dval->max = stemp->max;
break;
}
case SOCK_MATRIX: {
bNodeSocketValueMatrix *dval = (bNodeSocketValueMatrix *)sock->default_value;
dval->value[0][0] = stemp->val1;
dval->value[0][1] = 0.0f;
dval->value[0][2] = 0.0f;
dval->value[0][3] = 0.0f;
dval->value[1][0] = 0.0f;
dval->value[1][1] = stemp->val1;
dval->value[1][2] = 0.0f;
dval->value[1][3] = 0.0f;
dval->value[2][0] = 0.0f;
dval->value[2][1] = 0.0f;
dval->value[2][2] = stemp->val1;
dval->value[2][3] = 0.0f;
dval->value[3][0] = 0.0f;
dval->value[3][1] = 0.0f;
dval->value[3][2] = 0.0f;
dval->value[3][3] = stemp->val1;
dval->min = stemp->min;
dval->max = stemp->max;
break;
}
case SOCK_RGBA: {
bNodeSocketValueRGBA *dval = (bNodeSocketValueRGBA *)sock->default_value;
dval->value[0] = stemp->val1;
@ -351,6 +374,20 @@ void node_socket_init_default_value(bNodeSocket *sock)
sock->default_value = dval;
break;
}
case SOCK_MATRIX: {
static float default_value[][4] = {{1.0f, 0.0f, 0.0f, 0.0f},
{0.0f, 1.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 1.0f, 0.0f},
{0.0f, 0.0f, 0.0f, 1.0f}};
bNodeSocketValueMatrix *dval = MEM_cnew<bNodeSocketValueMatrix>(
"node socket value vector");
copy_m4_m4(dval->value, default_value);
dval->min = -FLT_MAX;
dval->max = FLT_MAX;
sock->default_value = dval;
break;
}
case SOCK_RGBA: {
static float default_value[] = {0.0f, 0.0f, 0.0f, 1.0f};
bNodeSocketValueRGBA *dval = MEM_cnew<bNodeSocketValueRGBA>("node socket value color");
@ -451,6 +488,12 @@ void node_socket_copy_default_value(bNodeSocket *to, const bNodeSocket *from)
*toval = *fromval;
break;
}
case SOCK_MATRIX: {
bNodeSocketValueMatrix *toval = (bNodeSocketValueMatrix *)to->default_value;
bNodeSocketValueMatrix *fromval = (bNodeSocketValueMatrix *)from->default_value;
*toval = *fromval;
break;
}
case SOCK_RGBA: {
bNodeSocketValueRGBA *toval = (bNodeSocketValueRGBA *)to->default_value;
bNodeSocketValueRGBA *fromval = (bNodeSocketValueRGBA *)from->default_value;
@ -670,6 +713,22 @@ static bNodeSocketType *make_socket_type_vector(PropertySubType subtype)
return socktype;
}
static bNodeSocketType *make_socket_type_matrix()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_MATRIX, PROP_MATRIX);
socktype->base_cpp_type = &blender::CPPType::get<blender::float4x4>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(blender::float4x4 *)r_value = float4x4(((bNodeSocketValueMatrix *)socket.default_value)->value);
};
socktype->geometry_nodes_cpp_type = &blender::CPPType::get<ValueOrField<blender::float4x4>>();
socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) {
blender::float4x4 value;
socket.typeinfo->get_base_cpp_value(socket, &value);
new (r_value) ValueOrField<blender::float4x4>(value);
};
return socktype;
}
static bNodeSocketType *make_socket_type_rgba()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_RGBA, PROP_NONE);
@ -804,6 +863,8 @@ void register_standard_node_socket_types()
nodeRegisterSocketType(make_socket_type_vector(PROP_EULER));
nodeRegisterSocketType(make_socket_type_vector(PROP_XYZ));
nodeRegisterSocketType(make_socket_type_matrix());
nodeRegisterSocketType(make_socket_type_rgba());
nodeRegisterSocketType(make_socket_type_string());

View File

@ -273,6 +273,52 @@ bNodeSocket &Vector::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket
/** \} */
/* -------------------------------------------------------------------- */
/** \name #Matrix
* \{ */
bNodeSocket &Matrix::build(bNodeTree &ntree, bNode &node) const
{
bNodeSocket &socket = *nodeAddStaticSocket(
&ntree, &node, in_out, SOCK_MATRIX, PROP_MATRIX, identifier.c_str(), name.c_str());
this->set_common_flags(socket);
bNodeSocketValueMatrix &value = *(bNodeSocketValueMatrix *)socket.default_value;
copy_m4_m4(value.value, default_value_.ptr());
value.min = soft_min_value_;
value.max = soft_max_value_;
return socket;
}
bool Matrix::matches(const bNodeSocket &socket) const
{
if (!this->matches_common_data(socket)) {
return false;
}
if (socket.type != SOCK_MATRIX) {
return false;
}
return true;
}
bool Matrix::can_connect(const bNodeSocket &socket) const
{
return sockets_can_connect(*this, socket) && socket.type == SOCK_MATRIX;
}
bNodeSocket &Matrix::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const
{
if (socket.type != SOCK_MATRIX) {
BLI_assert(socket.in_out == in_out);
return this->build(ntree, node);
}
this->set_common_flags(socket);
/*bNodeSocketValueMatrix &value = *(bNodeSocketValueMatrix *)socket.default_value;*/
STRNCPY(socket.name, name.c_str());
return socket;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name #Bool
* \{ */