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

Merged
Hans Goudey merged 47 commits from HooglyBoogly/blender:nodes-matrix-socket into main 2024-02-13 18:59:46 +01:00
59 changed files with 1345 additions and 147 deletions

View File

@ -533,7 +533,7 @@ class NODE_MT_category_GEO_UTILITIES(Menu):
bl_idname = "NODE_MT_category_GEO_UTILITIES"
bl_label = "Utilities"
def draw(self, _context):
def draw(self, context):
layout = self.layout
layout.menu("NODE_MT_geometry_node_GEO_COLOR")
layout.menu("NODE_MT_category_GEO_TEXT")
@ -541,6 +541,8 @@ 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")
if context.preferences.experimental.use_new_matrix_socket:
layout.menu("NODE_MT_category_utilities_matrix")
layout.menu("NODE_MT_category_GEO_UTILITIES_ROTATION")
layout.menu("NODE_MT_category_GEO_UTILITIES_DEPRECATED")
layout.separator()
@ -592,6 +594,22 @@ class NODE_MT_category_GEO_UTILITIES_ROTATION(Menu):
node_add_menu.draw_assets_for_catalog(layout, "Utilities/Rotation")
class NODE_MT_category_utilities_matrix(Menu):
bl_idname = "NODE_MT_category_utilities_matrix"
bl_label = "Matrix"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "FunctionNodeCombineTransform")
node_add_menu.add_node_type(layout, "FunctionNodeInvertMatrix")
node_add_menu.add_node_type(layout, "FunctionNodeMatrixMultiply")
node_add_menu.add_node_type(layout, "FunctionNodeSeparateTransform")
node_add_menu.add_node_type(layout, "FunctionNodeTransformDirection")
node_add_menu.add_node_type(layout, "FunctionNodeTransformPoint")
node_add_menu.add_node_type(layout, "FunctionNodeTransposeMatrix")
node_add_menu.draw_assets_for_catalog(layout, "Utilities/Matrix")
class NODE_MT_category_GEO_UTILITIES_MATH(Menu):
bl_idname = "NODE_MT_category_GEO_UTILITIES_MATH"
bl_label = "Math"
@ -779,6 +797,7 @@ classes = (
NODE_MT_category_GEO_UTILITIES_FIELD,
NODE_MT_category_GEO_UTILITIES_MATH,
NODE_MT_category_GEO_UTILITIES_ROTATION,
NODE_MT_category_utilities_matrix,
NODE_MT_category_GEO_UTILITIES_DEPRECATED,
NODE_MT_category_GEO_GROUP,
)

View File

@ -2661,6 +2661,7 @@ class USERPREF_PT_experimental_prototypes(ExperimentalPanel, Panel):
({"property": "use_sculpt_texture_paint"}, ("blender/blender/issues/96225", "#96225")),
({"property": "use_experimental_compositors"}, ("blender/blender/issues/88150", "#88150")),
({"property": "use_grease_pencil_version3"}, ("blender/blender/projects/6", "Grease Pencil 3.0")),
({"property": "use_new_matrix_socket"}, ("blender/blender/issues/116067", "Matrix Socket")),
({"property": "enable_overlay_next"}, ("blender/blender/issues/102179", "#102179")),
({"property": "use_extension_repos"}, ("/blender/blender/issues/106254", "#106254")),
),

View File

@ -35,7 +35,8 @@ inline void convert_to_static_type(const CPPType &cpp_type, const Func &func)
int8_t,
ColorGeometry4f,
ColorGeometry4b,
math::Quaternion>([&](auto type_tag) {
math::Quaternion,
float4x4>([&](auto type_tag) {
using T = typename decltype(type_tag)::type;
if constexpr (std::is_same_v<T, void>) {
/* It's expected that the given cpp type is one of the supported ones. */
@ -517,6 +518,26 @@ class ColorGeometry4bMixer {
void finalize(const IndexMask &mask);
};
class float4x4Mixer {
private:
MutableSpan<float4x4> buffer_;
Array<float> total_weights_;
Array<float3> location_buffer_;
Array<float3> expmap_buffer_;
Array<float3> scale_buffer_;
public:
float4x4Mixer(MutableSpan<float4x4> buffer);
/**
* \param mask: Only initialize these indices. Other indices in the buffer will be invalid.
*/
float4x4Mixer(MutableSpan<float4x4> buffer, const IndexMask &mask);
void set(int64_t index, const float4x4 &value, float weight = 1.0f);
void mix_in(int64_t index, const float4x4 &value, float weight = 1.0f);
void finalize();
void finalize(const IndexMask &mask);
};
template<typename T> struct DefaultMixerStruct {
/* Use void by default. This can be checked for in `if constexpr` statements. */
using type = void;
@ -538,6 +559,9 @@ template<> struct DefaultMixerStruct<ColorGeometry4f> {
template<> struct DefaultMixerStruct<ColorGeometry4b> {
using type = ColorGeometry4bMixer;
};
template<> struct DefaultMixerStruct<float4x4> {
using type = float4x4Mixer;
};
template<> struct DefaultMixerStruct<int> {
static double int_to_double(const int &value)
{

View File

@ -1366,6 +1366,13 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
#define FN_NODE_ROTATE_VECTOR 1229
#define FN_NODE_ROTATE_ROTATION 1230
#define FN_NODE_INVERT_ROTATION 1231
#define FN_NODE_TRANSFORM_POINT 1232
#define FN_NODE_TRANSFORM_DIRECTION 1233
#define FN_NODE_MATRIX_MULTIPLY 1234
#define FN_NODE_COMBINE_TRANSFORM 1235
#define FN_NODE_SEPARATE_TRANSFORM 1236
#define FN_NODE_INVERT_MATRIX 1237
#define FN_NODE_TRANSPOSE_MATRIX 1238
/** \} */

View File

@ -130,6 +130,7 @@ static const bNodeSocketStaticTypeInfo node_socket_subtypes[] = {
{"NodeSocketIntFactor", "NodeTreeInterfaceSocketIntFactor", SOCK_INT, PROP_FACTOR},
{"NodeSocketBool", "NodeTreeInterfaceSocketBool", SOCK_BOOLEAN, PROP_NONE},
{"NodeSocketRotation", "NodeTreeInterfaceSocketRotation", SOCK_ROTATION, PROP_NONE},
{"NodeSocketMatrix", "NodeTreeInterfaceSocketMatrix", SOCK_MATRIX, PROP_NONE},
{"NodeSocketVector", "NodeTreeInterfaceSocketVector", SOCK_VECTOR, PROP_NONE},
{"NodeSocketVectorTranslation",
"NodeTreeInterfaceSocketVectorTranslation",
@ -206,6 +207,7 @@ template<typename Fn> bool socket_data_to_static_type(const eNodeSocketDatatype
case SOCK_CUSTOM:
case SOCK_SHADER:
case SOCK_MATRIX:
case SOCK_GEOMETRY:
return true;
}

View File

@ -50,6 +50,8 @@ const blender::CPPType *custom_data_type_to_cpp_type(const eCustomDataType type)
return &CPPType::get<ColorGeometry4b>();
case CD_PROP_QUATERNION:
return &CPPType::get<math::Quaternion>();
case CD_PROP_FLOAT4X4:
return &CPPType::get<float4x4>();
case CD_PROP_STRING:
return &CPPType::get<MStringProperty>();
default:
@ -89,6 +91,9 @@ eCustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type)
if (type.is<math::Quaternion>()) {
return CD_PROP_QUATERNION;
}
if (type.is<float4x4>()) {
return CD_PROP_FLOAT4X4;
}
if (type.is<MStringProperty>()) {
return CD_PROP_STRING;
}
@ -167,6 +172,8 @@ static int attribute_data_type_complexity(const eCustomDataType data_type)
return 8;
case CD_PROP_COLOR:
return 9;
case CD_PROP_FLOAT4X4:
return 10;
#if 0 /* These attribute types are not supported yet. */
case CD_PROP_STRING:
return 10;

View File

@ -3,6 +3,7 @@
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_array_utils.hh"
#include "BLI_math_matrix.hh"
#include "BLI_math_quaternion.hh"
#include "BKE_attribute_math.hh"
@ -36,6 +37,40 @@ math::Quaternion mix4(const float4 &weights,
return math::Quaternion::expmap(expmap_mixed);
}
template<> float4x4 mix2(const float factor, const float4x4 &a, const float4x4 &b)
{
return math::interpolate(a, b, factor);
}
template<>
float4x4 mix3(const float3 &weights, const float4x4 &v0, const float4x4 &v1, const float4x4 &v2)
{
const float3 location = mix3(weights, v0.location(), v1.location(), v2.location());
const math::Quaternion rotation = mix3(
weights, math::to_quaternion(v0), math::to_quaternion(v1), math::to_quaternion(v2));
const float3 scale = mix3(weights, math::to_scale(v0), math::to_scale(v1), math::to_scale(v2));
return math::from_loc_rot_scale<float4x4>(location, rotation, scale);
}
template<>
float4x4 mix4(const float4 &weights,
const float4x4 &v0,
const float4x4 &v1,
const float4x4 &v2,
const float4x4 &v3)
{
const float3 location = mix4(
weights, v0.location(), v1.location(), v2.location(), v3.location());
const math::Quaternion rotation = mix4(weights,
math::to_quaternion(v0),
math::to_quaternion(v1),
math::to_quaternion(v2),
math::to_quaternion(v3));
const float3 scale = mix4(
weights, math::to_scale(v0), math::to_scale(v1), math::to_scale(v2), math::to_scale(v3));
return math::from_loc_rot_scale<float4x4>(location, rotation, scale);
}
ColorGeometry4fMixer::ColorGeometry4fMixer(MutableSpan<ColorGeometry4f> buffer,
ColorGeometry4f default_color)
: ColorGeometry4fMixer(buffer, buffer.index_range(), default_color)
@ -160,6 +195,58 @@ void ColorGeometry4bMixer::finalize(const IndexMask &mask)
});
}
float4x4Mixer::float4x4Mixer(MutableSpan<float4x4> buffer)
: float4x4Mixer(buffer, buffer.index_range())
{
}
float4x4Mixer::float4x4Mixer(MutableSpan<float4x4> buffer, const IndexMask & /*mask*/)
: buffer_(buffer),
total_weights_(buffer.size(), 0.0f),
location_buffer_(buffer.size(), float3(0)),
expmap_buffer_(buffer.size(), float3(0)),
scale_buffer_(buffer.size(), float3(0))
{
}
void float4x4Mixer::float4x4Mixer::set(int64_t index, const float4x4 &value, const float weight)
{
location_buffer_[index] = value.location() * weight;
expmap_buffer_[index] = math::to_quaternion(value).expmap() * weight;
scale_buffer_[index] = math::to_scale(value) * weight;
total_weights_[index] = weight;
}
void float4x4Mixer::mix_in(int64_t index, const float4x4 &value, float weight)
{
location_buffer_[index] += value.location() * weight;
expmap_buffer_[index] += math::to_quaternion(value).expmap() * weight;
scale_buffer_[index] += math::to_scale(value) * weight;
total_weights_[index] += weight;
}
void float4x4Mixer::finalize()
{
this->finalize(buffer_.index_range());
}
void float4x4Mixer::finalize(const IndexMask &mask)
{
mask.foreach_index([&](const int64_t i) {
const float weight = total_weights_[i];
if (weight > 0.0f) {
const float weight_inv = math::rcp(weight);
buffer_[i] = math::from_loc_rot_scale<float4x4>(
location_buffer_[i] * weight_inv,
math::Quaternion::expmap(expmap_buffer_[i] * weight_inv),
scale_buffer_[i] * weight_inv);
}
else {
buffer_[i] = float4x4::identity();
}
});
}
void gather(const GSpan src, const Span<int> map, GMutableSpan dst)
{
attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {

View File

@ -1042,6 +1042,10 @@ static std::shared_ptr<io::serialize::Value> serialize_primitive_value(
const math::Quaternion value = *static_cast<const math::Quaternion *>(value_ptr);
return serialize_float_array({&value.x, 4});
}
case CD_PROP_FLOAT4X4: {
const float4x4 value = *static_cast<const float4x4 *>(value_ptr);
return serialize_float_array({value.base_ptr(), value.col_len * value.row_len});
}
default:
break;
}
@ -1160,6 +1164,9 @@ template<typename T>
case CD_PROP_QUATERNION: {
return deserialize_float_array(io_value, {static_cast<float *>(r_value), 4});
}
case CD_PROP_FLOAT4X4: {
return deserialize_float_array(io_value, {static_cast<float *>(r_value), 4 * 4});
}
default:
break;
}

View File

@ -47,6 +47,7 @@ Array<std::unique_ptr<BakeItem>> move_socket_values_to_bake_items(const Span<voi
case SOCK_INT:
case SOCK_BOOLEAN:
case SOCK_ROTATION:
case SOCK_MATRIX:
case SOCK_RGBA: {
auto &value_variant = *static_cast<SocketValueVariant *>(socket_value);
if (value_variant.is_context_dependent_field()) {
@ -131,6 +132,7 @@ Array<std::unique_ptr<BakeItem>> move_socket_values_to_bake_items(const Span<voi
case SOCK_INT:
case SOCK_BOOLEAN:
case SOCK_ROTATION:
case SOCK_MATRIX:
case SOCK_RGBA: {
const CPPType &base_type = *socket_type_to_geo_nodes_base_cpp_type(socket_type);
if (const auto *item = dynamic_cast<const PrimitiveBakeItem *>(&bake_item)) {

View File

@ -24,6 +24,7 @@
#include "BLI_endian_switch.h"
#include "BLI_index_range.hh"
#include "BLI_math_color_blend.h"
#include "BLI_math_matrix.hh"
#include "BLI_math_quaternion_types.hh"
#include "BLI_math_vector.hh"
#include "BLI_mempool.h"
@ -113,6 +114,7 @@ bool CustomData_MeshMasks_are_matching(const CustomData_MeshMasks *mask_ref,
struct LayerTypeInfo {
int size; /* the memory size of one element of this layer's data */
int alignment;
/** name of the struct used, for file writing */
const char *structname;
@ -1526,6 +1528,16 @@ static void layerDefault_propquaternion(void *data, const int count)
MutableSpan(static_cast<math::Quaternion *>(data), count).fill(math::Quaternion::identity());
}
/* -------------------------------------------------------------------- */
/** \name Callbacks for (#math::Quaternion, #CD_PROP_FLOAT4X4)
* \{ */
static void layerDefault_propfloat4x4(void *data, const int count)
{
using namespace blender;
MutableSpan(static_cast<float4x4 *>(data), count).fill(float4x4::identity());
}
/** \} */
/* -------------------------------------------------------------------- */
@ -1534,11 +1546,30 @@ static void layerDefault_propquaternion(void *data, const int count)
static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
/* 0: CD_MVERT */ /* DEPRECATED */
{sizeof(MVert), "MVert", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
{sizeof(MVert),
alignof(MVert),
"MVert",
1,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr},
/* 1: CD_MSTICKY */ /* DEPRECATED */
{sizeof(float[2]), "", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
{sizeof(float[2]),
alignof(float2),
"",
1,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr},
/* 2: CD_MDEFORMVERT */
{sizeof(MDeformVert),
alignof(MDeformVert),
"MDeformVert",
1,
nullptr,
@ -1549,11 +1580,30 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
nullptr,
layerConstruct_mdeformvert},
/* 3: CD_MEDGE */ /* DEPRECATED */
{sizeof(MEdge), "MEdge", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
{sizeof(MEdge),
alignof(MEdge),
"MEdge",
1,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr},
/* 4: CD_MFACE */
{sizeof(MFace), "MFace", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
{sizeof(MFace),
alignof(MFace),
"MFace",
1,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr},
/* 5: CD_MTFACE */
{sizeof(MTFace),
alignof(MTFace),
"MTFace",
1,
N_("UVMap"),
@ -1576,18 +1626,31 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
layerMaxNum_tface},
/* 6: CD_MCOL */
/* 4 MCol structs per face */
{sizeof(MCol[4]), "MCol", 4,
N_("Col"), nullptr, nullptr,
layerInterp_mcol, layerSwap_mcol, layerDefault_mcol,
nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr},
{sizeof(MCol[4]),
alignof(MCol[4]),
"MCol",
4,
N_("Col"),
nullptr,
nullptr,
layerInterp_mcol,
layerSwap_mcol,
layerDefault_mcol},
/* 7: CD_ORIGINDEX */
{sizeof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, layerDefault_origindex},
{sizeof(int),
alignof(int),
"",
0,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
layerDefault_origindex},
/* 8: CD_NORMAL */
/* 3 floats per normal vector */
{sizeof(float[3]),
alignof(blender::float3),
"vec3f",
1,
nullptr,
@ -1605,9 +1668,10 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
nullptr,
layerCopyValue_normal},
/* 9: CD_FACEMAP */ /* DEPRECATED */
{sizeof(int), ""},
{sizeof(int), alignof(int), ""},
/* 10: CD_PROP_FLOAT */
{sizeof(MFloatProperty),
alignof(float),
"MFloatProperty",
1,
N_("Float"),
@ -1620,6 +1684,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
layerValidate_propFloat},
/* 11: CD_PROP_INT32 */
{sizeof(MIntProperty),
alignof(int),
"MIntProperty",
1,
N_("Int"),
@ -1629,6 +1694,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
nullptr},
/* 12: CD_PROP_STRING */
{sizeof(MStringProperty),
alignof(MStringProperty),
"MStringProperty",
1,
N_("String"),
@ -1638,6 +1704,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
nullptr},
/* 13: CD_ORIGSPACE */
{sizeof(OrigSpaceFace),
alignof(OrigSpaceFace),
"OrigSpaceFace",
1,
N_("UVMap"),
@ -1647,15 +1714,25 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
layerSwap_origspace_face,
layerDefault_origspace_face},
/* 14: CD_ORCO */
{sizeof(float[3]), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
{sizeof(float[3]),
alignof(blender::float3),
"",
0,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr},
/* 15: CD_MTEXPOLY */ /* DEPRECATED */
/* NOTE: when we expose the UV Map / TexFace split to the user,
* change this back to face Texture. */
{sizeof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
{sizeof(int), alignof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 16: CD_MLOOPUV */ /* DEPRECATED */
{sizeof(MLoopUV), "MLoopUV", 1, N_("UVMap")},
{sizeof(MLoopUV), alignof(MLoopUV), "MLoopUV", 1, N_("UVMap")},
/* 17: CD_PROP_BYTE_COLOR */
{sizeof(MLoopCol),
alignof(MLoopCol),
"MLoopCol",
1,
N_("Col"),
@ -1677,9 +1754,19 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
nullptr,
nullptr},
/* 18: CD_TANGENT */
{sizeof(float[4][4]), "", 0, N_("Tangent"), nullptr, nullptr, nullptr, nullptr, nullptr},
{sizeof(float[4][4]),
alignof(float[4][4]),
"",
0,
N_("Tangent"),
nullptr,
nullptr,
nullptr,
nullptr,
nullptr},
/* 19: CD_MDISPS */
{sizeof(MDisps),
alignof(MDisps),
"MDisps",
1,
nullptr,
@ -1700,11 +1787,30 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
layerWrite_mdisps,
layerFilesize_mdisps},
/* 20: CD_PREVIEW_MCOL */
{},
{sizeof(blender::float4x4),
alignof(blender::float4x4),
"mat4x4f",
1,
N_("4 by 4 Float Matrix"),
nullptr,
nullptr,
nullptr,
nullptr,
layerDefault_propfloat4x4},
/* 21: CD_ID_MCOL */ /* DEPRECATED */
{sizeof(MCol[4]), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
{sizeof(MCol[4]),
alignof(MCol[4]),
"",
0,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr},
/* 22: CD_TEXTURE_MCOL */
{sizeof(MCol[4]),
alignof(MCol[4]),
"MCol",
4,
N_("TexturedCol"),
@ -1714,13 +1820,40 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
layerSwap_mcol,
layerDefault_mcol},
/* 23: CD_CLOTH_ORCO */
{sizeof(float[3]), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
{sizeof(float[3]),
alignof(float[3]),
"",
0,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr},
/* 24: CD_RECAST */
{sizeof(MRecast), "MRecast", 1, N_("Recast"), nullptr, nullptr, nullptr, nullptr},
{sizeof(MRecast),
alignof(MRecast),
"MRecast",
1,
N_("Recast"),
nullptr,
nullptr,
nullptr,
nullptr},
/* 25: CD_MPOLY */ /* DEPRECATED */
{sizeof(MPoly), "MPoly", 1, N_("NGon Face"), nullptr, nullptr, nullptr, nullptr, nullptr},
{sizeof(MPoly),
alignof(MPoly),
"MPoly",
1,
N_("NGon Face"),
nullptr,
nullptr,
nullptr,
nullptr,
nullptr},
/* 26: CD_MLOOP */ /* DEPRECATED */
{sizeof(MLoop),
alignof(MLoop),
"MLoop",
1,
N_("NGon Face-Vertex"),
@ -1730,15 +1863,23 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
nullptr,
nullptr},
/* 27: CD_SHAPE_KEYINDEX */
{sizeof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
{sizeof(int), alignof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 28: CD_SHAPEKEY */
{sizeof(float[3]), "", 0, N_("ShapeKey"), nullptr, nullptr, layerInterp_shapekey},
{sizeof(float[3]),
alignof(float[3]),
"",
0,
N_("ShapeKey"),
nullptr,
nullptr,
layerInterp_shapekey},
/* 29: CD_BWEIGHT */ /* DEPRECATED */
{sizeof(MFloatProperty), "MFloatProperty", 1},
{sizeof(MFloatProperty), alignof(MFloatProperty), "MFloatProperty", 1},
/* 30: CD_CREASE */ /* DEPRECATED */
{sizeof(float), ""},
{sizeof(float), alignof(float), ""},
/* 31: CD_ORIGSPACE_MLOOP */
{sizeof(OrigSpaceLoop),
alignof(OrigSpaceLoop),
"OrigSpaceLoop",
1,
N_("OS Loop"),
@ -1759,6 +1900,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
{},
/* 33: CD_BM_ELEM_PYPTR */
{sizeof(void *),
alignof(void *),
"",
1,
nullptr,
@ -1768,9 +1910,10 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
nullptr,
nullptr},
/* 34: CD_PAINT_MASK */ /* DEPRECATED */
{sizeof(float), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
{sizeof(float), alignof(float), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 35: CD_GRID_PAINT_MASK */
{sizeof(GridPaintMask),
alignof(GridPaintMask),
"GridPaintMask",
1,
nullptr,
@ -1782,6 +1925,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
layerConstruct_grid_paint_mask},
/* 36: CD_MVERT_SKIN */
{sizeof(MVertSkin),
alignof(MVertSkin),
"MVertSkin",
1,
nullptr,
@ -1792,6 +1936,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
layerDefault_mvert_skin},
/* 37: CD_FREESTYLE_EDGE */
{sizeof(FreestyleEdge),
alignof(FreestyleEdge),
"FreestyleEdge",
1,
nullptr,
@ -1802,6 +1947,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
nullptr},
/* 38: CD_FREESTYLE_FACE */
{sizeof(FreestyleFace),
alignof(FreestyleFace),
"FreestyleFace",
1,
nullptr,
@ -1811,23 +1957,87 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
nullptr,
nullptr},
/* 39: CD_MLOOPTANGENT */
{sizeof(float[4]), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
{sizeof(float[4]),
alignof(float[4]),
"",
0,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr},
/* 40: CD_TESSLOOPNORMAL */
{sizeof(short[4][3]), "", 0, nullptr, nullptr, nullptr, nullptr, layerSwap_flnor, nullptr},
{sizeof(short[4][3]),
alignof(short[4][3]),
"",
0,
nullptr,
nullptr,
nullptr,
nullptr,
layerSwap_flnor,
nullptr},
/* 41: CD_CUSTOMLOOPNORMAL */
{sizeof(short[2]), "vec2s", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
{sizeof(short[2]),
alignof(short[2]),
"vec2s",
1,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr},
/* 42: CD_SCULPT_FACE_SETS */ /* DEPRECATED */
{sizeof(int), ""},
{sizeof(int), alignof(int), ""},
/* 43: CD_LOCATION */
{sizeof(float[3]), "vec3f", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
{sizeof(float[3]),
alignof(float[3]),
"vec3f",
1,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr},
/* 44: CD_RADIUS */
{sizeof(float), "MFloatProperty", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
{sizeof(float),
alignof(float),
"MFloatProperty",
1,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr},
/* 45: CD_PROP_INT8 */
{sizeof(int8_t), "MInt8Property", 1, N_("Int8"), nullptr, nullptr, nullptr, nullptr, nullptr},
{sizeof(int8_t),
alignof(int8_t),
"MInt8Property",
1,
N_("Int8"),
nullptr,
nullptr,
nullptr,
nullptr,
nullptr},
/* 46: CD_PROP_INT32_2D */
{sizeof(blender::int2), "vec2i", 1, N_("Int 2D"), nullptr, nullptr, nullptr, nullptr, nullptr},
{sizeof(blender::int2),
alignof(blender::int2),
"vec2i",
1,
N_("Int 2D"),
nullptr,
nullptr,
nullptr,
nullptr,
nullptr},
/* 47: CD_PROP_COLOR */
{sizeof(MPropCol),
alignof(MPropCol),
"MPropCol",
1,
N_("Color"),
@ -1850,6 +2060,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
nullptr},
/* 48: CD_PROP_FLOAT3 */
{sizeof(float[3]),
alignof(blender::float3),
"vec3f",
1,
N_("Float3"),
@ -1866,6 +2077,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
layerAdd_propfloat3},
/* 49: CD_PROP_FLOAT2 */
{sizeof(float[2]),
alignof(float2),
"vec2f",
1,
N_("Float2"),
@ -1884,6 +2096,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
layerCopyValue_propfloat2},
/* 50: CD_PROP_BOOL */
{sizeof(bool),
alignof(bool),
"bool",
1,
N_("Boolean"),
@ -1898,9 +2111,19 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
nullptr,
nullptr},
/* 51: CD_HAIRLENGTH */ /* DEPRECATED */ /* UNUSED */
{sizeof(float), "float", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
{sizeof(float),
alignof(float),
"float",
1,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr},
/* 52: CD_PROP_QUATERNION */
{sizeof(float[4]),
alignof(blender::float4),
"vec4f",
1,
N_("Quaternion"),
@ -2134,12 +2357,15 @@ static bool customdata_typemap_is_valid(const CustomData *data)
static void *copy_layer_data(const eCustomDataType type, const void *data, const int totelem)
{
const LayerTypeInfo &type_info = *layerType_getInfo(type);
const int64_t size_in_bytes = int64_t(totelem) * type_info.size;
void *new_data = MEM_mallocN_aligned(size_in_bytes, type_info.alignment, __func__);
if (type_info.copy) {
void *new_data = MEM_malloc_arrayN(size_t(totelem), type_info.size, __func__);
type_info.copy(data, new_data, totelem);
return new_data;
}
return MEM_dupallocN(data);
else {
memcpy(new_data, data, size_in_bytes);
}
return new_data;
}
static void free_layer_data(const eCustomDataType type, const void *data, const int totelem)
@ -2389,7 +2615,7 @@ void CustomData_realloc(CustomData *data,
const int64_t old_size_in_bytes = int64_t(old_size) * typeInfo->size;
const int64_t new_size_in_bytes = int64_t(new_size) * typeInfo->size;
void *new_layer_data = MEM_mallocN(new_size_in_bytes, __func__);
void *new_layer_data = MEM_mallocN_aligned(new_size_in_bytes, typeInfo->alignment, __func__);
/* Copy data to new array. */
if (old_size_in_bytes) {
if (typeInfo->copy) {
@ -2877,23 +3103,27 @@ static CustomDataLayer *customData_add_layer__internal(
* leaks into the new layer. */
memset(&new_layer, 0, sizeof(CustomDataLayer));
const int64_t size_in_bytes = int64_t(totelem) * type_info.size;
const char *alloc_name = layerType_getName(type);
if (alloctype.has_value()) {
switch (*alloctype) {
case CD_SET_DEFAULT: {
if (totelem > 0) {
new_layer.data = MEM_mallocN_aligned(size_in_bytes, type_info.alignment, alloc_name);
if (type_info.set_default_value) {
new_layer.data = MEM_malloc_arrayN(totelem, type_info.size, layerType_getName(type));
type_info.set_default_value(new_layer.data, totelem);
}
else {
new_layer.data = MEM_calloc_arrayN(totelem, type_info.size, layerType_getName(type));
/* Alternatively, #MEM_calloc_arrayN is faster, but has no aligned version. */
memset(new_layer.data, 0, size_in_bytes);
}
}
break;
}
case CD_CONSTRUCT: {
if (totelem > 0) {
new_layer.data = MEM_malloc_arrayN(totelem, type_info.size, layerType_getName(type));
new_layer.data = MEM_mallocN_aligned(size_in_bytes, type_info.alignment, alloc_name);
if (type_info.construct) {
type_info.construct(new_layer.data, totelem);
}

View File

@ -132,6 +132,9 @@ static void sort_indices(MutableSpan<int> indices, const Span<T> values, const i
const float4 value2_quat = float4(value2);
return value1_quat[component_i] < value2_quat[component_i];
}
if constexpr (std::is_same_v<T, float4x4>) {
return value1.base_ptr()[component_i] < value2.base_ptr()[component_i];
}
if constexpr (std::is_same_v<T, int2>) {
for (int i = 0; i < 2; i++) {
if (value1[i] != value2[i]) {
@ -248,6 +251,10 @@ static bool values_different(const T value1,
const float4 value2_f = float4(value2);
return compare_threshold_relative(value1_f[component_i], value2_f[component_i], threshold);
}
if constexpr (std::is_same_v<T, float4x4>) {
return compare_threshold_relative(
value1.base_ptr()[component_i], value2.base_ptr()[component_i], threshold);
}
BLI_assert_unreachable();
}
@ -575,6 +582,9 @@ static std::optional<MeshMismatch> sort_domain_using_attributes(
else if constexpr (is_same_any_v<T, math::Quaternion, ColorGeometry4f>) {
num_loops = 4;
}
else if constexpr (is_same_any_v<T, float4x4>) {
num_loops = 16;
}
for (const int component_i : IndexRange(num_loops)) {
sort_per_set_based_on_attributes(
maps.set_sizes, maps.from_sorted1, maps.from_sorted2, values1, values2, component_i);

View File

@ -353,6 +353,7 @@ static void library_foreach_node_socket(LibraryForeachIDData *data, bNodeSocket
case SOCK_RGBA:
case SOCK_BOOLEAN:
case SOCK_ROTATION:
case SOCK_MATRIX:
case SOCK_INT:
case SOCK_STRING:
case SOCK_CUSTOM:
@ -703,10 +704,12 @@ static void write_node_socket_default_value(BlendWriter *writer, const bNodeSock
case SOCK_ROTATION:
BLO_write_struct(writer, bNodeSocketValueRotation, sock->default_value);
break;
case SOCK_MENU: {
case SOCK_MENU:
BLO_write_struct(writer, bNodeSocketValueMenu, sock->default_value);
break;
}
case SOCK_MATRIX:
/* Matrix sockets currently have no default value. */
break;
case SOCK_CUSTOM:
/* Custom node sockets where default_value is defined uses custom properties for storage. */
break;
@ -939,6 +942,7 @@ static bool is_node_socket_supported(const bNodeSocket *sock)
case SOCK_MATERIAL:
case SOCK_ROTATION:
case SOCK_MENU:
case SOCK_MATRIX:
return true;
}
return false;
@ -1863,6 +1867,7 @@ static void socket_id_user_increment(bNodeSocket *sock)
case SOCK_RGBA:
case SOCK_BOOLEAN:
case SOCK_ROTATION:
case SOCK_MATRIX:
case SOCK_INT:
case SOCK_STRING:
case SOCK_MENU:
@ -1910,6 +1915,7 @@ static bool socket_id_user_decrement(bNodeSocket *sock)
case SOCK_RGBA:
case SOCK_BOOLEAN:
case SOCK_ROTATION:
case SOCK_MATRIX:
case SOCK_INT:
case SOCK_STRING:
case SOCK_MENU:
@ -1965,6 +1971,7 @@ void nodeModifySocketType(bNodeTree *ntree,
case SOCK_SHADER:
case SOCK_BOOLEAN:
case SOCK_ROTATION:
case SOCK_MATRIX:
case SOCK_CUSTOM:
case SOCK_OBJECT:
case SOCK_IMAGE:
@ -2071,6 +2078,8 @@ const char *nodeStaticSocketType(const int type, const int subtype)
return "NodeSocketBool";
case SOCK_ROTATION:
return "NodeSocketRotation";
case SOCK_MATRIX:
return "NodeSocketMatrix";
case SOCK_VECTOR:
switch (PropertySubType(subtype)) {
case PROP_TRANSLATION:
@ -2154,6 +2163,8 @@ const char *nodeStaticSocketInterfaceTypeNew(const int type, const int subtype)
return "NodeTreeInterfaceSocketBool";
case SOCK_ROTATION:
return "NodeTreeInterfaceSocketRotation";
case SOCK_MATRIX:
return "NodeTreeInterfaceSocketMatrix";
case SOCK_VECTOR:
switch (PropertySubType(subtype)) {
case PROP_TRANSLATION:
@ -2209,6 +2220,8 @@ const char *nodeStaticSocketLabel(const int type, const int /*subtype*/)
return "Boolean";
case SOCK_ROTATION:
return "Rotation";
case SOCK_MATRIX:
return "Matrix";
case SOCK_VECTOR:
return "Vector";
case SOCK_RGBA:
@ -2756,6 +2769,9 @@ static void *socket_value_storage(bNodeSocket &socket)
return &socket.default_value_typed<bNodeSocketValueRotation>()->value_euler;
case SOCK_MENU:
return &socket.default_value_typed<bNodeSocketValueMenu>()->value;
case SOCK_MATRIX:
/* Matrix sockets currently have no default value. */
return nullptr;
case SOCK_STRING:
/* We don't want do this now! */
return nullptr;
@ -4344,6 +4360,8 @@ std::optional<eCustomDataType> socket_type_to_custom_data_type(eNodeSocketDataty
return CD_PROP_BOOL;
case SOCK_ROTATION:
return CD_PROP_QUATERNION;
case SOCK_MATRIX:
return CD_PROP_FLOAT4X4;
case SOCK_INT:
return CD_PROP_INT32;
case SOCK_STRING:
@ -4372,6 +4390,8 @@ std::optional<eNodeSocketDatatype> custom_data_type_to_socket_type(eCustomDataTy
return SOCK_RGBA;
case CD_PROP_QUATERNION:
return SOCK_ROTATION;
case CD_PROP_FLOAT4X4:
return SOCK_MATRIX;
default:
return std::nullopt;
}
@ -4434,6 +4454,9 @@ std::optional<eNodeSocketDatatype> geo_nodes_base_cpp_type_to_socket_type(const
if (type.is<math::Quaternion>()) {
return SOCK_ROTATION;
}
if (type.is<float4x4>()) {
return SOCK_MATRIX;
}
if (type.is<std::string>()) {
return SOCK_STRING;
}

View File

@ -54,6 +54,9 @@ template<typename T> static std::optional<eNodeSocketDatatype> static_type_to_so
if constexpr (is_single_or_field_or_grid_v<T, math::Quaternion>) {
return SOCK_ROTATION;
}
if constexpr (is_same_any_v<T, float4x4, fn::Field<float4x4>>) {
return SOCK_MATRIX;
}
if constexpr (is_same_any_v<T, std::string>) {
return SOCK_STRING;
}
@ -195,6 +198,10 @@ void SocketValueVariant::store_single(const eNodeSocketDatatype socket_type, con
value_.emplace<math::Quaternion>(*static_cast<const math::Quaternion *>(value));
break;
}
case SOCK_MATRIX: {
value_.emplace<float4x4>(*static_cast<const float4x4 *>(value));
break;
}
case SOCK_RGBA: {
value_.emplace<ColorGeometry4f>(*static_cast<const ColorGeometry4f *>(value));
break;
@ -281,6 +288,8 @@ void *SocketValueVariant::allocate_single(const eNodeSocketDatatype socket_type)
return value_.allocate<bool>();
case SOCK_ROTATION:
return value_.allocate<math::Quaternion>();
case SOCK_MATRIX:
return value_.allocate<float4x4>();
case SOCK_RGBA:
return value_.allocate<ColorGeometry4f>();
case SOCK_STRING:
@ -344,6 +353,9 @@ INSTANTIATE_SINGLE_AND_FIELD_AND_GRID(blender::math::Quaternion)
INSTANTIATE(std::string)
INSTANTIATE(fn::GField)
INSTANTIATE(float4x4)
INSTANTIATE(fn::Field<float4x4>)
#ifdef WITH_OPENVDB
INSTANTIATE(GVolumeGrid)
#endif

View File

@ -349,11 +349,21 @@ static ColorGeometry4f byte_color_to_color(const ColorGeometry4b &a)
return a.decode();
}
static math::Quaternion float4x4_to_quaternion(const float4x4 &a)
{
return math::to_quaternion(a);
}
static float3 quaternion_to_float3(const math::Quaternion &a)
{
return float3(math::to_euler(a).xyz());
}
static float4x4 quaternion_to_float4x4(const math::Quaternion &a)
{
return math::from_rotation<float4x4>(a);
}
static DataTypeConversions create_implicit_conversions()
{
DataTypeConversions conversions;
@ -441,7 +451,10 @@ static DataTypeConversions create_implicit_conversions()
add_implicit_conversion<ColorGeometry4b, float3, byte_color_to_float3>(conversions);
add_implicit_conversion<ColorGeometry4b, ColorGeometry4f, byte_color_to_color>(conversions);
add_implicit_conversion<float4x4, math::Quaternion, float4x4_to_quaternion>(conversions);
add_implicit_conversion<math::Quaternion, float3, quaternion_to_float3>(conversions);
add_implicit_conversion<math::Quaternion, float4x4, quaternion_to_float4x4>(conversions);
return conversions;
}

View File

@ -23,11 +23,13 @@ GPUVertFormat init_format_for_attribute(const eCustomDataType data_type,
bke::attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
using Converter = AttributeConverter<T>;
GPU_vertformat_attr_add(&format,
vbo_name.c_str(),
Converter::gpu_component_type,
Converter::gpu_component_len,
Converter::gpu_fetch_mode);
if constexpr (!std::is_void_v<typename Converter::VBOType>) {
GPU_vertformat_attr_add(&format,
vbo_name.c_str(),
Converter::gpu_component_type,
Converter::gpu_component_len,
Converter::gpu_fetch_mode);
}
});
return format;
}
@ -38,18 +40,20 @@ void vertbuf_data_extract_direct(const GSpan attribute, GPUVertBuf &vbo)
using T = decltype(dummy);
using Converter = AttributeConverter<T>;
using VBOType = typename Converter::VBOType;
const Span<T> src = attribute.typed<T>();
MutableSpan<VBOType> data(static_cast<VBOType *>(GPU_vertbuf_get_data(&vbo)),
attribute.size());
if constexpr (std::is_same_v<T, VBOType>) {
array_utils::copy(src, data);
}
else {
threading::parallel_for(src.index_range(), 8192, [&](const IndexRange range) {
for (const int i : range) {
data[i] = Converter::convert(src[i]);
}
});
if constexpr (!std::is_void_v<VBOType>) {
const Span<T> src = attribute.typed<T>();
MutableSpan<VBOType> data(static_cast<VBOType *>(GPU_vertbuf_get_data(&vbo)),
attribute.size());
if constexpr (std::is_same_v<T, VBOType>) {
array_utils::copy(src, data);
}
else {
threading::parallel_for(src.index_range(), 8192, [&](const IndexRange range) {
for (const int i : range) {
data[i] = Converter::convert(src[i]);
}
});
}
}
});
}

View File

@ -582,9 +582,11 @@ struct PBVHBatches {
using T = decltype(dummy);
using Converter = AttributeConverter<T>;
using VBOType = typename Converter::VBOType;
std::fill_n(static_cast<VBOType *>(GPU_vertbuf_get_data(vbo.vert_buf)),
GPU_vertbuf_get_vertex_len(vbo.vert_buf),
VBOType());
if constexpr (!std::is_void_v<VBOType>) {
std::fill_n(static_cast<VBOType *>(GPU_vertbuf_get_data(vbo.vert_buf)),
GPU_vertbuf_get_vertex_len(vbo.vert_buf),
VBOType());
}
});
}
}
@ -754,18 +756,20 @@ struct PBVHBatches {
const GVArraySpan attribute = *attributes.lookup_or_default(name, domain, data_type);
bke::attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
switch (domain) {
case bke::AttrDomain::Point:
extract_data_vert_faces<T>(args, attribute.typed<T>(), vert_buf);
break;
case bke::AttrDomain::Face:
extract_data_face_faces<T>(args, attribute.typed<T>(), vert_buf);
break;
case bke::AttrDomain::Corner:
extract_data_corner_faces<T>(args, attribute.typed<T>(), vert_buf);
break;
default:
BLI_assert_unreachable();
if constexpr (!std::is_void_v<typename AttributeConverter<T>::VBOType>) {
switch (domain) {
case bke::AttrDomain::Point:
extract_data_vert_faces<T>(args, attribute.typed<T>(), vert_buf);
break;
case bke::AttrDomain::Face:
extract_data_face_faces<T>(args, attribute.typed<T>(), vert_buf);
break;
case bke::AttrDomain::Corner:
extract_data_corner_faces<T>(args, attribute.typed<T>(), vert_buf);
break;
default:
BLI_assert_unreachable();
}
}
});
}
@ -920,18 +924,20 @@ struct PBVHBatches {
const int cd_offset = CustomData_get_offset_named(&custom_data, data_type, request.name);
bke::attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
switch (domain) {
case bke::AttrDomain::Point:
extract_data_vert_bmesh<T>(args, cd_offset, *vbo.vert_buf);
break;
case bke::AttrDomain::Face:
extract_data_face_bmesh<T>(args, cd_offset, *vbo.vert_buf);
break;
case bke::AttrDomain::Corner:
extract_data_corner_bmesh<T>(args, cd_offset, *vbo.vert_buf);
break;
default:
BLI_assert_unreachable();
if constexpr (!std::is_void_v<typename AttributeConverter<T>::VBOType>) {
switch (domain) {
case bke::AttrDomain::Point:
extract_data_vert_bmesh<T>(args, cd_offset, *vbo.vert_buf);
break;
case bke::AttrDomain::Face:
extract_data_face_bmesh<T>(args, cd_offset, *vbo.vert_buf);
break;
case bke::AttrDomain::Corner:
extract_data_corner_bmesh<T>(args, cd_offset, *vbo.vert_buf);
break;
default:
BLI_assert_unreachable();
}
}
});
}

View File

@ -199,21 +199,23 @@ static void extract_attribute(const MeshRenderData &mr,
bke::attribute_math::convert_to_static_type(request.cd_type, [&](auto dummy) {
using T = decltype(dummy);
switch (request.domain) {
case bke::AttrDomain::Point:
extract_data_bmesh_vert<T>(*mr.bm, cd_offset, vbo);
break;
case bke::AttrDomain::Edge:
extract_data_bmesh_edge<T>(*mr.bm, cd_offset, vbo);
break;
case bke::AttrDomain::Face:
extract_data_bmesh_face<T>(*mr.bm, cd_offset, vbo);
break;
case bke::AttrDomain::Corner:
extract_data_bmesh_loop<T>(*mr.bm, cd_offset, vbo);
break;
default:
BLI_assert_unreachable();
if constexpr (!std::is_void_v<typename AttributeConverter<T>::VBOType>) {
switch (request.domain) {
case bke::AttrDomain::Point:
extract_data_bmesh_vert<T>(*mr.bm, cd_offset, vbo);
break;
case bke::AttrDomain::Edge:
extract_data_bmesh_edge<T>(*mr.bm, cd_offset, vbo);
break;
case bke::AttrDomain::Face:
extract_data_bmesh_face<T>(*mr.bm, cd_offset, vbo);
break;
case bke::AttrDomain::Corner:
extract_data_bmesh_loop<T>(*mr.bm, cd_offset, vbo);
break;
default:
BLI_assert_unreachable();
}
}
});
}
@ -225,21 +227,23 @@ static void extract_attribute(const MeshRenderData &mr,
bke::attribute_math::convert_to_static_type(request.cd_type, [&](auto dummy) {
using T = decltype(dummy);
switch (request.domain) {
case bke::AttrDomain::Point:
extract_data_mesh_mapped_corner(attribute.typed<T>(), mr.corner_verts, vbo);
break;
case bke::AttrDomain::Edge:
extract_data_mesh_mapped_corner(attribute.typed<T>(), mr.corner_edges, vbo);
break;
case bke::AttrDomain::Face:
extract_data_mesh_face(mr.faces, attribute.typed<T>(), vbo);
break;
case bke::AttrDomain::Corner:
vertbuf_data_extract_direct(attribute.typed<T>(), vbo);
break;
default:
BLI_assert_unreachable();
if constexpr (!std::is_void_v<typename AttributeConverter<T>::VBOType>) {
switch (request.domain) {
case bke::AttrDomain::Point:
extract_data_mesh_mapped_corner(attribute.typed<T>(), mr.corner_verts, vbo);
break;
case bke::AttrDomain::Edge:
extract_data_mesh_mapped_corner(attribute.typed<T>(), mr.corner_edges, vbo);
break;
case bke::AttrDomain::Face:
extract_data_mesh_face(mr.faces, attribute.typed<T>(), vbo);
break;
case bke::AttrDomain::Corner:
vertbuf_data_extract_direct(attribute.typed<T>(), vbo);
break;
default:
BLI_assert_unreachable();
}
}
});
}
@ -282,12 +286,14 @@ static void extract_attr_init_subdiv(const DRWSubdivCache &subdiv_cache,
bke::attribute_math::convert_to_static_type(request.cd_type, [&](auto dummy) {
using T = decltype(dummy);
using Converter = AttributeConverter<T>;
draw_subdiv_interp_custom_data(subdiv_cache,
src_data,
dst_buffer,
Converter::gpu_component_type,
Converter::gpu_component_len,
0);
if constexpr (!std::is_void_v<typename Converter::VBOType>) {
draw_subdiv_interp_custom_data(subdiv_cache,
src_data,
dst_buffer,
Converter::gpu_component_type,
Converter::gpu_component_len,
0);
}
});
GPU_vertbuf_discard(src_data);

View File

@ -1201,6 +1201,7 @@ static const float std_node_socket_colors[][4] = {
{0.92, 0.46, 0.51, 1.0}, /* SOCK_MATERIAL */
{0.65, 0.39, 0.78, 1.0}, /* SOCK_ROTATION */
{0.40, 0.40, 0.40, 1.0}, /* SOCK_MENU */
{0.72, 0.20, 0.52, 1.0}, /* SOCK_MATRIX */
};
/* Callback for colors that does not depend on the socket pointer argument to get the type. */
@ -1236,6 +1237,7 @@ static const SocketColorFn std_node_socket_color_funcs[] = {
std_node_socket_color_fn<SOCK_MATERIAL>,
std_node_socket_color_fn<SOCK_ROTATION>,
std_node_socket_color_fn<SOCK_MENU>,
std_node_socket_color_fn<SOCK_MATRIX>,
};
/* draw function for file output node sockets,
@ -1350,6 +1352,10 @@ static void std_node_socket_draw(
uiItemR(column, ptr, "default_value", DEFAULT_FLAGS, text, ICON_NONE);
break;
}
case SOCK_MATRIX: {
uiItemL(layout, text, ICON_NONE);
break;
}
case SOCK_RGBA: {
if (text[0] == '\0') {
uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, "", ICON_NONE);
@ -1528,6 +1534,7 @@ static void std_node_socket_interface_draw(ID *id,
}
case SOCK_SHADER:
case SOCK_GEOMETRY:
case SOCK_MATRIX:
break;
case SOCK_CUSTOM:

View File

@ -1303,6 +1303,14 @@ static void create_inspection_string_for_generic_value(const bNodeSocket &socket
ss << fmt::format(TIP_("{} (Boolean)"),
((*static_cast<bool *>(socket_value)) ? TIP_("True") : TIP_("False")));
}
else if (socket_type.is<float4x4>()) {
const float4x4 &value = *static_cast<const float4x4 *>(socket_value);
ss << value[0] << ",\n";
ss << value[1] << ",\n";
ss << value[2] << ",\n";
ss << value[3] << ",\n";
ss << TIP_("(Matrix)");
}
}
static void create_inspection_string_for_field_info(const bNodeSocket &socket,

View File

@ -157,6 +157,7 @@ static eCustomDataType data_type_in_attribute_input_node(const eCustomDataType t
case CD_PROP_COLOR:
case CD_PROP_BOOL:
case CD_PROP_QUATERNION:
case CD_PROP_FLOAT4X4:
return type;
case CD_PROP_BYTE_COLOR:
return CD_PROP_COLOR;

View File

@ -2230,6 +2230,7 @@ static int get_main_socket_priority(const bNodeSocket *socket)
case SOCK_OBJECT:
case SOCK_IMAGE:
case SOCK_ROTATION:
case SOCK_MATRIX:
case SOCK_GEOMETRY:
case SOCK_COLLECTION:
case SOCK_TEXTURE:

View File

@ -391,6 +391,9 @@ static Vector<NodeLinkItem> ui_node_link_items(NodeLinkArg *arg,
else if (dynamic_cast<const decl::Rotation *>(&socket_decl)) {
item.socket_type = SOCK_ROTATION;
}
else if (dynamic_cast<const decl::Matrix *>(&socket_decl)) {
item.socket_type = SOCK_MATRIX;
}
else if (dynamic_cast<const decl::String *>(&socket_decl)) {
item.socket_type = SOCK_STRING;
}

View File

@ -339,6 +339,7 @@ static float get_default_column_width(const ColumnValues &values)
static const float float_width = 3;
switch (values.type()) {
case SPREADSHEET_VALUE_TYPE_BOOL:
case SPREADSHEET_VALUE_TYPE_FLOAT4X4:
return 2.0f;
case SPREADSHEET_VALUE_TYPE_INT8:
case SPREADSHEET_VALUE_TYPE_INT32:

View File

@ -60,6 +60,9 @@ eSpreadsheetColumnValueType cpp_type_to_column_type(const CPPType &type)
if (type.is<math::Quaternion>()) {
return SPREADSHEET_VALUE_TYPE_QUATERNION;
}
if (type.is<float4x4>()) {
return SPREADSHEET_VALUE_TYPE_FLOAT4X4;
}
return SPREADSHEET_VALUE_TYPE_UNKNOWN;
}

View File

@ -209,6 +209,9 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
const float4 value = float4(data.get<math::Quaternion>(real_index));
this->draw_float_vector(params, Span(&value.x, 4));
}
else if (data.type().is<float4x4>()) {
this->draw_float4x4(params, data.get<float4x4>(real_index));
}
else if (data.type().is<bke::InstanceReference>()) {
const bke::InstanceReference value = data.get<bke::InstanceReference>(real_index);
switch (value.type()) {
@ -398,6 +401,40 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
}
}
void draw_float4x4(const CellDrawParams &params, const float4x4 &value) const
{
uiBut *but = uiDefIconTextBut(params.block,
UI_BTYPE_LABEL,
0,
ICON_NONE,
"...",
params.xmin,
params.ymin,
params.width,
params.height,
nullptr,
0,
0,
0,
0,
nullptr);
/* Center alignment. */
UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT);
UI_but_func_tooltip_set(
but,
[](bContext * /*C*/, void *argN, const char * /*tip*/) {
const float4x4 &value = *static_cast<const float4x4 *>(argN);
std::stringstream ss;
ss << value[0] << ",\n";
ss << value[1] << ",\n";
ss << value[2] << ",\n";
ss << value[3];
return ss.str();
},
MEM_new<float4x4>(__func__, value),
MEM_freeN);
}
int column_width(int column_index) const final
{
return spreadsheet_layout_.columns[column_index].width;

View File

@ -109,6 +109,7 @@ static std::string value_string(const SpreadsheetRowFilter &row_filter,
case SPREADSHEET_VALUE_TYPE_STRING:
return row_filter.value_string;
case SPREADSHEET_VALUE_TYPE_QUATERNION:
case SPREADSHEET_VALUE_TYPE_FLOAT4X4:
case SPREADSHEET_VALUE_TYPE_UNKNOWN:
return "";
}
@ -253,6 +254,7 @@ static void spreadsheet_filter_panel_draw(const bContext *C, Panel *panel)
break;
case SPREADSHEET_VALUE_TYPE_UNKNOWN:
case SPREADSHEET_VALUE_TYPE_QUATERNION:
case SPREADSHEET_VALUE_TYPE_FLOAT4X4:
uiItemL(layout, IFACE_("Unsupported column type"), ICON_ERROR);
break;
}

View File

@ -138,7 +138,7 @@ typedef enum eCustomDataType {
CD_PROP_BYTE_COLOR = 17,
CD_TANGENT = 18,
CD_MDISPS = 19,
/* CD_PREVIEW_MCOL = 20, */ /* UNUSED */
CD_PROP_FLOAT4X4 = 20,
/* CD_ID_MCOL = 21, */
/* CD_TEXTURE_MLOOPCOL = 22, */ /* UNUSED */
CD_CLOTH_ORCO = 23,
@ -230,6 +230,7 @@ using eCustomDataMask = uint64_t;
#define CD_MASK_PROP_INT8 (1ULL << CD_PROP_INT8)
#define CD_MASK_PROP_INT32_2D (1ULL << CD_PROP_INT32_2D)
#define CD_MASK_PROP_QUATERNION (1ULL << CD_PROP_QUATERNION)
#define CD_MASK_PROP_FLOAT4X4 (1ULL << CD_PROP_FLOAT4X4)
/** Multi-resolution loop data. */
#define CD_MASK_MULTIRES_GRIDS (CD_MASK_MDISPS | CD_GRID_PAINT_MASK)
@ -241,7 +242,7 @@ using eCustomDataMask = uint64_t;
#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_INT32_2D | CD_MASK_PROP_QUATERNION)
CD_MASK_PROP_INT8 | CD_MASK_PROP_INT32_2D | CD_MASK_PROP_QUATERNION | CD_MASK_PROP_FLOAT4X4)
/* All color attributes */
#define CD_MASK_COLOR_ALL (CD_MASK_PROP_COLOR | CD_MASK_PROP_BYTE_COLOR)

View File

@ -263,6 +263,7 @@ typedef enum eNodeSocketDatatype {
SOCK_MATERIAL = 13,
SOCK_ROTATION = 14,
SOCK_MENU = 15,
SOCK_MATRIX = 16,
} eNodeSocketDatatype;
/** Socket shape. */

View File

@ -2037,6 +2037,7 @@ typedef enum eSpreadsheetColumnValueType {
SPREADSHEET_VALUE_TYPE_INT8 = 9,
SPREADSHEET_VALUE_TYPE_INT32_2D = 10,
SPREADSHEET_VALUE_TYPE_QUATERNION = 11,
SPREADSHEET_VALUE_TYPE_FLOAT4X4 = 12,
} eSpreadsheetColumnValueType;
/**

View File

@ -716,12 +716,13 @@ typedef struct UserDef_Experimental {
char use_extended_asset_browser;
char use_sculpt_texture_paint;
char use_grease_pencil_version3;
char use_new_matrix_socket;
char enable_overlay_next;
char use_new_volume_nodes;
char use_shader_node_previews;
char use_extension_repos;
char _pad[4];
char _pad[3];
/** `makesdna` does not allow empty structs. */
} UserDef_Experimental;

View File

@ -49,6 +49,10 @@ typedef struct vec4i {
typedef struct vec4f {
float x, y, z, w;
} vec4f;
typedef struct mat4x4f {
float value[4][4];
} mat4x4f;
/*
typedef struct vec4d {
double x, y, z, w;

View File

@ -47,6 +47,7 @@ const EnumPropertyItem rna_enum_attribute_type_items[] = {
{CD_PROP_INT8, "INT8", 0, "8-Bit Integer", "Smaller integer with a range from -128 to 127"},
{CD_PROP_INT32_2D, "INT32_2D", 0, "2D Integer Vector", "32-bit signed integer vector"},
{CD_PROP_QUATERNION, "QUATERNION", 0, "Quaternion", "Floating point quaternion rotation"},
{CD_PROP_FLOAT4X4, "FLOAT4X4", 0, "4x4 Matrix", "Floating point matrix"},
{0, nullptr, 0, nullptr, nullptr},
};
@ -76,6 +77,7 @@ const EnumPropertyItem rna_enum_attribute_type_with_auto_items[] = {
{CD_PROP_FLOAT2, "FLOAT2", 0, "2D Vector", "2D vector with floating-point values"},
{CD_PROP_INT32_2D, "INT32_2D", 0, "2D Integer Vector", "32-bit signed integer vector"},
{CD_PROP_QUATERNION, "QUATERNION", 0, "Quaternion", "Floating point quaternion rotation"},
{CD_PROP_FLOAT4X4, "FLOAT4X4", 0, "4x4 Matrix", "Floating point matrix"},
{0, nullptr, 0, nullptr, nullptr},
};
@ -207,6 +209,8 @@ static StructRNA *srna_by_custom_data_layer_type(const eCustomDataType type)
return &RNA_Int2Attribute;
case CD_PROP_QUATERNION:
return &RNA_QuaternionAttribute;
case CD_PROP_FLOAT4X4:
return &RNA_Float4x4Attribute;
default:
return nullptr;
}
@ -1096,6 +1100,40 @@ static void rna_def_attribute_quaternion(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Attribute_update_data");
}
static void rna_def_attribute_float4x4(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "Float4x4Attribute", "Attribute");
RNA_def_struct_sdna(srna, "CustomDataLayer");
RNA_def_struct_ui_text(
srna, "4x4 Matrix Attribute", "Geometry attribute that stores a 4 by 4 float matrix");
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "Float4x4AttributeValue");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_collection_funcs(prop,
"rna_Attribute_data_begin",
"rna_iterator_array_next",
"rna_iterator_array_end",
"rna_iterator_array_get",
"rna_Attribute_data_length",
nullptr,
nullptr,
nullptr);
srna = RNA_def_struct(brna, "Float4x4AttributeValue", nullptr);
RNA_def_struct_sdna(srna, "mat4x4f");
RNA_def_struct_ui_text(srna, "Matrix Attribute Value", "Matrix value in geometry attribute");
prop = RNA_def_property(srna, "value", PROP_FLOAT, PROP_MATRIX);
RNA_def_property_ui_text(prop, "Value", "Matrix");
RNA_def_property_float_sdna(prop, nullptr, "value");
RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4);
RNA_def_property_update(prop, 0, "rna_Attribute_update_data");
}
static void rna_def_attribute_float2(BlenderRNA *brna)
{
StructRNA *srna;
@ -1182,6 +1220,7 @@ static void rna_def_attribute(BlenderRNA *brna)
rna_def_attribute_int(brna);
rna_def_attribute_int2(brna);
rna_def_attribute_quaternion(brna);
rna_def_attribute_float4x4(brna);
rna_def_attribute_string(brna);
rna_def_attribute_bool(brna);
rna_def_attribute_float2(brna);

View File

@ -25,6 +25,7 @@ const EnumPropertyItem rna_enum_node_socket_type_items[] = {
{SOCK_BOOLEAN, "BOOLEAN", 0, "Boolean", ""},
{SOCK_VECTOR, "VECTOR", 0, "Vector", ""},
{SOCK_ROTATION, "ROTATION", 0, "Rotation", ""},
{SOCK_MATRIX, "MATRIX", 0, "Matrix", ""},
{SOCK_STRING, "STRING", 0, "String", ""},
{SOCK_RGBA, "RGBA", 0, "RGBA", ""},
{SOCK_SHADER, "SHADER", 0, "Shader", ""},
@ -1011,6 +1012,30 @@ static void rna_def_node_socket_interface_rotation(BlenderRNA *brna, const char
rna_def_node_tree_interface_socket_builtin(srna);
}
static void rna_def_node_socket_matrix(BlenderRNA *brna, const char *identifier)
{
StructRNA *srna;
srna = RNA_def_struct(brna, identifier, "NodeSocketStandard");
RNA_def_struct_ui_text(srna, "Matrix Node Socket", "Matrix value socket of a node");
RNA_def_struct_sdna(srna, "bNodeSocket");
RNA_def_struct_sdna_from(srna, "bNodeSocket", nullptr);
}
static void rna_def_node_socket_interface_matrix(BlenderRNA *brna, const char *identifier)
{
StructRNA *srna;
srna = RNA_def_struct(brna, identifier, "NodeTreeInterfaceSocket");
RNA_def_struct_ui_text(srna, "Matrix Node Socket Interface", "Matrix value socket of a node");
RNA_def_struct_sdna(srna, "bNodeTreeInterfaceSocket");
RNA_def_struct_sdna_from(srna, "bNodeTreeInterfaceSocket", nullptr);
rna_def_node_tree_interface_socket_builtin(srna);
}
static void rna_def_node_socket_vector(BlenderRNA *brna,
const char *identifier,
PropertySubType subtype)
@ -1528,6 +1553,7 @@ static const bNodeSocketStaticTypeInfo node_socket_subtypes[] = {
{"NodeSocketIntFactor", "NodeTreeInterfaceSocketIntFactor", SOCK_INT, PROP_FACTOR},
{"NodeSocketBool", "NodeTreeInterfaceSocketBool", SOCK_BOOLEAN, PROP_NONE},
{"NodeSocketRotation", "NodeTreeInterfaceSocketRotation", SOCK_ROTATION, PROP_NONE},
{"NodeSocketMatrix", "NodeTreeInterfaceSocketMatrix", SOCK_MATRIX, PROP_NONE},
{"NodeSocketVector", "NodeTreeInterfaceSocketVector", SOCK_VECTOR, PROP_NONE},
{"NodeSocketVectorTranslation",
"NodeTreeInterfaceSocketVectorTranslation",
@ -1577,6 +1603,9 @@ static void rna_def_node_socket_subtypes(BlenderRNA *brna)
case SOCK_ROTATION:
rna_def_node_socket_rotation(brna, identifier);
break;
case SOCK_MATRIX:
rna_def_node_socket_matrix(brna, identifier);
break;
case SOCK_VECTOR:
rna_def_node_socket_vector(brna, identifier, info.subtype);
break;
@ -1640,6 +1669,9 @@ void rna_def_node_socket_interface_subtypes(BlenderRNA *brna)
case SOCK_ROTATION:
rna_def_node_socket_interface_rotation(brna, identifier);
break;
case SOCK_MATRIX:
rna_def_node_socket_interface_matrix(brna, identifier);
break;
case SOCK_VECTOR:
rna_def_node_socket_interface_vector(brna, identifier, info.subtype);
break;

View File

@ -77,6 +77,7 @@ const EnumPropertyItem rna_enum_node_socket_data_type_items[] = {
{SOCK_BOOLEAN, "BOOLEAN", 0, "Boolean", ""},
{SOCK_VECTOR, "VECTOR", 0, "Vector", ""},
{SOCK_ROTATION, "ROTATION", 0, "Rotation", ""},
{SOCK_MATRIX, "MATRIX", 0, "Matrix", ""},
{SOCK_STRING, "STRING", 0, "String", ""},
{SOCK_MENU, "MENU", 0, "Menu", ""},
{SOCK_RGBA, "RGBA", 0, "Color", ""},
@ -1894,7 +1895,8 @@ static bool generic_attribute_type_supported(const EnumPropertyItem *item)
CD_PROP_BOOL,
CD_PROP_INT32,
CD_PROP_BYTE_COLOR,
CD_PROP_QUATERNION);
CD_PROP_QUATERNION,
CD_PROP_FLOAT4X4);
}
static bool generic_attribute_type_supported_with_socket(const EnumPropertyItem *item)

View File

@ -7120,6 +7120,12 @@ static void rna_def_userdef_experimental(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, 0, "rna_userdef_keyconfig_reload_update");
prop = RNA_def_property(srna, "use_new_matrix_socket", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "use_new_matrix_socket", 1);
RNA_def_property_ui_text(
prop, "Matrix Socket", "Enable the matrix socket type for geometry nodes");
RNA_def_property_update(prop, 0, "rna_userdef_ui_update");
prop = RNA_def_property(srna, "use_viewport_debug", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "use_viewport_debug", 1);
RNA_def_property_ui_text(prop,

View File

@ -824,7 +824,7 @@ static void check_property_socket_sync(const Object *ob, ModifierData *md)
IDProperty *property = IDP_GetPropertyFromGroup(nmd->settings.properties, socket->identifier);
if (property == nullptr) {
if (type == SOCK_GEOMETRY) {
if (ELEM(type, SOCK_GEOMETRY, SOCK_MATRIX)) {
geometry_socket_count++;
}
else {

View File

@ -87,8 +87,15 @@ class GeoNodeExecParams {
}
template<typename T>
static inline constexpr bool is_field_base_type_v =
is_same_any_v<T, float, int, bool, ColorGeometry4f, float3, std::string, math::Quaternion>;
static inline constexpr bool is_field_base_type_v = is_same_any_v<T,
float,
int,
bool,
ColorGeometry4f,
float3,
std::string,
math::Quaternion,
float4x4>;
template<typename T>
static inline constexpr bool stored_as_SocketValueVariant_v =

View File

@ -158,6 +158,22 @@ class RotationBuilder : public SocketDeclarationBuilder<Rotation> {
RotationBuilder &default_value(const math::EulerXYZ &value);
};
class MatrixBuilder;
class Matrix : public SocketDeclaration {
public:
friend MatrixBuilder;
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> {};
class StringBuilder;
class String : public SocketDeclaration {

View File

@ -267,6 +267,7 @@ DefNode(FunctionNode, FN_NODE_AXIS_ANGLE_TO_ROTATION, 0, "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_COMBINE_TRANSFORM, 0, "COMBINE_TRANSFORM", CombineTransform, "Combine Transform", "")
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", "")
@ -276,7 +277,9 @@ 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_MATRIX, 0, "INVERT_MATRIX", InvertMatrix, "Invert Matrix", "")
DefNode(FunctionNode, FN_NODE_INVERT_ROTATION, 0, "INVERT_ROTATION", InvertRotation, "Invert Rotation", "")
DefNode(FunctionNode, FN_NODE_MATRIX_MULTIPLY, 0, "MATRIX_MULTIPLY", MatrixMultiply, "Multiply Matrices", "")
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", "")
@ -286,8 +289,12 @@ DefNode(FunctionNode, FN_NODE_ROTATION_TO_AXIS_ANGLE, 0, "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_SEPARATE_TRANSFORM, 0, "SEPARATE_TRANSFORM", SeparateTransform, "Separate Transform", "")
DefNode(FunctionNode, FN_NODE_SLICE_STRING, 0, "SLICE_STRING", SliceString, "Slice String", "")
DefNode(FunctionNode, FN_NODE_STRING_LENGTH, 0, "STRING_LENGTH", StringLength, "String Length", "")
DefNode(FunctionNode, FN_NODE_TRANSFORM_DIRECTION, 0, "TRANSFORM_DIRECTION", TransformDirection, "Transform Direction", "")
HooglyBoogly marked this conversation as resolved Outdated

Some missing renames.

Some missing renames.
DefNode(FunctionNode, FN_NODE_TRANSFORM_POINT, 0, "TRANSFORM_POINT", TransformPoint, "Transform Point", "")
DefNode(FunctionNode, FN_NODE_TRANSPOSE_MATRIX, 0, "TRANSPOSE_MATRIX", TransposeMatrix, "Transpose Matrix", "")
DefNode(FunctionNode, FN_NODE_VALUE_TO_STRING, 0, "VALUE_TO_STRING", ValueToString, "Value to String", "")
DefNode(GeometryNode, GEO_NODE_ACCUMULATE_FIELD, 0, "ACCUMULATE_FIELD", AccumulateField, "Accumulate Field", "Add the values of an evaluated field together and output the running total for each element")

View File

@ -51,12 +51,16 @@ struct SimulationItemsAccessor {
}
static bool supports_socket_type(const eNodeSocketDatatype socket_type)
{
if (socket_type == SOCK_MATRIX) {
return U.experimental.use_new_matrix_socket;
}
return ELEM(socket_type,
SOCK_FLOAT,
SOCK_VECTOR,
SOCK_RGBA,
SOCK_BOOLEAN,
SOCK_ROTATION,
SOCK_MATRIX,
SOCK_INT,
SOCK_STRING,
SOCK_GEOMETRY);
@ -115,12 +119,16 @@ struct RepeatItemsAccessor {
}
static bool supports_socket_type(const eNodeSocketDatatype socket_type)
{
if (socket_type == SOCK_MATRIX) {
return U.experimental.use_new_matrix_socket;
}
return ELEM(socket_type,
SOCK_FLOAT,
SOCK_VECTOR,
SOCK_RGBA,
SOCK_BOOLEAN,
SOCK_ROTATION,
SOCK_MATRIX,
SOCK_INT,
SOCK_STRING,
SOCK_GEOMETRY,

View File

@ -31,7 +31,10 @@ 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_matrix.cc
nodes/node_fn_invert_rotation.cc
nodes/node_fn_combine_transform.cc
nodes/node_fn_matrix_multiply.cc
nodes/node_fn_quaternion_to_rotation.cc
nodes/node_fn_random_value.cc
nodes/node_fn_replace_string.cc
@ -42,8 +45,12 @@ set(SRC
nodes/node_fn_rotation_to_euler.cc
nodes/node_fn_rotation_to_quaternion.cc
nodes/node_fn_separate_color.cc
nodes/node_fn_separate_transform.cc
nodes/node_fn_slice_string.cc
nodes/node_fn_string_length.cc
nodes/node_fn_transform_direction.cc
nodes/node_fn_transform_point.cc
nodes/node_fn_transpose_matrix.cc
nodes/node_fn_value_to_string.cc
node_function_util.cc

View File

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

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

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

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

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

Unless I can prove it's faster I don't think this is worth it.
}
else if (no_translation && no_scale) {
mask.foreach_index(
[&](const int64_t i) { transforms[i] = math::from_rotation<float4x4>(rotation[i]); });
}
else if (no_translation && no_rotation) {
mask.foreach_index(
[&](const int64_t i) { transforms[i] = math::from_scale<float4x4>(scale[i]); });
}
else {
mask.foreach_index([&](const int64_t i) {
transforms[i] = math::from_loc_rot_scale<float4x4>(location[i], rotation[i], scale[i]);
});
}
}
};
static void node_build_multi_function(NodeMultiFunctionBuilder &builder)
{
static CombineTransformFunction fn;
builder.set_matching_fn(fn);
}
static void node_register()
{
static bNodeType ntype;
fn_node_type_base(&ntype, FN_NODE_COMBINE_TRANSFORM, "Combine Transform", NODE_CLASS_CONVERTER);
ntype.declare = node_declare;
ntype.gather_link_search_ops = search_link_ops;
ntype.build_multi_function = node_build_multi_function;
nodeRegisterType(&ntype);
}
NOD_REGISTER_NODE(node_register)
} // namespace blender::nodes::node_fn_combine_transform_cc

View File

@ -0,0 +1,45 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_math_matrix.hh"
#include "NOD_socket_search_link.hh"
#include "node_function_util.hh"
namespace blender::nodes::node_fn_invert_matrix_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
b.add_input<decl::Matrix>("Matrix");
b.add_output<decl::Matrix>("Matrix");
}
static void search_link_ops(GatherLinkSearchOpParams &params)
{
if (U.experimental.use_new_matrix_socket) {
nodes::search_link_ops_for_basic_node(params);
}
}
static void node_build_multi_function(NodeMultiFunctionBuilder &builder)
{
static auto fn = mf::build::SI1_SO<float4x4, float4x4>(
"Invert Matrix", [](float4x4 matrix) { return math::invert(matrix); });
builder.set_matching_fn(fn);
}
static void node_register()
{
static bNodeType ntype;
fn_node_type_base(&ntype, FN_NODE_INVERT_MATRIX, "Invert Matrix", NODE_CLASS_CONVERTER);
ntype.declare = node_declare;
ntype.gather_link_search_ops = search_link_ops;
ntype.build_multi_function = node_build_multi_function;
nodeRegisterType(&ntype);
}
NOD_REGISTER_NODE(node_register)
} // namespace blender::nodes::node_fn_invert_matrix_cc

View File

@ -0,0 +1,46 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_math_matrix.hh"
#include "NOD_socket_search_link.hh"
#include "node_function_util.hh"
namespace blender::nodes::node_fn_matrix_multiply_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
b.add_input<decl::Matrix>("Matrix");
b.add_input<decl::Matrix>("Matrix", "Matrix_001");
b.add_output<decl::Matrix>("Matrix");
}
static void search_link_ops(GatherLinkSearchOpParams &params)
{
if (U.experimental.use_new_matrix_socket) {
nodes::search_link_ops_for_basic_node(params);
}
}
static void node_build_multi_function(NodeMultiFunctionBuilder &builder)
{
static auto fn = mf::build::SI2_SO<float4x4, float4x4, float4x4>(
"Multiply Matrices", [](float4x4 a, float4x4 b) { return a * b; });
builder.set_matching_fn(fn);
}
static void node_register()
{
static bNodeType ntype;
fn_node_type_base(&ntype, FN_NODE_MATRIX_MULTIPLY, "Multiply Matrices", NODE_CLASS_CONVERTER);
ntype.declare = node_declare;
ntype.gather_link_search_ops = search_link_ops;
ntype.build_multi_function = node_build_multi_function;
nodeRegisterType(&ntype);
}
NOD_REGISTER_NODE(node_register)
} // namespace blender::nodes::node_fn_matrix_multiply_cc

View File

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

View File

@ -0,0 +1,49 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_math_matrix.hh"
#include "NOD_socket_search_link.hh"
#include "node_function_util.hh"
namespace blender::nodes::node_fn_transform_direction_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
b.add_input<decl::Vector>("Direction").subtype(PROP_XYZ);
b.add_input<decl::Matrix>("Transform");
b.add_output<decl::Vector>("Direction").subtype(PROP_XYZ);
}
static void search_link_ops(GatherLinkSearchOpParams &params)
{
if (U.experimental.use_new_matrix_socket) {
nodes::search_link_ops_for_basic_node(params);
}
}
static void node_build_multi_function(NodeMultiFunctionBuilder &builder)
{
static auto fn = mf::build::SI2_SO<float3, float4x4, float3>(
"Transform Direction", [](float3 direction, float4x4 matrix) {
return math::transform_direction(matrix, direction);
});
builder.set_matching_fn(fn);
}
static void node_register()
{
static bNodeType ntype;
fn_node_type_base(
&ntype, FN_NODE_TRANSFORM_DIRECTION, "Transform Direction", NODE_CLASS_CONVERTER);
ntype.declare = node_declare;
ntype.gather_link_search_ops = search_link_ops;
ntype.build_multi_function = node_build_multi_function;
nodeRegisterType(&ntype);
}
NOD_REGISTER_NODE(node_register)
} // namespace blender::nodes::node_fn_transform_direction_cc

View File

@ -0,0 +1,47 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_math_matrix.hh"
#include "NOD_socket_search_link.hh"
#include "node_function_util.hh"
namespace blender::nodes::node_fn_transform_point_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
b.add_input<decl::Vector>("Vector").subtype(PROP_XYZ);
b.add_input<decl::Matrix>("Transform");
b.add_output<decl::Vector>("Vector").subtype(PROP_XYZ);
}
static void search_link_ops(GatherLinkSearchOpParams &params)
{
if (U.experimental.use_new_matrix_socket) {
nodes::search_link_ops_for_basic_node(params);
}
}
static void node_build_multi_function(NodeMultiFunctionBuilder &builder)
{
static auto fn = mf::build::SI2_SO<float3, float4x4, float3>(
"Transform Point",
[](float3 point, float4x4 matrix) { return math::transform_point(matrix, point); });
builder.set_matching_fn(fn);
}
static void node_register()
{
static bNodeType ntype;
fn_node_type_base(&ntype, FN_NODE_TRANSFORM_POINT, "Transform Point", NODE_CLASS_CONVERTER);
ntype.declare = node_declare;
ntype.gather_link_search_ops = search_link_ops;
ntype.build_multi_function = node_build_multi_function;
nodeRegisterType(&ntype);
}
NOD_REGISTER_NODE(node_register)
} // namespace blender::nodes::node_fn_transform_point_cc

View File

@ -0,0 +1,45 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_math_matrix.hh"
#include "NOD_socket_search_link.hh"
#include "node_function_util.hh"
namespace blender::nodes::node_fn_transpose_matrix_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
b.add_input<decl::Matrix>("Matrix");
b.add_output<decl::Matrix>("Matrix");
}
static void search_link_ops(GatherLinkSearchOpParams &params)
{
if (U.experimental.use_new_matrix_socket) {
nodes::search_link_ops_for_basic_node(params);
}
}
static void node_build_multi_function(NodeMultiFunctionBuilder &builder)
{
static auto fn = mf::build::SI1_SO<float4x4, float4x4>(
"Transpose Matrix", [](float4x4 matrix) { return math::transpose(matrix); });
builder.set_matching_fn(fn);
}
static void node_register()
{
static bNodeType ntype;
fn_node_type_base(&ntype, FN_NODE_TRANSPOSE_MATRIX, "Transpose Matrix", NODE_CLASS_CONVERTER);
ntype.declare = node_declare;
ntype.gather_link_search_ops = search_link_ops;
ntype.build_multi_function = node_build_multi_function;
nodeRegisterType(&ntype);
}
NOD_REGISTER_NODE(node_register)
} // namespace blender::nodes::node_fn_transpose_matrix_cc

View File

@ -96,6 +96,15 @@ static bool geometry_node_tree_validate_link(eNodeSocketDatatype type_a,
/* Floats and vectors implicitly convert to rotations. */
return true;
}
/* Support implicit conversions between matrices and rotations. */
if (type_a == SOCK_MATRIX && type_b == SOCK_ROTATION) {
return true;
}
if (type_a == SOCK_ROTATION && type_b == SOCK_MATRIX) {
return true;
}
if (type_a == SOCK_ROTATION && type_b == SOCK_VECTOR) {
/* Rotations implicitly convert to vectors. */
return true;
@ -106,12 +115,16 @@ static bool geometry_node_tree_validate_link(eNodeSocketDatatype type_a,
static bool geometry_node_tree_socket_type_valid(bNodeTreeType * /*treetype*/,
bNodeSocketType *socket_type)
{
if (socket_type->type == SOCK_MATRIX) {
return U.experimental.use_new_matrix_socket;
}
return blender::bke::nodeIsStaticSocketType(socket_type) && ELEM(socket_type->type,
SOCK_FLOAT,
SOCK_VECTOR,
SOCK_RGBA,
SOCK_BOOLEAN,
SOCK_ROTATION,
SOCK_MATRIX,
SOCK_INT,
SOCK_STRING,
SOCK_OBJECT,

View File

@ -50,6 +50,9 @@ const EnumPropertyItem *attribute_type_type_with_socket_fn(bContext * /*C*/,
bool generic_attribute_type_supported(const EnumPropertyItem &item)
{
if (item.value == SOCK_MATRIX) {
return U.experimental.use_new_matrix_socket;
}
return ELEM(item.value,
CD_PROP_FLOAT,
CD_PROP_FLOAT2,
@ -58,7 +61,8 @@ bool generic_attribute_type_supported(const EnumPropertyItem &item)
CD_PROP_BOOL,
CD_PROP_INT32,
CD_PROP_BYTE_COLOR,
CD_PROP_QUATERNION);
CD_PROP_QUATERNION,
CD_PROP_FLOAT4X4);
}
const EnumPropertyItem *domain_experimental_grease_pencil_version3_fn(bContext * /*C*/,

View File

@ -88,6 +88,10 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
/* Don't implement quaternion blurring for now. */
return;
}
if (fixed_data_type == CD_PROP_FLOAT4X4) {
/* Don't implement matrix blurring for now. */
return;
}
if (fixed_data_type == CD_PROP_BOOL) {
/* This node does not support boolean sockets, use integer instead. */
fixed_data_type = CD_PROP_INT32;

View File

@ -290,11 +290,15 @@ static void node_rna(StructRNA *srna)
*r_free = true;
return enum_items_filter(rna_enum_node_socket_data_type_items,
[](const EnumPropertyItem &item) -> bool {
if (item.value == SOCK_MATRIX) {
return U.experimental.use_new_matrix_socket;
}
return ELEM(item.value,
SOCK_FLOAT,
SOCK_INT,
SOCK_BOOLEAN,
SOCK_ROTATION,
SOCK_MATRIX,
SOCK_VECTOR,
SOCK_STRING,
SOCK_RGBA,

View File

@ -427,9 +427,9 @@ class LazyFunctionForSimulationOutputNode final : public LazyFunction {
Span<NodeSimulationItem> simulation_items_;
int skip_input_index_;
/**
* Start index of the simulation state inputs that are used when the simulation is skipped. Those
* inputs are linked directly to the simulation input node. Those inputs only exist internally,
* but not in the UI.
* Start index of the simulation state inputs that are used when the simulation is skipped.
* Those inputs are linked directly to the simulation input node. Those inputs only exist
* internally, but not in the UI.
*/
int skip_inputs_offset_;
/**
@ -648,8 +648,8 @@ class LazyFunctionForSimulationOutputNode final : public LazyFunction {
}
const bool skip = skip_variant->get<bool>();
/* Instead of outputting the values directly, convert them to a bake state and then back. This
* ensures that some geometry processing happens on the data consistently (e.g. removing
/* Instead of outputting the values directly, convert them to a bake state and then back.
* This ensures that some geometry processing happens on the data consistently (e.g. removing
* anonymous attributes). */
std::optional<bke::bake::BakeState> bake_state = this->get_bake_state_from_inputs(
params, data_block_map, skip);
@ -945,7 +945,8 @@ void mix_baked_data_item(const eNodeSocketDatatype socket_type,
case SOCK_INT:
case SOCK_BOOLEAN:
case SOCK_ROTATION:
case SOCK_RGBA: {
case SOCK_RGBA:
case SOCK_MATRIX: {
const CPPType &type = node_geo_simulation_cc::get_simulation_item_cpp_type(socket_type);
SocketValueVariant prev_value_variant = *static_cast<const SocketValueVariant *>(prev);
SocketValueVariant next_value_variant = *static_cast<const SocketValueVariant *>(next);

View File

@ -222,11 +222,15 @@ static void node_rna(StructRNA *srna)
*r_free = true;
return enum_items_filter(rna_enum_node_socket_data_type_items,
[](const EnumPropertyItem &item) -> bool {
if (item.value == SOCK_MATRIX) {
return U.experimental.use_new_matrix_socket;
}
return ELEM(item.value,
SOCK_FLOAT,
SOCK_INT,
SOCK_BOOLEAN,
SOCK_ROTATION,
SOCK_MATRIX,
SOCK_VECTOR,
SOCK_STRING,
SOCK_RGBA,

View File

@ -93,7 +93,6 @@ static bool node_needs_own_transform_relation(const bNode &node)
node.storage);
return storage.transform_space == GEO_NODE_TRANSFORM_SPACE_RELATIVE;
}
if (node.type == GEO_NODE_SELF_OBJECT) {
return true;
}
@ -346,6 +345,7 @@ std::unique_ptr<IDProperty, bke::idprop::IDPropertyDeleter> id_property_create_f
socket.socket_data);
return bke::idprop::create(identifier, reinterpret_cast<ID *>(value->value));
}
case SOCK_MATRIX:
case SOCK_CUSTOM:
case SOCK_GEOMETRY:
case SOCK_SHADER:
@ -387,6 +387,7 @@ bool id_property_type_matches_socket(const bNodeTreeInterfaceSocket &socket,
case SOCK_MATERIAL:
return property.type == IDP_ID;
case SOCK_CUSTOM:
case SOCK_MATRIX:
case SOCK_GEOMETRY:
case SOCK_SHADER:
return false;
@ -674,12 +675,15 @@ static Vector<OutputAttributeToStore> compute_attributes_to_store(
for (const OutputAttributeInfo &output_info : outputs_info) {
const CPPType &type = output_info.field.cpp_type();
const bke::AttributeValidator validator = attributes.lookup_validator(output_info.name);
OutputAttributeToStore store{
component_type,
domain,
output_info.name,
GMutableSpan{
type, MEM_malloc_arrayN(domain_size, type.size(), __func__), domain_size}};
type,
MEM_mallocN_aligned(type.size() * domain_size, type.alignment(), __func__),
domain_size}};
fn::GField field = validator.validate_field_if_necessary(output_info.field);
field_evaluator.add_with_destination(std::move(field), store.data);
attributes_to_store.append(store);
@ -868,7 +872,7 @@ void update_input_properties_from_node_tree(const bNodeTree &tree,
if (new_prop == nullptr) {
/* Out of the set of supported input sockets, only
* geometry sockets aren't added to the modifier. */
BLI_assert(socket_type == SOCK_GEOMETRY);
BLI_assert(ELEM(socket_type, SOCK_GEOMETRY, SOCK_MATRIX));
continue;
}

View File

@ -245,6 +245,11 @@ static SocketDeclarationPtr declaration_for_interface_socket(
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_INT: {
const auto &value = node_interface::get_socket_data_as<bNodeSocketValueInt>(io_socket);
std::unique_ptr<decl::Int> decl = std::make_unique<decl::Int>();

View File

@ -414,6 +414,8 @@ std::unique_ptr<SocketDeclaration> make_declaration_for_socket_type(
return std::make_unique<decl::Bool>();
case SOCK_ROTATION:
return std::make_unique<decl::Rotation>();
case SOCK_MATRIX:
return std::make_unique<decl::Matrix>();
case SOCK_INT:
return std::make_unique<decl::Int>();
case SOCK_STRING:
@ -449,6 +451,8 @@ BaseSocketDeclarationBuilder &NodeDeclarationBuilder::add_input(
return this->add_input<decl::Bool>(name, identifier);
case SOCK_ROTATION:
return this->add_input<decl::Rotation>(name, identifier);
case SOCK_MATRIX:
return this->add_input<decl::Matrix>(name, identifier);
case SOCK_INT:
return this->add_input<decl::Int>(name, identifier);
case SOCK_STRING:
@ -492,6 +496,8 @@ BaseSocketDeclarationBuilder &NodeDeclarationBuilder::add_output(
return this->add_output<decl::Bool>(name, identifier);
case SOCK_ROTATION:
return this->add_output<decl::Rotation>(name, identifier);
case SOCK_MATRIX:
return this->add_output<decl::Matrix>(name, identifier);
case SOCK_INT:
return this->add_output<decl::Int>(name, identifier);
case SOCK_STRING:

View File

@ -13,6 +13,8 @@
#include "BLI_color.hh"
#include "BLI_listbase.h"
#include "BLI_math_euler.hh"
#include "BLI_math_matrix.h"
#include "BLI_math_matrix.hh"
#include "BLI_math_quaternion_types.hh"
#include "BLI_math_vector.h"
#include "BLI_math_vector_types.hh"
@ -298,6 +300,9 @@ static std::optional<eNodeSocketDatatype> decl_to_data_type(const SocketDeclarat
else if (dynamic_cast<const decl::Rotation *>(&socket_decl)) {
return SOCK_ROTATION;
}
else if (dynamic_cast<const decl::Matrix *>(&socket_decl)) {
return SOCK_MATRIX;
}
else if (dynamic_cast<const decl::String *>(&socket_decl)) {
return SOCK_STRING;
}
@ -554,7 +559,8 @@ bool socket_type_supports_fields(const eNodeSocketDatatype socket_type)
SOCK_BOOLEAN,
SOCK_INT,
SOCK_ROTATION,
SOCK_MENU);
SOCK_MENU,
SOCK_MATRIX);
}
} // namespace blender::nodes
@ -699,6 +705,7 @@ void node_socket_init_default_value_data(eNodeSocketDatatype datatype, int subty
case SOCK_CUSTOM:
case SOCK_GEOMETRY:
case SOCK_MATRIX:
case SOCK_SHADER:
break;
}
@ -797,6 +804,7 @@ void node_socket_copy_default_value_data(eNodeSocketDatatype datatype, void *to,
case SOCK_CUSTOM:
case SOCK_GEOMETRY:
case SOCK_MATRIX:
case SOCK_SHADER:
break;
}
@ -978,6 +986,22 @@ static bNodeSocketType *make_socket_type_rotation()
return socktype;
}
static bNodeSocketType *make_socket_type_matrix()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_MATRIX, PROP_NONE);
socktype->base_cpp_type = &blender::CPPType::get<float4x4>();
socktype->get_base_cpp_value = [](const void * /*socket_value*/, void *r_value) {
*static_cast<float4x4 *>(r_value) = float4x4::identity();
};
socktype->geometry_nodes_cpp_type = &blender::CPPType::get<SocketValueVariant>();
socktype->get_geometry_nodes_cpp_value = [](const void * /*socket_value*/, void *r_value) {
new (r_value) SocketValueVariant(float4x4::identity());
};
static SocketValueVariant default_value{float4x4::identity()};
socktype->geometry_nodes_default_cpp_value = &default_value;
return socktype;
}
static bNodeSocketType *make_socket_type_float(PropertySubType subtype)
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_FLOAT, subtype);
@ -1172,6 +1196,7 @@ void register_standard_node_socket_types()
nodeRegisterSocketType(make_socket_type_bool());
nodeRegisterSocketType(make_socket_type_rotation());
nodeRegisterSocketType(make_socket_type_matrix());
nodeRegisterSocketType(make_socket_type_vector(PROP_NONE));
nodeRegisterSocketType(make_socket_type_vector(PROP_TRANSLATION));

View File

@ -417,9 +417,9 @@ bool Rotation::can_connect(const bNodeSocket &socket) const
return false;
}
if (this->in_out == SOCK_IN) {
return ELEM(socket.type, SOCK_ROTATION, SOCK_FLOAT, SOCK_VECTOR);
return ELEM(socket.type, SOCK_ROTATION, SOCK_FLOAT, SOCK_VECTOR, SOCK_MATRIX);
}
return ELEM(socket.type, SOCK_ROTATION, SOCK_VECTOR);
return ELEM(socket.type, SOCK_ROTATION, SOCK_VECTOR, SOCK_MATRIX);
}
bNodeSocket &Rotation::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const
@ -434,6 +434,57 @@ bNodeSocket &Rotation::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocke
/** \} */
/* -------------------------------------------------------------------- */
/** \name #Matrix
* \{ */
bNodeSocket &Matrix::build(bNodeTree &ntree, bNode &node) const
{
bNodeSocket &socket = *nodeAddStaticSocket(&ntree,
&node,
this->in_out,
SOCK_MATRIX,
PROP_NONE,
this->identifier.c_str(),
this->name.c_str());
this->set_common_flags(socket);
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
{
if (!sockets_can_connect(*this, socket)) {
return false;
}
if (this->in_out == SOCK_IN) {
return ELEM(socket.type, SOCK_MATRIX, SOCK_FLOAT, SOCK_VECTOR, SOCK_MATRIX);
}
return ELEM(socket.type, SOCK_MATRIX, SOCK_VECTOR, SOCK_MATRIX);
}
bNodeSocket &Matrix::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const
{
if (socket.type != SOCK_MATRIX) {
BLI_assert(socket.in_out == this->in_out);
return this->build(ntree, node);
}
this->set_common_flags(socket);
return socket;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name #String
* \{ */