diff options
-rw-r--r-- | release/scripts/startup/nodeitems_builtins.py | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_node.h | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/node.cc | 2 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_node_types.h | 14 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_nodetree.c | 33 | ||||
-rw-r--r-- | source/blender/nodes/CMakeLists.txt | 2 | ||||
-rw-r--r-- | source/blender/nodes/NOD_geometry.h | 2 | ||||
-rw-r--r-- | source/blender/nodes/NOD_static_types.h | 2 | ||||
-rw-r--r-- | source/blender/nodes/geometry/nodes/node_geo_attribute_combine_xyz.cc | 135 | ||||
-rw-r--r-- | source/blender/nodes/geometry/nodes/node_geo_attribute_separate_xyz.cc | 148 |
10 files changed, 342 insertions, 0 deletions
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index 40b57fd10de..9d7485a0837 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -491,6 +491,8 @@ geometry_node_categories = [ NodeItem("GeometryNodeAttributeColorRamp"), NodeItem("GeometryNodeAttributeVectorMath"), NodeItem("GeometryNodeAttributeSampleTexture"), + NodeItem("GeometryNodeAttributeCombineXYZ"), + NodeItem("GeometryNodeAttributeSeparateXYZ"), ]), GeometryNodeCategory("GEO_COLOR", "Color", items=[ NodeItem("ShaderNodeValToRGB"), diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index f4f753c4084..7984bbc980a 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -1370,6 +1370,8 @@ int ntreeTexExecTree(struct bNodeTree *ntree, #define GEO_NODE_IS_VIEWPORT 1024 #define GEO_NODE_ATTRIBUTE_PROXIMITY 1025 #define GEO_NODE_VOLUME_TO_MESH 1026 +#define GEO_NODE_ATTRIBUTE_COMBINE_XYZ 1027 +#define GEO_NODE_ATTRIBUTE_SEPARATE_XYZ 1028 /** \} */ diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index a4440d3d9f3..ed8dd84a9bb 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -4753,12 +4753,14 @@ static void registerGeometryNodes() register_node_type_geo_align_rotation_to_vector(); register_node_type_geo_attribute_color_ramp(); + register_node_type_geo_attribute_combine_xyz(); register_node_type_geo_attribute_compare(); register_node_type_geo_attribute_fill(); register_node_type_geo_attribute_math(); register_node_type_geo_attribute_mix(); register_node_type_geo_attribute_proximity(); register_node_type_geo_attribute_randomize(); + register_node_type_geo_attribute_separate_xyz(); register_node_type_geo_attribute_vector_math(); register_node_type_geo_boolean(); register_node_type_geo_collection_info(); diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index e8748e28776..61b0b469426 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1216,6 +1216,20 @@ typedef struct NodeGeometryVolumeToMesh { char _pad[7]; } NodeGeometryVolumeToMesh; +typedef struct NodeAttributeCombineXYZ { + /* GeometryNodeAttributeInputMode. */ + uint8_t input_type_x; + uint8_t input_type_y; + uint8_t input_type_z; + + char _pad[1]; +} NodeAttributeCombineXYZ; + +typedef struct NodeAttributeSeparateXYZ { + /* GeometryNodeAttributeInputMode. */ + uint8_t input_type; +} NodeAttributeSeparateXYZ; + /* script node mode */ #define NODE_SCRIPT_INTERNAL 0 #define NODE_SCRIPT_EXTERNAL 1 diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index c67a3e4448b..c00f843c76e 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -9029,6 +9029,39 @@ static void def_geo_volume_to_mesh(StructRNA *srna) prop = RNA_def_property(srna, "resolution_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, resolution_mode_items); RNA_def_property_ui_text(prop, "Resolution Mode", "How the voxel size is specified"); +} + +static void def_geo_attribute_combine_xyz(StructRNA *srna) +{ + PropertyRNA *prop; + + RNA_def_struct_sdna_from(srna, "NodeAttributeCombineXYZ", "storage"); + + prop = RNA_def_property(srna, "input_type_x", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float); + RNA_def_property_ui_text(prop, "Input Type X", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); + + prop = RNA_def_property(srna, "input_type_y", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float); + RNA_def_property_ui_text(prop, "Input Type Y", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); + + prop = RNA_def_property(srna, "input_type_z", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float); + RNA_def_property_ui_text(prop, "Input Type Z", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); +} + +static void def_geo_attribute_separate_xyz(StructRNA *srna) +{ + PropertyRNA *prop; + + RNA_def_struct_sdna_from(srna, "NodeAttributeSeparateXYZ", "storage"); + + prop = RNA_def_property(srna, "input_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_vector); + RNA_def_property_ui_text(prop, "Input Type", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 4656e2e5e4f..64c240eb5fd 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -143,6 +143,7 @@ set(SRC geometry/nodes/node_geo_align_rotation_to_vector.cc geometry/nodes/node_geo_attribute_color_ramp.cc + geometry/nodes/node_geo_attribute_combine_xyz.cc geometry/nodes/node_geo_attribute_compare.cc geometry/nodes/node_geo_attribute_fill.cc geometry/nodes/node_geo_attribute_math.cc @@ -150,6 +151,7 @@ set(SRC geometry/nodes/node_geo_attribute_sample_texture.cc geometry/nodes/node_geo_attribute_proximity.cc geometry/nodes/node_geo_attribute_randomize.cc + geometry/nodes/node_geo_attribute_separate_xyz.cc geometry/nodes/node_geo_attribute_vector_math.cc geometry/nodes/node_geo_boolean.cc geometry/nodes/node_geo_collection_info.cc diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h index 39338ab14dc..8980855fd51 100644 --- a/source/blender/nodes/NOD_geometry.h +++ b/source/blender/nodes/NOD_geometry.h @@ -28,12 +28,14 @@ void register_node_type_geo_group(void); void register_node_type_geo_align_rotation_to_vector(void); void register_node_type_geo_attribute_color_ramp(void); +void register_node_type_geo_attribute_combine_xyz(void); void register_node_type_geo_attribute_compare(void); void register_node_type_geo_attribute_fill(void); void register_node_type_geo_attribute_math(void); void register_node_type_geo_attribute_mix(void); void register_node_type_geo_attribute_proximity(void); void register_node_type_geo_attribute_randomize(void); +void register_node_type_geo_attribute_separate_xyz(void); void register_node_type_geo_attribute_vector_math(void); void register_node_type_geo_boolean(void); void register_node_type_geo_collection_info(void); diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 980790af766..15f078cebf2 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -295,6 +295,8 @@ DefNode(GeometryNode, GEO_NODE_COLLECTION_INFO, def_geo_collection_info, "COLLEC DefNode(GeometryNode, GEO_NODE_IS_VIEWPORT, 0, "IS_VIEWPORT", IsViewport, "Is Viewport", "") DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_PROXIMITY, def_geo_attribute_proximity, "ATTRIBUTE_PROXIMITY", AttributeProximity, "Attribute Proximity", "") DefNode(GeometryNode, GEO_NODE_VOLUME_TO_MESH, def_geo_volume_to_mesh, "VOLUME_TO_MESH", VolumeToMesh, "Volume to Mesh", "") +DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_COMBINE_XYZ, def_geo_attribute_combine_xyz, "ATTRIBUTE_COMBINE_XYZ", AttributeCombineXYZ, "Attribute Combine XYZ", "") +DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_SEPARATE_XYZ, def_geo_attribute_separate_xyz, "ATTRIBUTE_SEPARATE_XYZ", AttributeSeparateXYZ, "Attribute Separate XYZ", "") /* undefine macros */ #undef DefNode diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_combine_xyz.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_combine_xyz.cc new file mode 100644 index 00000000000..a231b4f9e92 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_combine_xyz.cc @@ -0,0 +1,135 @@ +/* + * 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 "UI_interface.h" +#include "UI_resources.h" + +static bNodeSocketTemplate geo_node_attribute_combine_xyz_in[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {SOCK_STRING, N_("X")}, + {SOCK_FLOAT, N_("X"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX}, + {SOCK_STRING, N_("Y")}, + {SOCK_FLOAT, N_("Y"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX}, + {SOCK_STRING, N_("Z")}, + {SOCK_FLOAT, N_("Z"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX}, + {SOCK_STRING, N_("Result")}, + {-1, ""}, +}; + +static bNodeSocketTemplate geo_node_attribute_combine_xyz_out[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {-1, ""}, +}; + +static void geo_node_attribute_combine_xyz_layout(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *ptr) +{ + uiItemR(layout, ptr, "input_type_x", 0, IFACE_("Type X"), ICON_NONE); + uiItemR(layout, ptr, "input_type_y", 0, IFACE_("Type Y"), ICON_NONE); + uiItemR(layout, ptr, "input_type_z", 0, IFACE_("Type Z"), ICON_NONE); +} + +namespace blender::nodes { + +static void geo_node_attribute_combine_xyz_init(bNodeTree *UNUSED(tree), bNode *node) +{ + NodeAttributeCombineXYZ *data = (NodeAttributeCombineXYZ *)MEM_callocN( + sizeof(NodeAttributeCombineXYZ), __func__); + + data->input_type_x = GEO_NODE_ATTRIBUTE_INPUT_FLOAT; + data->input_type_y = GEO_NODE_ATTRIBUTE_INPUT_FLOAT; + data->input_type_z = GEO_NODE_ATTRIBUTE_INPUT_FLOAT; + node->storage = data; +} + +static void geo_node_attribute_combine_xyz_update(bNodeTree *UNUSED(ntree), bNode *node) +{ + NodeAttributeCombineXYZ *node_storage = (NodeAttributeCombineXYZ *)node->storage; + update_attribute_input_socket_availabilities( + *node, "X", (GeometryNodeAttributeInputMode)node_storage->input_type_x); + update_attribute_input_socket_availabilities( + *node, "Y", (GeometryNodeAttributeInputMode)node_storage->input_type_y); + update_attribute_input_socket_availabilities( + *node, "Z", (GeometryNodeAttributeInputMode)node_storage->input_type_z); +} + +static void combine_attributes(GeometryComponent &component, const GeoNodeExecParams ¶ms) +{ + const std::string result_name = params.get_input<std::string>("Result"); + /* The result domain is always point for now. */ + const AttributeDomain result_domain = ATTR_DOMAIN_POINT; + if (result_name.empty()) { + return; + } + + OutputAttributePtr attribute_result = component.attribute_try_get_for_output( + result_name, result_domain, CD_PROP_FLOAT3); + if (!attribute_result) { + return; + } + FloatReadAttribute attribute_x = params.get_input_attribute<float>( + "X", component, result_domain, 0.0f); + FloatReadAttribute attribute_y = params.get_input_attribute<float>( + "Y", component, result_domain, 0.0f); + FloatReadAttribute attribute_z = params.get_input_attribute<float>( + "Z", component, result_domain, 0.0f); + + MutableSpan<float3> results = attribute_result->get_span_for_write_only<float3>(); + for (const int i : results.index_range()) { + const float x = attribute_x[i]; + const float y = attribute_y[i]; + const float z = attribute_z[i]; + const float3 result = float3(x, y, z); + results[i] = result; + } + attribute_result.apply_span_and_save(); +} + +static void geo_node_attribute_combine_xyz_exec(GeoNodeExecParams params) +{ + GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); + + if (geometry_set.has<MeshComponent>()) { + combine_attributes(geometry_set.get_component_for_write<MeshComponent>(), params); + } + if (geometry_set.has<PointCloudComponent>()) { + combine_attributes(geometry_set.get_component_for_write<PointCloudComponent>(), params); + } + + params.set_output("Geometry", geometry_set); +} + +} // namespace blender::nodes + +void register_node_type_geo_attribute_combine_xyz() +{ + static bNodeType ntype; + + geo_node_type_base( + &ntype, GEO_NODE_ATTRIBUTE_COMBINE_XYZ, "Attribute Combine XYZ", NODE_CLASS_ATTRIBUTE, 0); + node_type_socket_templates( + &ntype, geo_node_attribute_combine_xyz_in, geo_node_attribute_combine_xyz_out); + node_type_init(&ntype, blender::nodes::geo_node_attribute_combine_xyz_init); + node_type_update(&ntype, blender::nodes::geo_node_attribute_combine_xyz_update); + node_type_storage( + &ntype, "NodeAttributeCombineXYZ", node_free_standard_storage, node_copy_standard_storage); + ntype.geometry_node_execute = blender::nodes::geo_node_attribute_combine_xyz_exec; + ntype.draw_buttons = geo_node_attribute_combine_xyz_layout; + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_separate_xyz.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_separate_xyz.cc new file mode 100644 index 00000000000..07941f7db79 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_separate_xyz.cc @@ -0,0 +1,148 @@ +/* + * 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 "DNA_material_types.h" + +#include "node_geometry_util.hh" + +#include "UI_interface.h" +#include "UI_resources.h" + +static bNodeSocketTemplate geo_node_attribute_separate_xyz_in[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {SOCK_STRING, N_("Vector")}, + {SOCK_VECTOR, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_STRING, N_("Result X")}, + {SOCK_STRING, N_("Result Y")}, + {SOCK_STRING, N_("Result Z")}, + {-1, ""}, +}; + +static bNodeSocketTemplate geo_node_attribute_separate_xyz_out[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {-1, ""}, +}; + +static void geo_node_attribute_separate_xyz_layout(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *ptr) +{ + uiItemR(layout, ptr, "input_type", 0, IFACE_("Type"), ICON_NONE); +} + +namespace blender::nodes { + +static void geo_node_attribute_separate_xyz_init(bNodeTree *UNUSED(tree), bNode *node) +{ + NodeAttributeSeparateXYZ *data = (NodeAttributeSeparateXYZ *)MEM_callocN( + sizeof(NodeAttributeSeparateXYZ), __func__); + data->input_type = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE; + node->storage = data; +} + +static void geo_node_attribute_separate_xyz_update(bNodeTree *UNUSED(ntree), bNode *node) +{ + NodeAttributeSeparateXYZ *node_storage = (NodeAttributeSeparateXYZ *)node->storage; + update_attribute_input_socket_availabilities( + *node, "Vector", (GeometryNodeAttributeInputMode)node_storage->input_type); +} + +static void extract_input(const int index, const Span<float3> &input, MutableSpan<float> result) +{ + for (const int i : result.index_range()) { + /* Get the component of the float3. (0: X, 1: Y, 2: Z). */ + const float component = input[i][index]; + result[i] = component; + } +} + +static void separate_attribute(GeometryComponent &component, const GeoNodeExecParams ¶ms) +{ + const std::string result_name_x = params.get_input<std::string>("Result X"); + const std::string result_name_y = params.get_input<std::string>("Result Y"); + const std::string result_name_z = params.get_input<std::string>("Result Z"); + /* The node is only for float3 to float conversions. */ + const CustomDataType input_type = CD_PROP_FLOAT3; + const CustomDataType result_type = CD_PROP_FLOAT; + /* The result domain is always point for now. */ + const AttributeDomain result_domain = ATTR_DOMAIN_POINT; + + /* No output to write to. */ + if (result_name_x.empty() && result_name_y.empty() && result_name_z.empty()) { + return; + } + + ReadAttributePtr attribute_input = params.get_input_attribute( + "Vector", component, result_domain, input_type, nullptr); + if (!attribute_input) { + return; + } + const Span<float3> input_span = attribute_input->get_span<float3>(); + + OutputAttributePtr attribute_result_x = component.attribute_try_get_for_output( + result_name_x, result_domain, result_type); + OutputAttributePtr attribute_result_y = component.attribute_try_get_for_output( + result_name_y, result_domain, result_type); + OutputAttributePtr attribute_result_z = component.attribute_try_get_for_output( + result_name_z, result_domain, result_type); + + /* Only extract the components for the outputs with a given attribute. */ + if (attribute_result_x) { + extract_input(0, input_span, attribute_result_x->get_span_for_write_only<float>()); + attribute_result_x.apply_span_and_save(); + } + if (attribute_result_y) { + extract_input(1, input_span, attribute_result_y->get_span_for_write_only<float>()); + attribute_result_y.apply_span_and_save(); + } + if (attribute_result_z) { + extract_input(2, input_span, attribute_result_z->get_span_for_write_only<float>()); + attribute_result_z.apply_span_and_save(); + } +} + +static void geo_node_attribute_separate_xyz_exec(GeoNodeExecParams params) +{ + GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); + + if (geometry_set.has<MeshComponent>()) { + separate_attribute(geometry_set.get_component_for_write<MeshComponent>(), params); + } + if (geometry_set.has<PointCloudComponent>()) { + separate_attribute(geometry_set.get_component_for_write<PointCloudComponent>(), params); + } + + params.set_output("Geometry", geometry_set); +} + +} // namespace blender::nodes + +void register_node_type_geo_attribute_separate_xyz() +{ + static bNodeType ntype; + + geo_node_type_base( + &ntype, GEO_NODE_ATTRIBUTE_SEPARATE_XYZ, "Attribute Separate XYZ", NODE_CLASS_ATTRIBUTE, 0); + node_type_socket_templates( + &ntype, geo_node_attribute_separate_xyz_in, geo_node_attribute_separate_xyz_out); + node_type_init(&ntype, blender::nodes::geo_node_attribute_separate_xyz_init); + node_type_update(&ntype, blender::nodes::geo_node_attribute_separate_xyz_update); + node_type_storage( + &ntype, "NodeAttributeSeparateXYZ", node_free_standard_storage, node_copy_standard_storage); + ntype.geometry_node_execute = blender::nodes::geo_node_attribute_separate_xyz_exec; + ntype.draw_buttons = geo_node_attribute_separate_xyz_layout; + nodeRegisterType(&ntype); +} |