diff options
Diffstat (limited to 'source/blender/nodes')
-rw-r--r-- | source/blender/nodes/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/nodes/NOD_geometry.h | 1 | ||||
-rw-r--r-- | source/blender/nodes/NOD_math_functions.hh | 226 | ||||
-rw-r--r-- | source/blender/nodes/NOD_static_types.h | 1 | ||||
-rw-r--r-- | source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc | 432 | ||||
-rw-r--r-- | source/blender/nodes/intern/math_functions.cc | 66 |
6 files changed, 727 insertions, 0 deletions
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 5ab2f5b49ea..de4d23d8577 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -146,6 +146,7 @@ set(SRC geometry/nodes/node_geo_attribute_math.cc geometry/nodes/node_geo_attribute_mix.cc geometry/nodes/node_geo_attribute_randomize.cc + geometry/nodes/node_geo_attribute_vector_math.cc geometry/nodes/node_geo_boolean.cc geometry/nodes/node_geo_common.cc geometry/nodes/node_geo_edge_split.cc diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h index 4653c9aae3f..93123c9a684 100644 --- a/source/blender/nodes/NOD_geometry.h +++ b/source/blender/nodes/NOD_geometry.h @@ -27,6 +27,7 @@ void register_node_tree_type_geo(void); void register_node_type_geo_group(void); void register_node_type_geo_attribute_fill(void); +void register_node_type_geo_attribute_vector_math(void); void register_node_type_geo_boolean(void); void register_node_type_geo_edge_split(void); void register_node_type_geo_transform(void); diff --git a/source/blender/nodes/NOD_math_functions.hh b/source/blender/nodes/NOD_math_functions.hh index cc750f9595a..c662220fea7 100644 --- a/source/blender/nodes/NOD_math_functions.hh +++ b/source/blender/nodes/NOD_math_functions.hh @@ -18,6 +18,7 @@ #include "DNA_node_types.h" +#include "BLI_float3.hh" #include "BLI_math_base_safe.h" #include "BLI_math_rotation.h" #include "BLI_string_ref.hh" @@ -36,6 +37,7 @@ struct FloatMathOperationInfo { }; const FloatMathOperationInfo *get_float_math_operation_info(const int operation); +const FloatMathOperationInfo *get_float3_math_operation_info(const int operation); const FloatMathOperationInfo *get_float_compare_operation_info(const int operation); /** @@ -231,4 +233,228 @@ inline bool try_dispatch_float_math_fl_fl_to_bool(const FloatCompareOperation op return false; } +/** + * This is similar to try_dispatch_float_math_fl_to_fl, just with a different callback signature. + */ +template<typename Callback> +inline bool try_dispatch_float_math_fl3_fl3_to_fl3(const NodeVectorMathOperation operation, + Callback &&callback) +{ + const FloatMathOperationInfo *info = get_float3_math_operation_info(operation); + if (info == nullptr) { + return false; + } + + /* This is just a utility function to keep the individual cases smaller. */ + auto dispatch = [&](auto math_function) -> bool { + callback(math_function, *info); + return true; + }; + + switch (operation) { + case NODE_VECTOR_MATH_ADD: + return dispatch([](float3 a, float3 b) { return a + b; }); + case NODE_VECTOR_MATH_SUBTRACT: + return dispatch([](float3 a, float3 b) { return a - b; }); + case NODE_VECTOR_MATH_MULTIPLY: + return dispatch([](float3 a, float3 b) { return a * b; }); + case NODE_VECTOR_MATH_DIVIDE: + return dispatch([](float3 a, float3 b) { + return float3(safe_divide(a.x, b.x), safe_divide(a.y, b.y), safe_divide(a.z, b.z)); + }); + case NODE_VECTOR_MATH_CROSS_PRODUCT: + return dispatch([](float3 a, float3 b) { return float3::cross_high_precision(a, b); }); + case NODE_VECTOR_MATH_PROJECT: + return dispatch([](float3 a, float3 b) { + float length_squared = float3::dot(a, b); + return (length_squared != 0.0) ? (float3::dot(a, b) / length_squared) * b : float3(0.0f); + }); + case NODE_VECTOR_MATH_REFLECT: + return dispatch([](float3 a, float3 b) { + b.normalize(); + return a.reflected(b); + }); + case NODE_VECTOR_MATH_SNAP: + return dispatch([](float3 a, float3 b) { + return float3(floor(safe_divide(a.x, b.x)), + floor(safe_divide(a.y, b.y)), + floor(safe_divide(a.z, b.z))) * + b; + }); + case NODE_VECTOR_MATH_MODULO: + return dispatch([](float3 a, float3 b) { + return float3(safe_modf(a.x, b.x), safe_modf(a.y, b.y), safe_modf(a.z, b.z)); + }); + case NODE_VECTOR_MATH_MINIMUM: + return dispatch([](float3 a, float3 b) { + return float3(min_ff(a.x, b.x), min_ff(a.y, b.y), min_ff(a.z, b.z)); + }); + case NODE_VECTOR_MATH_MAXIMUM: + return dispatch([](float3 a, float3 b) { + return float3(max_ff(a.x, b.x), max_ff(a.y, b.y), max_ff(a.z, b.z)); + }); + default: + return false; + } + return false; +} + +/** + * This is similar to try_dispatch_float_math_fl_to_fl, just with a different callback signature. + */ +template<typename Callback> +inline bool try_dispatch_float_math_fl3_fl3_to_fl(const NodeVectorMathOperation operation, + Callback &&callback) +{ + const FloatMathOperationInfo *info = get_float3_math_operation_info(operation); + if (info == nullptr) { + return false; + } + + /* This is just a utility function to keep the individual cases smaller. */ + auto dispatch = [&](auto math_function) -> bool { + callback(math_function, *info); + return true; + }; + + switch (operation) { + case NODE_VECTOR_MATH_DOT_PRODUCT: + return dispatch([](float3 a, float3 b) { return float3::dot(a, b); }); + case NODE_VECTOR_MATH_DISTANCE: + return dispatch([](float3 a, float3 b) { return float3::distance(a, b); }); + default: + return false; + } + return false; +} + +/** + * This is similar to try_dispatch_float_math_fl_to_fl, just with a different callback signature. + */ +template<typename Callback> +inline bool try_dispatch_float_math_fl3_fl3_fl3_to_fl3(const NodeVectorMathOperation operation, + Callback &&callback) +{ + const FloatMathOperationInfo *info = get_float3_math_operation_info(operation); + if (info == nullptr) { + return false; + } + + /* This is just a utility function to keep the individual cases smaller. */ + auto dispatch = [&](auto math_function) -> bool { + callback(math_function, *info); + return true; + }; + + switch (operation) { + case NODE_VECTOR_MATH_WRAP: + return dispatch([](float3 a, float3 b, float3 c) { + return float3(wrapf(a.x, b.x, c.x), wrapf(a.y, b.y, c.y), wrapf(a.z, b.z, c.z)); + }); + default: + return false; + } + return false; +} + +/** + * This is similar to try_dispatch_float_math_fl_to_fl, just with a different callback signature. + */ +template<typename Callback> +inline bool try_dispatch_float_math_fl3_to_fl(const NodeVectorMathOperation operation, + Callback &&callback) +{ + const FloatMathOperationInfo *info = get_float3_math_operation_info(operation); + if (info == nullptr) { + return false; + } + + /* This is just a utility function to keep the individual cases smaller. */ + auto dispatch = [&](auto math_function) -> bool { + callback(math_function, *info); + return true; + }; + + switch (operation) { + case NODE_VECTOR_MATH_LENGTH: + return dispatch([](float3 in) { return in.length(); }); + default: + return false; + } + return false; +} + +/** + * This is similar to try_dispatch_float_math_fl_to_fl, just with a different callback signature. + */ +template<typename Callback> +inline bool try_dispatch_float_math_fl3_fl_to_fl3(const NodeVectorMathOperation operation, + Callback &&callback) +{ + const FloatMathOperationInfo *info = get_float3_math_operation_info(operation); + if (info == nullptr) { + return false; + } + + /* This is just a utility function to keep the individual cases smaller. */ + auto dispatch = [&](auto math_function) -> bool { + callback(math_function, *info); + return true; + }; + + switch (operation) { + case NODE_VECTOR_MATH_SCALE: + return dispatch([](float3 a, float b) { return a * b; }); + default: + return false; + } + return false; +} + +/** + * This is similar to try_dispatch_float_math_fl_to_fl, just with a different callback signature. + */ +template<typename Callback> +inline bool try_dispatch_float_math_fl3_to_fl3(const NodeVectorMathOperation operation, + Callback &&callback) +{ + const FloatMathOperationInfo *info = get_float3_math_operation_info(operation); + if (info == nullptr) { + return false; + } + + /* This is just a utility function to keep the individual cases smaller. */ + auto dispatch = [&](auto math_function) -> bool { + callback(math_function, *info); + return true; + }; + + switch (operation) { + case NODE_VECTOR_MATH_NORMALIZE: + return dispatch([](float3 in) { + float3 out = in; + out.normalize(); + return out; + }); /* Should be safe. */ + case NODE_VECTOR_MATH_FLOOR: + return dispatch([](float3 in) { return float3(floor(in.x), floor(in.y), floor(in.z)); }); + case NODE_VECTOR_MATH_CEIL: + return dispatch([](float3 in) { return float3(ceil(in.x), ceil(in.y), ceil(in.z)); }); + case NODE_VECTOR_MATH_FRACTION: + return dispatch( + [](float3 in) { return in - float3(floor(in.x), floor(in.y), floor(in.z)); }); + case NODE_VECTOR_MATH_ABSOLUTE: + return dispatch([](float3 in) { return float3::abs(in); }); + case NODE_VECTOR_MATH_SINE: + return dispatch([](float3 in) { return float3(sinf(in.x), sinf(in.y), sinf(in.z)); }); + case NODE_VECTOR_MATH_COSINE: + return dispatch([](float3 in) { return float3(cosf(in.x), cosf(in.y), cosf(in.z)); }); + case NODE_VECTOR_MATH_TANGENT: + return dispatch([](float3 in) { return float3(tanf(in.x), tanf(in.y), tanf(in.z)); }); + default: + return false; + } + return false; +} + } // namespace blender::nodes diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 2cd08069f6f..55b06cb31a5 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -285,6 +285,7 @@ DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_COLOR_RAMP, def_geo_attribute_color_ram DefNode(GeometryNode, GEO_NODE_POINT_SEPARATE, 0, "POINT_SEPARATE", PointSeparate, "Point Separate", "") DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_COMPARE, def_geo_attribute_attribute_compare, "ATTRIBUTE_COMPARE", AttributeCompare, "Attribute Compare", "") DefNode(GeometryNode, GEO_NODE_ROTATE_POINTS, def_geo_rotate_points, "ROTATE_POINTS", RotatePoints, "Rotate Points", "") +DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_VECTOR_MATH, def_geo_attribute_vector_math, "ATTRIBUTE_VECTOR_MATH", AttributeVectorMath, "Attribute Vector Math", "") /* undefine macros */ #undef DefNode diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc new file mode 100644 index 00000000000..0bbd5a07577 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc @@ -0,0 +1,432 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "node_geometry_util.hh" + +#include "BKE_attribute.h" +#include "BKE_attribute_access.hh" + +#include "BLI_array.hh" +#include "BLI_math_base_safe.h" +#include "BLI_rand.hh" + +#include "DNA_mesh_types.h" +#include "DNA_pointcloud_types.h" + +#include "NOD_math_functions.hh" + +static bNodeSocketTemplate geo_node_attribute_vector_math_in[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {SOCK_STRING, N_("A")}, + {SOCK_VECTOR, N_("A"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_STRING, N_("B")}, + {SOCK_VECTOR, N_("B"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_FLOAT, N_("B"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_STRING, N_("C")}, + {SOCK_VECTOR, N_("C"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_STRING, N_("Result")}, + {-1, ""}, +}; + +static bNodeSocketTemplate geo_node_attribute_vector_math_out[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {-1, ""}, +}; + +static void geo_node_attribute_vector_math_init(bNodeTree *UNUSED(tree), bNode *node) +{ + NodeAttributeVectorMath *data = (NodeAttributeVectorMath *)MEM_callocN( + sizeof(NodeAttributeVectorMath), __func__); + + data->operation = NODE_VECTOR_MATH_ADD; + data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE; + data->input_type_b = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE; + node->storage = data; +} + +static CustomDataType operation_get_read_type_b(const NodeVectorMathOperation operation) +{ + if (operation == NODE_VECTOR_MATH_SCALE) { + return CD_PROP_FLOAT; + } + return CD_PROP_FLOAT3; +} + +static bool operation_use_input_b(const NodeVectorMathOperation operation) +{ + return !ELEM(operation, + NODE_VECTOR_MATH_NORMALIZE, + NODE_VECTOR_MATH_FLOOR, + NODE_VECTOR_MATH_CEIL, + NODE_VECTOR_MATH_FRACTION, + NODE_VECTOR_MATH_ABSOLUTE, + NODE_VECTOR_MATH_SINE, + NODE_VECTOR_MATH_COSINE, + NODE_VECTOR_MATH_TANGENT, + NODE_VECTOR_MATH_LENGTH); +} + +static bool operation_use_input_c(const NodeVectorMathOperation operation) +{ + return operation == NODE_VECTOR_MATH_WRAP; +} + +static CustomDataType operation_get_result_type(const NodeVectorMathOperation operation) +{ + switch (operation) { + case NODE_VECTOR_MATH_ADD: + case NODE_VECTOR_MATH_SUBTRACT: + case NODE_VECTOR_MATH_MULTIPLY: + case NODE_VECTOR_MATH_DIVIDE: + case NODE_VECTOR_MATH_CROSS_PRODUCT: + case NODE_VECTOR_MATH_PROJECT: + case NODE_VECTOR_MATH_REFLECT: + case NODE_VECTOR_MATH_SCALE: + case NODE_VECTOR_MATH_NORMALIZE: + case NODE_VECTOR_MATH_SNAP: + case NODE_VECTOR_MATH_FLOOR: + case NODE_VECTOR_MATH_CEIL: + case NODE_VECTOR_MATH_MODULO: + case NODE_VECTOR_MATH_FRACTION: + case NODE_VECTOR_MATH_ABSOLUTE: + case NODE_VECTOR_MATH_MINIMUM: + case NODE_VECTOR_MATH_MAXIMUM: + case NODE_VECTOR_MATH_WRAP: + case NODE_VECTOR_MATH_SINE: + case NODE_VECTOR_MATH_COSINE: + case NODE_VECTOR_MATH_TANGENT: + return CD_PROP_FLOAT3; + case NODE_VECTOR_MATH_DOT_PRODUCT: + case NODE_VECTOR_MATH_DISTANCE: + case NODE_VECTOR_MATH_LENGTH: + return CD_PROP_FLOAT; + } + + BLI_assert(false); + return CD_PROP_FLOAT3; +} + +namespace blender::nodes { + +static void geo_node_attribute_vector_math_update(bNodeTree *UNUSED(ntree), bNode *node) +{ + const NodeAttributeVectorMath *node_storage = (NodeAttributeVectorMath *)node->storage; + const NodeVectorMathOperation operation = (const NodeVectorMathOperation)node_storage->operation; + + update_attribute_input_socket_availabilities( + *node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a); + update_attribute_input_socket_availabilities( + *node, + "B", + (GeometryNodeAttributeInputMode)node_storage->input_type_b, + operation_use_input_b(operation)); + update_attribute_input_socket_availabilities( + *node, + "C", + (GeometryNodeAttributeInputMode)node_storage->input_type_c, + operation_use_input_c(operation)); +} + +static void do_math_operation_fl3_fl3_to_fl3(const Float3ReadAttribute &input_a, + const Float3ReadAttribute &input_b, + Float3WriteAttribute result, + const NodeVectorMathOperation operation) +{ + const int size = input_a.size(); + + Span<float3> span_a = input_a.get_span(); + Span<float3> span_b = input_b.get_span(); + MutableSpan<float3> span_result = result.get_span(); + + bool success = try_dispatch_float_math_fl3_fl3_to_fl3( + operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) { + for (const int i : IndexRange(size)) { + const float3 a = span_a[i]; + const float3 b = span_b[i]; + const float3 out = math_function(a, b); + span_result[i] = out; + } + }); + + result.apply_span(); + + /* The operation is not supported by this node currently. */ + BLI_assert(success); + UNUSED_VARS_NDEBUG(success); +} + +static void do_math_operation_fl3_fl3_fl3_to_fl3(const Float3ReadAttribute &input_a, + const Float3ReadAttribute &input_b, + const Float3ReadAttribute &input_c, + Float3WriteAttribute result, + const NodeVectorMathOperation operation) +{ + const int size = input_a.size(); + + Span<float3> span_a = input_a.get_span(); + Span<float3> span_b = input_b.get_span(); + Span<float3> span_c = input_c.get_span(); + MutableSpan<float3> span_result = result.get_span(); + + bool success = try_dispatch_float_math_fl3_fl3_fl3_to_fl3( + operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) { + for (const int i : IndexRange(size)) { + const float3 a = span_a[i]; + const float3 b = span_b[i]; + const float3 c = span_c[i]; + const float3 out = math_function(a, b, c); + span_result[i] = out; + } + }); + + result.apply_span(); + + /* The operation is not supported by this node currently. */ + BLI_assert(success); + UNUSED_VARS_NDEBUG(success); +} + +static void do_math_operation_fl3_fl3_to_fl(const Float3ReadAttribute &input_a, + const Float3ReadAttribute &input_b, + FloatWriteAttribute result, + const NodeVectorMathOperation operation) +{ + const int size = input_a.size(); + + Span<float3> span_a = input_a.get_span(); + Span<float3> span_b = input_b.get_span(); + MutableSpan<float> span_result = result.get_span(); + + bool success = try_dispatch_float_math_fl3_fl3_to_fl( + operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) { + for (const int i : IndexRange(size)) { + const float3 a = span_a[i]; + const float3 b = span_b[i]; + const float out = math_function(a, b); + span_result[i] = out; + } + }); + + result.apply_span(); + + /* The operation is not supported by this node currently. */ + BLI_assert(success); + UNUSED_VARS_NDEBUG(success); +} + +static void do_math_operation_fl3_fl_to_fl3(const Float3ReadAttribute &input_a, + const FloatReadAttribute &input_b, + Float3WriteAttribute result, + const NodeVectorMathOperation operation) +{ + const int size = input_a.size(); + + Span<float3> span_a = input_a.get_span(); + Span<float> span_b = input_b.get_span(); + MutableSpan<float3> span_result = result.get_span(); + + bool success = try_dispatch_float_math_fl3_fl_to_fl3( + operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) { + for (const int i : IndexRange(size)) { + const float3 a = span_a[i]; + const float b = span_b[i]; + const float3 out = math_function(a, b); + span_result[i] = out; + } + }); + + result.apply_span(); + + /* The operation is not supported by this node currently. */ + BLI_assert(success); + UNUSED_VARS_NDEBUG(success); +} + +static void do_math_operation_fl3_to_fl3(const Float3ReadAttribute &input_a, + Float3WriteAttribute result, + const NodeVectorMathOperation operation) +{ + const int size = input_a.size(); + + Span<float3> span_a = input_a.get_span(); + MutableSpan<float3> span_result = result.get_span(); + + bool success = try_dispatch_float_math_fl3_to_fl3( + operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) { + for (const int i : IndexRange(size)) { + const float3 in = span_a[i]; + const float3 out = math_function(in); + span_result[i] = out; + } + }); + + result.apply_span(); + + /* The operation is not supported by this node currently. */ + BLI_assert(success); + UNUSED_VARS_NDEBUG(success); +} + +static void do_math_operation_fl3_to_fl(const Float3ReadAttribute &input_a, + FloatWriteAttribute result, + const NodeVectorMathOperation operation) +{ + const int size = input_a.size(); + + Span<float3> span_a = input_a.get_span(); + MutableSpan<float> span_result = result.get_span(); + + bool success = try_dispatch_float_math_fl3_to_fl( + operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) { + for (const int i : IndexRange(size)) { + const float3 in = span_a[i]; + const float out = math_function(in); + span_result[i] = out; + } + }); + + result.apply_span(); + + /* The operation is not supported by this node currently. */ + BLI_assert(success); + UNUSED_VARS_NDEBUG(success); +} + +static void attribute_vector_math_calc(GeometryComponent &component, + const GeoNodeExecParams ¶ms) +{ + const bNode &node = params.node(); + const NodeAttributeVectorMath *node_storage = (const NodeAttributeVectorMath *)node.storage; + const NodeVectorMathOperation operation = (NodeVectorMathOperation)node_storage->operation; + + /* The number and type of the input attribute depend on the operation. */ + const CustomDataType read_type_a = CD_PROP_FLOAT3; + const bool use_input_b = operation_use_input_b(operation); + const CustomDataType read_type_b = operation_get_read_type_b(operation); + const bool use_input_c = operation_use_input_c(operation); + const CustomDataType read_type_c = CD_PROP_FLOAT3; + + /* The result domain is always point for now. */ + const CustomDataType result_type = operation_get_result_type(operation); + const AttributeDomain result_domain = ATTR_DOMAIN_POINT; + + ReadAttributePtr attribute_a = params.get_input_attribute( + "A", component, result_domain, read_type_a, nullptr); + if (!attribute_a) { + return; + } + ReadAttributePtr attribute_b; + ReadAttributePtr attribute_c; + if (use_input_b) { + attribute_b = params.get_input_attribute("B", component, result_domain, read_type_b, nullptr); + if (!attribute_b) { + return; + } + } + if (use_input_c) { + attribute_c = params.get_input_attribute("C", component, result_domain, read_type_c, nullptr); + if (!attribute_c) { + return; + } + } + + /* Get result attribute first, in case it has to overwrite one of the existing attributes. */ + const std::string result_name = params.get_input<std::string>("Result"); + WriteAttributePtr attribute_result = component.attribute_try_ensure_for_write( + result_name, result_domain, result_type); + if (!attribute_result) { + return; + } + + switch (operation) { + case NODE_VECTOR_MATH_ADD: + case NODE_VECTOR_MATH_SUBTRACT: + case NODE_VECTOR_MATH_MULTIPLY: + case NODE_VECTOR_MATH_DIVIDE: + case NODE_VECTOR_MATH_CROSS_PRODUCT: + case NODE_VECTOR_MATH_PROJECT: + case NODE_VECTOR_MATH_REFLECT: + case NODE_VECTOR_MATH_SNAP: + case NODE_VECTOR_MATH_MODULO: + case NODE_VECTOR_MATH_MINIMUM: + case NODE_VECTOR_MATH_MAXIMUM: + do_math_operation_fl3_fl3_to_fl3( + std::move(attribute_a), std::move(attribute_b), std::move(attribute_result), operation); + break; + case NODE_VECTOR_MATH_DOT_PRODUCT: + case NODE_VECTOR_MATH_DISTANCE: + do_math_operation_fl3_fl3_to_fl( + std::move(attribute_a), std::move(attribute_b), std::move(attribute_result), operation); + break; + case NODE_VECTOR_MATH_LENGTH: + do_math_operation_fl3_to_fl(std::move(attribute_a), std::move(attribute_result), operation); + break; + case NODE_VECTOR_MATH_SCALE: + do_math_operation_fl3_fl_to_fl3( + std::move(attribute_a), std::move(attribute_b), std::move(attribute_result), operation); + break; + case NODE_VECTOR_MATH_NORMALIZE: + case NODE_VECTOR_MATH_FLOOR: + case NODE_VECTOR_MATH_CEIL: + case NODE_VECTOR_MATH_FRACTION: + case NODE_VECTOR_MATH_ABSOLUTE: + case NODE_VECTOR_MATH_SINE: + case NODE_VECTOR_MATH_COSINE: + case NODE_VECTOR_MATH_TANGENT: + do_math_operation_fl3_to_fl3(std::move(attribute_a), std::move(attribute_result), operation); + break; + case NODE_VECTOR_MATH_WRAP: + do_math_operation_fl3_fl3_fl3_to_fl3(std::move(attribute_a), + std::move(attribute_b), + std::move(attribute_c), + std::move(attribute_result), + operation); + break; + } +} + +static void geo_node_attribute_vector_math_exec(GeoNodeExecParams params) +{ + GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); + + if (geometry_set.has<MeshComponent>()) { + attribute_vector_math_calc(geometry_set.get_component_for_write<MeshComponent>(), params); + } + if (geometry_set.has<PointCloudComponent>()) { + attribute_vector_math_calc(geometry_set.get_component_for_write<PointCloudComponent>(), + params); + } + + params.set_output("Geometry", geometry_set); +} + +} // namespace blender::nodes + +void register_node_type_geo_attribute_vector_math() +{ + static bNodeType ntype; + + geo_node_type_base( + &ntype, GEO_NODE_ATTRIBUTE_VECTOR_MATH, "Attribute Vector Math", NODE_CLASS_ATTRIBUTE, 0); + node_type_socket_templates( + &ntype, geo_node_attribute_vector_math_in, geo_node_attribute_vector_math_out); + ntype.geometry_node_execute = blender::nodes::geo_node_attribute_vector_math_exec; + node_type_update(&ntype, blender::nodes::geo_node_attribute_vector_math_update); + node_type_init(&ntype, geo_node_attribute_vector_math_init); + node_type_storage( + &ntype, "NodeAttributeVectorMath", node_free_standard_storage, node_copy_standard_storage); + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/intern/math_functions.cc b/source/blender/nodes/intern/math_functions.cc index 32a18f1c193..14de2fce9b3 100644 --- a/source/blender/nodes/intern/math_functions.cc +++ b/source/blender/nodes/intern/math_functions.cc @@ -146,4 +146,70 @@ const FloatMathOperationInfo *get_float_compare_operation_info(const int operati return nullptr; } +const FloatMathOperationInfo *get_float3_math_operation_info(const int operation) +{ + +#define RETURN_OPERATION_INFO(title_case_name, shader_name) \ + { \ + static const FloatMathOperationInfo info{title_case_name, shader_name}; \ + return &info; \ + } \ + ((void)0) + + switch (operation) { + case NODE_VECTOR_MATH_ADD: + RETURN_OPERATION_INFO("Add", "vector_math_add"); + case NODE_VECTOR_MATH_SUBTRACT: + RETURN_OPERATION_INFO("Subtract", "vector_math_subtract"); + case NODE_VECTOR_MATH_MULTIPLY: + RETURN_OPERATION_INFO("Multiply", "vector_math_multiply"); + case NODE_VECTOR_MATH_DIVIDE: + RETURN_OPERATION_INFO("Divide", "vector_math_divide"); + case NODE_VECTOR_MATH_CROSS_PRODUCT: + RETURN_OPERATION_INFO("Cross Product", "vector_math_cross"); + case NODE_VECTOR_MATH_PROJECT: + RETURN_OPERATION_INFO("Project", "vector_math_project"); + case NODE_VECTOR_MATH_REFLECT: + RETURN_OPERATION_INFO("Reflect", "vector_math_reflect"); + case NODE_VECTOR_MATH_DOT_PRODUCT: + RETURN_OPERATION_INFO("Dot Product", "vector_math_dot"); + case NODE_VECTOR_MATH_DISTANCE: + RETURN_OPERATION_INFO("Distance", "vector_math_distance"); + case NODE_VECTOR_MATH_LENGTH: + RETURN_OPERATION_INFO("Length", "vector_math_length"); + case NODE_VECTOR_MATH_SCALE: + RETURN_OPERATION_INFO("Scale", "vector_math_scale"); + case NODE_VECTOR_MATH_NORMALIZE: + RETURN_OPERATION_INFO("Normalize", "vector_math_normalize"); + case NODE_VECTOR_MATH_SNAP: + RETURN_OPERATION_INFO("Snap", "vector_math_snap"); + case NODE_VECTOR_MATH_FLOOR: + RETURN_OPERATION_INFO("Floor", "vector_math_floor"); + case NODE_VECTOR_MATH_CEIL: + RETURN_OPERATION_INFO("Ceiling", "vector_math_ceil"); + case NODE_VECTOR_MATH_MODULO: + RETURN_OPERATION_INFO("Modulo", "vector_math_modulo"); + case NODE_VECTOR_MATH_FRACTION: + RETURN_OPERATION_INFO("Fraction", "vector_math_fraction"); + case NODE_VECTOR_MATH_ABSOLUTE: + RETURN_OPERATION_INFO("Absolute", "vector_math_absolute"); + case NODE_VECTOR_MATH_MINIMUM: + RETURN_OPERATION_INFO("Minimum", "vector_math_minimum"); + case NODE_VECTOR_MATH_MAXIMUM: + RETURN_OPERATION_INFO("Maximum", "vector_math_maximum"); + case NODE_VECTOR_MATH_WRAP: + RETURN_OPERATION_INFO("Wrap", "vector_math_wrap"); + case NODE_VECTOR_MATH_SINE: + RETURN_OPERATION_INFO("Sine", "vector_math_sine"); + case NODE_VECTOR_MATH_COSINE: + RETURN_OPERATION_INFO("Cosine", "vector_math_cosine"); + case NODE_VECTOR_MATH_TANGENT: + RETURN_OPERATION_INFO("Tangent", "vector_math_tangent"); + } + +#undef RETURN_OPERATION_INFO + + return nullptr; +} + } // namespace blender::nodes |