diff options
Diffstat (limited to 'source/blender/nodes/geometry')
-rw-r--r-- | source/blender/nodes/geometry/node_geometry_tree.cc | 28 | ||||
-rw-r--r-- | source/blender/nodes/geometry/node_geometry_util.hh | 22 | ||||
-rw-r--r-- | source/blender/nodes/geometry/nodes/node_geo_curve_endpoints.cc | 223 | ||||
-rw-r--r-- | source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc | 18 | ||||
-rw-r--r-- | source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc | 8 | ||||
-rw-r--r-- | source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc | 241 | ||||
-rw-r--r-- | source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc | 4 | ||||
-rw-r--r-- | source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc | 17 | ||||
-rw-r--r-- | source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc | 47 | ||||
-rw-r--r-- | source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc | 3 | ||||
-rw-r--r-- | source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc | 2 | ||||
-rw-r--r-- | source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_subdivide.cc) | 16 |
12 files changed, 556 insertions, 73 deletions
diff --git a/source/blender/nodes/geometry/node_geometry_tree.cc b/source/blender/nodes/geometry/node_geometry_tree.cc index f4cd00b88ed..07a89a1fa8c 100644 --- a/source/blender/nodes/geometry/node_geometry_tree.cc +++ b/source/blender/nodes/geometry/node_geometry_tree.cc @@ -95,21 +95,21 @@ static bool geometry_node_tree_validate_link(bNodeTree *UNUSED(ntree), bNodeLink return (link->tosock->type == link->fromsock->type); } -static bool geometry_node_tree_socket_type_valid(eNodeSocketDatatype socket_type, - bNodeTreeType *UNUSED(ntreetype)) +static bool geometry_node_tree_socket_type_valid(bNodeTreeType *UNUSED(ntreetype), + bNodeSocketType *socket_type) { - return ELEM(socket_type, - SOCK_FLOAT, - SOCK_VECTOR, - SOCK_RGBA, - SOCK_BOOLEAN, - SOCK_INT, - SOCK_STRING, - SOCK_OBJECT, - SOCK_GEOMETRY, - SOCK_COLLECTION, - SOCK_TEXTURE, - SOCK_MATERIAL); + return nodeIsStaticSocketType(socket_type) && ELEM(socket_type->type, + SOCK_FLOAT, + SOCK_VECTOR, + SOCK_RGBA, + SOCK_BOOLEAN, + SOCK_INT, + SOCK_STRING, + SOCK_OBJECT, + SOCK_GEOMETRY, + SOCK_COLLECTION, + SOCK_TEXTURE, + SOCK_MATERIAL); } void register_node_tree_type_geo(void) diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh index 79a98c5ebf0..956b7b8a005 100644 --- a/source/blender/nodes/geometry/node_geometry_util.hh +++ b/source/blender/nodes/geometry/node_geometry_util.hh @@ -70,4 +70,26 @@ void copy_point_attributes_based_on_mask(const GeometryComponent &in_component, Span<bool> masks, const bool invert); +struct CurveToPointsResults { + int result_size; + MutableSpan<float3> positions; + MutableSpan<float> radii; + MutableSpan<float> tilts; + + Map<std::string, GMutableSpan> point_attributes; + + MutableSpan<float3> tangents; + MutableSpan<float3> normals; + MutableSpan<float3> rotations; +}; +/** + * Create references for all result point cloud attributes to simplify accessing them later on. + */ +CurveToPointsResults curve_to_points_create_result_attributes(PointCloudComponent &points, + const CurveEval &curve); + +void curve_create_default_rotation_attribute(Span<float3> tangents, + Span<float3> normals, + MutableSpan<float3> rotations); + } // namespace blender::nodes diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoints.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoints.cc new file mode 100644 index 00000000000..1f878259f30 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoints.cc @@ -0,0 +1,223 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "BLI_task.hh" +#include "BLI_timeit.hh" + +#include "BKE_pointcloud.h" +#include "BKE_spline.hh" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "node_geometry_util.hh" + +static bNodeSocketTemplate geo_node_curve_endpoints_in[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {-1, ""}, +}; + +static bNodeSocketTemplate geo_node_curve_endpoints_out[] = { + {SOCK_GEOMETRY, N_("Start Points")}, + {SOCK_GEOMETRY, N_("End Points")}, + {-1, ""}, +}; + +namespace blender::nodes { + +/** + * Evaluate splines in parallel to speed up the rest of the node's execution. + */ +static void evaluate_splines(Span<SplinePtr> splines) +{ + threading::parallel_for_each(splines, [](const SplinePtr &spline) { + /* These functions fill the corresponding caches on each spline. */ + spline->evaluated_positions(); + spline->evaluated_tangents(); + spline->evaluated_normals(); + spline->evaluated_lengths(); + }); +} + +/** + * \note Use attributes from the curve component rather than the attribute data directly on the + * attribute storage to allow reading the virtual spline attributes like "cyclic" and "resolution". + */ +static void copy_spline_domain_attributes(const CurveComponent &curve_component, + Span<int> offsets, + PointCloudComponent &points) +{ + curve_component.attribute_foreach([&](StringRefNull name, const AttributeMetaData &meta_data) { + if (meta_data.domain != ATTR_DOMAIN_CURVE) { + return true; + } + GVArrayPtr spline_attribute = curve_component.attribute_get_for_read( + name, ATTR_DOMAIN_CURVE, meta_data.data_type); + + OutputAttribute result_attribute = points.attribute_try_get_for_output_only( + name, ATTR_DOMAIN_POINT, meta_data.data_type); + GMutableSpan result = result_attribute.as_span(); + + /* Only copy the attributes of splines in the offsets. */ + for (const int i : offsets.index_range()) { + spline_attribute->get(offsets[i], result[i]); + } + + result_attribute.save(); + return true; + }); +} + +/** + * Get the offsets for the splines whose endpoints we want to output. + * Filter those which are cyclic, or that evaluate to empty. + * Could be easily adapted to include a selection argument to support attribute selection. + */ +static blender::Vector<int> get_endpoint_spline_offsets(Span<SplinePtr> splines) +{ + blender::Vector<int> spline_offsets; + spline_offsets.reserve(splines.size()); + + for (const int i : splines.index_range()) { + if (!(splines[i]->is_cyclic() || splines[i]->evaluated_points_size() == 0)) { + spline_offsets.append(i); + } + } + + return spline_offsets; +} + +/** + * Copy the endpoint attributes from the correct positions at the splines at the offsets to + * the start and end attributes. + */ +static void copy_endpoint_attributes(Span<SplinePtr> splines, + Span<int> offsets, + CurveToPointsResults &start_data, + CurveToPointsResults &end_data) +{ + threading::parallel_for(offsets.index_range(), 64, [&](IndexRange range) { + for (const int i : range) { + const Spline &spline = *splines[offsets[i]]; + + /* Copy the start and end point data over. */ + start_data.positions[i] = spline.evaluated_positions().first(); + start_data.tangents[i] = spline.evaluated_tangents().first(); + start_data.normals[i] = spline.evaluated_normals().first(); + start_data.radii[i] = spline.radii().first(); + start_data.tilts[i] = spline.tilts().first(); + + end_data.positions[i] = spline.evaluated_positions().last(); + end_data.tangents[i] = spline.evaluated_tangents().last(); + end_data.normals[i] = spline.evaluated_normals().last(); + end_data.radii[i] = spline.radii().last(); + end_data.tilts[i] = spline.tilts().last(); + + /* Copy the point attribute data over. */ + for (const auto &item : start_data.point_attributes.items()) { + const StringRef name = item.key; + GMutableSpan point_span = item.value; + + BLI_assert(spline.attributes.get_for_read(name)); + GSpan spline_span = *spline.attributes.get_for_read(name); + blender::fn::GVArray_For_GSpan(spline_span).get(0, point_span[i]); + } + + for (const auto &item : end_data.point_attributes.items()) { + const StringRef name = item.key; + GMutableSpan point_span = item.value; + + BLI_assert(spline.attributes.get_for_read(name)); + GSpan spline_span = *spline.attributes.get_for_read(name); + blender::fn::GVArray_For_GSpan(spline_span).get(spline.size() - 1, point_span[i]); + } + } + }); +} + +static void geo_node_curve_endpoints_exec(GeoNodeExecParams params) +{ + GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); + + geometry_set = bke::geometry_set_realize_instances(geometry_set); + + if (!geometry_set.has_curve()) { + params.set_output("Start Points", GeometrySet()); + params.set_output("End Points", GeometrySet()); + return; + } + + const CurveComponent &curve_component = *geometry_set.get_component_for_read<CurveComponent>(); + const CurveEval &curve = *curve_component.get_for_read(); + const Span<SplinePtr> splines = curve.splines(); + curve.assert_valid_point_attributes(); + + evaluate_splines(splines); + + const Vector<int> offsets = get_endpoint_spline_offsets(splines); + const int total_size = offsets.size(); + + if (total_size == 0) { + params.set_output("Start Points", GeometrySet()); + params.set_output("End Points", GeometrySet()); + return; + } + + GeometrySet start_result = GeometrySet::create_with_pointcloud( + BKE_pointcloud_new_nomain(total_size)); + GeometrySet end_result = GeometrySet::create_with_pointcloud( + BKE_pointcloud_new_nomain(total_size)); + PointCloudComponent &start_point_component = + start_result.get_component_for_write<PointCloudComponent>(); + PointCloudComponent &end_point_component = + end_result.get_component_for_write<PointCloudComponent>(); + + CurveToPointsResults start_attributes = curve_to_points_create_result_attributes( + start_point_component, curve); + CurveToPointsResults end_attributes = curve_to_points_create_result_attributes( + end_point_component, curve); + + copy_endpoint_attributes(splines, offsets.as_span(), start_attributes, end_attributes); + copy_spline_domain_attributes(curve_component, offsets.as_span(), start_point_component); + curve_create_default_rotation_attribute( + start_attributes.tangents, start_attributes.normals, start_attributes.rotations); + curve_create_default_rotation_attribute( + end_attributes.tangents, end_attributes.normals, end_attributes.rotations); + + /* The default radius is way too large for points, divide by 10. */ + for (float &radius : start_attributes.radii) { + radius *= 0.1f; + } + for (float &radius : end_attributes.radii) { + radius *= 0.1f; + } + + params.set_output("Start Points", std::move(start_result)); + params.set_output("End Points", std::move(end_result)); +} + +} // namespace blender::nodes + +void register_node_type_geo_curve_endpoints() +{ + static bNodeType ntype; + + geo_node_type_base(&ntype, GEO_NODE_CURVE_ENDPOINTS, "Curve Endpoints", NODE_CLASS_GEOMETRY, 0); + node_type_socket_templates(&ntype, geo_node_curve_endpoints_in, geo_node_curve_endpoints_out); + ntype.geometry_node_execute = blender::nodes::geo_node_curve_endpoints_exec; + + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc index 2b3ebf7f5f1..ae947b7aeed 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc @@ -83,9 +83,10 @@ static bool colinear_f3_f3_f3(const float3 p1, const float3 p2, const float3 p3) } static std::unique_ptr<CurveEval> create_point_circle_curve( - const float3 p1, const float3 p2, const float3 p3, const int resolution, float center_out[3]) + const float3 p1, const float3 p2, const float3 p3, const int resolution, float3 &r_center) { if (colinear_f3_f3_f3(p1, p2, p3)) { + r_center = float3(0); return nullptr; } @@ -118,6 +119,7 @@ static std::unique_ptr<CurveEval> create_point_circle_curve( /* If the 3 planes do not intersect at one point, just return empty geometry. */ if (!isect_plane_plane_plane_v3(plane_1, plane_2, plane_3, center)) { + r_center = float3(0); return nullptr; } @@ -141,7 +143,7 @@ static std::unique_ptr<CurveEval> create_point_circle_curve( curve->add_spline(std::move(spline)); curve->attributes.reallocate(curve->splines().size()); - copy_v3_v3(center_out, center); + r_center = center; return curve; } @@ -179,18 +181,13 @@ static void geo_node_curve_primitive_circle_exec(GeoNodeExecParams params) std::unique_ptr<CurveEval> curve; if (mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS) { - float center_point[3]; + float3 center_point; curve = create_point_circle_curve(params.extract_input<float3>("Point 1"), params.extract_input<float3>("Point 2"), params.extract_input<float3>("Point 3"), std::max(params.extract_input<int>("Resolution"), 3), center_point); - if (curve) { - params.set_output("Center", float3(center_point)); - } - else { - params.set_output("Center", float3(0, 0, 0)); - } + params.set_output("Center", center_point); } else if (mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_RADIUS) { curve = create_radius_circle_curve(std::max(params.extract_input<int>("Resolution"), 3), @@ -210,7 +207,8 @@ static void geo_node_curve_primitive_circle_exec(GeoNodeExecParams params) void register_node_type_geo_curve_primitive_circle() { static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_CIRCLE, "Circle", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base( + &ntype, GEO_NODE_CURVE_PRIMITIVE_CIRCLE, "Curve Circle", NODE_CLASS_GEOMETRY, 0); node_type_socket_templates( &ntype, geo_node_curve_primitive_circle_in, geo_node_curve_primitive_circle_out); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc index 7aeb077d1d6..419a7af1ba0 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc @@ -23,9 +23,9 @@ static bNodeSocketTemplate geo_node_curve_primitive_line_in[] = { {SOCK_VECTOR, N_("Start"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_TRANSLATION}, - {SOCK_VECTOR, N_("End"), 0.0f, 2.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_TRANSLATION}, - {SOCK_VECTOR, N_("Direction"), 0.0f, 1.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, - {SOCK_FLOAT, N_("Length"), 2.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_DISTANCE}, + {SOCK_VECTOR, N_("End"), 0.0f, 0.0f, 1.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_TRANSLATION}, + {SOCK_VECTOR, N_("Direction"), 0.0f, 0.0f, 1.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_FLOAT, N_("Length"), 1.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_DISTANCE}, {-1, ""}, }; @@ -95,7 +95,7 @@ static std::unique_ptr<CurveEval> create_direction_line_curve(const float3 start spline->resize(2); MutableSpan<float3> positions = spline->positions(); positions[0] = start; - positions[1] = direction.normalized() * length; + positions[1] = direction.normalized() * length + start; spline->radii().fill(1.0f); spline->tilts().fill(0.0f); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc new file mode 100644 index 00000000000..5f3f159c305 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc @@ -0,0 +1,241 @@ +/* + * 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 "BKE_spline.hh" +#include "UI_interface.h" +#include "UI_resources.h" +#include "node_geometry_util.hh" + +static bNodeSocketTemplate geo_node_curve_primitive_quadrilateral_in[] = { + {SOCK_FLOAT, N_("Width"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE}, + {SOCK_FLOAT, N_("Height"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE}, + {SOCK_FLOAT, N_("Bottom Width"), 4.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE}, + {SOCK_FLOAT, N_("Top Width"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE}, + {SOCK_FLOAT, N_("Offset"), 1.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_DISTANCE}, + {SOCK_FLOAT, N_("Bottom Height"), 3.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE}, + {SOCK_FLOAT, N_("Top Height"), 1.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_DISTANCE}, + {SOCK_VECTOR, N_("Point 1"), -1.0f, 1.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_DISTANCE}, + {SOCK_VECTOR, N_("Point 2"), 1.0f, 1.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_DISTANCE}, + {SOCK_VECTOR, N_("Point 3"), 1.0f, -1.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_DISTANCE}, + {SOCK_VECTOR, N_("Point 4"), -1.0f, -1.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_DISTANCE}, + {-1, ""}, +}; + +static bNodeSocketTemplate geo_node_curve_primitive_quadrilateral_out[] = { + {SOCK_GEOMETRY, N_("Curve")}, + {-1, ""}, +}; + +static void geo_node_curve_primitive_quadrilateral_layout(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *ptr) +{ + uiItemR(layout, ptr, "mode", 0, "", ICON_NONE); +} + +static void geo_node_curve_primitive_quadrilateral_init(bNodeTree *UNUSED(tree), bNode *node) +{ + NodeGeometryCurvePrimitiveQuad *data = (NodeGeometryCurvePrimitiveQuad *)MEM_callocN( + sizeof(NodeGeometryCurvePrimitiveQuad), __func__); + data->mode = GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE; + node->storage = data; +} + +namespace blender::nodes { + +static void geo_node_curve_primitive_quadrilateral_update(bNodeTree *UNUSED(ntree), bNode *node) +{ + NodeGeometryCurvePrimitiveQuad &node_storage = *(NodeGeometryCurvePrimitiveQuad *)node->storage; + GeometryNodeCurvePrimitiveQuadMode mode = static_cast<GeometryNodeCurvePrimitiveQuadMode>( + node_storage.mode); + + bNodeSocket *width = ((bNodeSocket *)node->inputs.first); + bNodeSocket *height = width->next; + bNodeSocket *bottom = height->next; + bNodeSocket *top = bottom->next; + bNodeSocket *offset = top->next; + bNodeSocket *bottom_height = offset->next; + bNodeSocket *top_height = bottom_height->next; + bNodeSocket *p1 = top_height->next; + bNodeSocket *p2 = p1->next; + bNodeSocket *p3 = p2->next; + bNodeSocket *p4 = p3->next; + + LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { + nodeSetSocketAvailability(sock, false); + } + + if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE) { + nodeSetSocketAvailability(width, true); + nodeSetSocketAvailability(height, true); + } + else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_PARALLELOGRAM) { + nodeSetSocketAvailability(width, true); + nodeSetSocketAvailability(height, true); + nodeSetSocketAvailability(offset, true); + } + else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_TRAPEZOID) { + nodeSetSocketAvailability(bottom, true); + nodeSetSocketAvailability(top, true); + nodeSetSocketAvailability(offset, true); + nodeSetSocketAvailability(height, true); + } + else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_KITE) { + nodeSetSocketAvailability(width, true); + nodeSetSocketAvailability(bottom_height, true); + nodeSetSocketAvailability(top_height, true); + } + else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_POINTS) { + nodeSetSocketAvailability(p1, true); + nodeSetSocketAvailability(p2, true); + nodeSetSocketAvailability(p3, true); + nodeSetSocketAvailability(p4, true); + } +} + +static void create_rectangle_curve(MutableSpan<float3> positions, + const float height, + const float width) +{ + positions[0] = float3(width / 2.0f, -height / 2.0f, 0.0f); + positions[1] = float3(-width / 2.0f, -height / 2.0f, 0.0f); + positions[2] = float3(-width / 2.0f, height / 2.0f, 0.0f); + positions[3] = float3(width / 2.0f, height / 2.0f, 0.0f); +} + +static void create_points_curve(MutableSpan<float3> positions, + const float3 &p1, + const float3 &p2, + const float3 &p3, + const float3 &p4) +{ + positions[0] = p1; + positions[1] = p2; + positions[2] = p3; + positions[3] = p4; +} + +static void create_parallelogram_curve(MutableSpan<float3> positions, + const float height, + const float width, + const float offset) +{ + positions[0] = float3(width / 2.0f - offset / 2.0f, -height / 2.0f, 0.0f); + positions[1] = float3(-width / 2.0f - offset / 2.0f, -height / 2.0f, 0.0f); + positions[2] = float3(-width / 2.0f + offset / 2.0f, height / 2.0f, 0.0f); + positions[3] = float3(width / 2.0f + offset / 2.0f, height / 2.0f, 0.0f); +} +static void create_trapezoid_curve(MutableSpan<float3> positions, + const float bottom, + const float top, + const float offset, + const float height) +{ + positions[0] = float3(bottom / 2.0f, -height / 2.0f, 0.0f); + positions[1] = float3(-bottom / 2.0f, -height / 2.0f, 0.0f); + positions[2] = float3(-top / 2.0f + offset, height / 2.0f, 0.0f); + positions[3] = float3(top / 2.0f + offset, height / 2.0f, 0.0f); +} + +static void create_kite_curve(MutableSpan<float3> positions, + const float width, + const float bottom_height, + const float top_height) +{ + positions[0] = float3(-width / 2.0f, 0, 0); + positions[1] = float3(0, top_height, 0); + positions[2] = float3(width / 2, 0, 0); + positions[3] = float3(0, -bottom_height, 0); +} + +static void geo_node_curve_primitive_quadrilateral_exec(GeoNodeExecParams params) +{ + const NodeGeometryCurvePrimitiveQuad &node_storage = + *(NodeGeometryCurvePrimitiveQuad *)(params.node()).storage; + const GeometryNodeCurvePrimitiveQuadMode mode = static_cast<GeometryNodeCurvePrimitiveQuadMode>( + node_storage.mode); + + std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>(); + std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>(); + spline->resize(4); + spline->radii().fill(1.0f); + spline->tilts().fill(0.0f); + spline->set_cyclic(true); + MutableSpan<float3> positions = spline->positions(); + + switch (mode) { + case GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE: + create_rectangle_curve(positions, + std::max(params.extract_input<float>("Height"), 0.0f), + std::max(params.extract_input<float>("Width"), 0.0f)); + break; + + case GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_PARALLELOGRAM: + create_parallelogram_curve(positions, + std::max(params.extract_input<float>("Height"), 0.0f), + std::max(params.extract_input<float>("Width"), 0.0f), + params.extract_input<float>("Offset")); + break; + case GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_TRAPEZOID: + create_trapezoid_curve(positions, + std::max(params.extract_input<float>("Bottom Width"), 0.0f), + std::max(params.extract_input<float>("Top Width"), 0.0f), + params.extract_input<float>("Offset"), + std::max(params.extract_input<float>("Height"), 0.0f)); + break; + case GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_KITE: + create_kite_curve(positions, + std::max(params.extract_input<float>("Width"), 0.0f), + std::max(params.extract_input<float>("Bottom Height"), 0.0f), + params.extract_input<float>("Top Height")); + break; + case GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_POINTS: + create_points_curve(positions, + params.extract_input<float3>("Point 1"), + params.extract_input<float3>("Point 2"), + params.extract_input<float3>("Point 3"), + params.extract_input<float3>("Point 4")); + break; + default: + params.set_output("Curve", GeometrySet()); + return; + } + + curve->add_spline(std::move(spline)); + curve->attributes.reallocate(curve->splines().size()); + params.set_output("Curve", GeometrySet::create_with_curve(curve.release())); +} + +} // namespace blender::nodes + +void register_node_type_geo_curve_primitive_quadrilateral() +{ + static bNodeType ntype; + geo_node_type_base( + &ntype, GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL, "Quadrilateral", NODE_CLASS_GEOMETRY, 0); + node_type_socket_templates(&ntype, + geo_node_curve_primitive_quadrilateral_in, + geo_node_curve_primitive_quadrilateral_out); + ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_quadrilateral_exec; + ntype.draw_buttons = geo_node_curve_primitive_quadrilateral_layout; + node_type_update(&ntype, blender::nodes::geo_node_curve_primitive_quadrilateral_update); + node_type_init(&ntype, geo_node_curve_primitive_quadrilateral_init); + node_type_storage(&ntype, + "NodeGeometryCurvePrimitiveQuad", + node_free_standard_storage, + node_copy_standard_storage); + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc index 367da3bc3c2..2e2bb247e2b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc @@ -19,7 +19,7 @@ #include "node_geometry_util.hh" static bNodeSocketTemplate geo_node_curve_primitive_star_in[] = { - {SOCK_INT, N_("Points"), 8.0f, 0.0f, 0.0f, 0.0f, 4, 256, PROP_UNSIGNED}, + {SOCK_INT, N_("Points"), 8.0f, 0.0f, 0.0f, 0.0f, 3, 256, PROP_UNSIGNED}, {SOCK_FLOAT, N_("Inner Radius"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE}, {SOCK_FLOAT, N_("Outer Radius"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE}, {SOCK_FLOAT, N_("Twist"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_ANGLE}, @@ -64,7 +64,7 @@ static void geo_node_curve_primitive_star_exec(GeoNodeExecParams params) std::max(params.extract_input<float>("Inner Radius"), 0.0f), std::max(params.extract_input<float>("Outer Radius"), 0.0f), params.extract_input<float>("Twist"), - std::max(params.extract_input<int>("Points"), 4)); + std::max(params.extract_input<int>("Points"), 3)); params.set_output("Curve", GeometrySet::create_with_curve(curve.release())); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc index fc65d1754e9..ad0c453c2af 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc @@ -87,6 +87,23 @@ static SplinePtr resample_spline(const Spline &input_spline, const int count) input_spline.tilts().first(), input_spline.radii().first()); output_spline->attributes.reallocate(1); + input_spline.attributes.foreach_attribute( + [&](StringRefNull name, const AttributeMetaData &meta_data) { + std::optional<GSpan> src = input_spline.attributes.get_for_read(name); + BLI_assert(src); + if (!output_spline->attributes.create(name, meta_data.data_type)) { + BLI_assert_unreachable(); + return false; + } + std::optional<GMutableSpan> dst = output_spline->attributes.get_for_write(name); + if (!dst) { + BLI_assert_unreachable(); + return false; + } + src->type().copy_assign(src->data(), dst->data()); + return true; + }, + ATTR_DOMAIN_POINT); return output_spline; } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc index e37822bd262..bb8f560f92d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc @@ -118,22 +118,6 @@ static Array<int> calculate_spline_point_offsets(GeoNodeExecParams ¶ms, return {0}; } -/** - * \note This doesn't store a map for spline domain attributes. - */ -struct ResultAttributes { - int result_size; - MutableSpan<float3> positions; - MutableSpan<float> radii; - MutableSpan<float> tilts; - - Map<std::string, GMutableSpan> point_attributes; - - MutableSpan<float3> tangents; - MutableSpan<float3> normals; - MutableSpan<float3> rotations; -}; - static GMutableSpan create_attribute_and_retrieve_span(PointCloudComponent &points, const StringRef name, const CustomDataType data_type) @@ -153,13 +137,10 @@ static MutableSpan<T> create_attribute_and_retrieve_span(PointCloudComponent &po return attribute.typed<T>(); } -/** - * Create references for all result point cloud attributes to simplify accessing them later on. - */ -static ResultAttributes create_point_attributes(PointCloudComponent &points, - const CurveEval &curve) +CurveToPointsResults curve_to_points_create_result_attributes(PointCloudComponent &points, + const CurveEval &curve) { - ResultAttributes attributes; + CurveToPointsResults attributes; attributes.result_size = points.attribute_domain_size(ATTR_DOMAIN_POINT); @@ -190,7 +171,7 @@ static ResultAttributes create_point_attributes(PointCloudComponent &points, */ static void copy_evaluated_point_attributes(Span<SplinePtr> splines, Span<int> offsets, - ResultAttributes &data) + CurveToPointsResults &data) { threading::parallel_for(splines.index_range(), 64, [&](IndexRange range) { for (const int i : range) { @@ -221,7 +202,7 @@ static void copy_evaluated_point_attributes(Span<SplinePtr> splines, static void copy_uniform_sample_point_attributes(Span<SplinePtr> splines, Span<int> offsets, - ResultAttributes &data) + CurveToPointsResults &data) { threading::parallel_for(splines.index_range(), 64, [&](IndexRange range) { for (const int i : range) { @@ -307,13 +288,14 @@ static void copy_spline_domain_attributes(const CurveComponent &curve_component, }); } -static void create_default_rotation_attribute(ResultAttributes &data) +void curve_create_default_rotation_attribute(Span<float3> tangents, + Span<float3> normals, + MutableSpan<float3> rotations) { - threading::parallel_for(IndexRange(data.result_size), 512, [&](IndexRange range) { + threading::parallel_for(IndexRange(rotations.size()), 512, [&](IndexRange range) { for (const int i : range) { - data.rotations[i] = float4x4::from_normalized_axis_data( - {0, 0, 0}, data.normals[i], data.tangents[i]) - .to_euler(); + rotations[i] = + float4x4::from_normalized_axis_data({0, 0, 0}, normals[i], tangents[i]).to_euler(); } }); } @@ -348,8 +330,8 @@ static void geo_node_curve_to_points_exec(GeoNodeExecParams params) GeometrySet result = GeometrySet::create_with_pointcloud(BKE_pointcloud_new_nomain(total_size)); PointCloudComponent &point_component = result.get_component_for_write<PointCloudComponent>(); - ResultAttributes new_attributes = create_point_attributes(point_component, curve); - + CurveToPointsResults new_attributes = curve_to_points_create_result_attributes(point_component, + curve); switch (mode) { case GEO_NODE_CURVE_SAMPLE_COUNT: case GEO_NODE_CURVE_SAMPLE_LENGTH: @@ -361,7 +343,8 @@ static void geo_node_curve_to_points_exec(GeoNodeExecParams params) } copy_spline_domain_attributes(curve_component, offsets, point_component); - create_default_rotation_attribute(new_attributes); + curve_create_default_rotation_attribute( + new_attributes.tangents, new_attributes.normals, new_attributes.rotations); /* The default radius is way too large for points, divide by 10. */ for (float &radius : new_attributes.radii) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc index 2915a17d2c8..667e1c931bd 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc @@ -228,7 +228,8 @@ void register_node_type_geo_mesh_primitive_circle() { static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CIRCLE, "Circle", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base( + &ntype, GEO_NODE_MESH_PRIMITIVE_CIRCLE, "Mesh Circle", NODE_CLASS_GEOMETRY, 0); node_type_socket_templates( &ntype, geo_node_mesh_primitive_circle_in, geo_node_mesh_primitive_circle_out); node_type_init(&ntype, geo_node_mesh_primitive_circle_init); diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc index e841455e58c..a193c05daa1 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc @@ -177,7 +177,7 @@ void register_node_type_geo_mesh_primitive_line() { static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_LINE, "Line", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_LINE, "Mesh Line", NODE_CLASS_GEOMETRY, 0); node_type_socket_templates( &ntype, geo_node_mesh_primitive_line_in, geo_node_mesh_primitive_line_out); node_type_init(&ntype, geo_node_mesh_primitive_line_init); diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc index 63aafe53e3b..245d7800621 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_subdivide.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc @@ -14,8 +14,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -// #include "MEM_guardedalloc.h" - #include "BKE_mesh.h" #include "BKE_subdiv.h" #include "BKE_subdiv_mesh.h" @@ -25,20 +23,20 @@ #include "node_geometry_util.hh" -static bNodeSocketTemplate geo_node_subdivide_in[] = { +static bNodeSocketTemplate geo_node_mesh_subdivide_in[] = { {SOCK_GEOMETRY, N_("Geometry")}, {SOCK_INT, N_("Level"), 1, 0, 0, 0, 0, 6}, {-1, ""}, }; -static bNodeSocketTemplate geo_node_subdivide_out[] = { +static bNodeSocketTemplate geo_node_mesh_subdivide_out[] = { {SOCK_GEOMETRY, N_("Geometry")}, {-1, ""}, }; namespace blender::nodes { -static void geo_node_subdivide_exec(GeoNodeExecParams params) +static void geo_node_mesh_subdivide_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); geometry_set = geometry_set_realize_instances(geometry_set); @@ -102,12 +100,12 @@ static void geo_node_subdivide_exec(GeoNodeExecParams params) } // namespace blender::nodes -void register_node_type_geo_subdivide() +void register_node_type_geo_mesh_subdivide() { static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_SUBDIVIDE, "Subdivide", NODE_CLASS_GEOMETRY, 0); - node_type_socket_templates(&ntype, geo_node_subdivide_in, geo_node_subdivide_out); - ntype.geometry_node_execute = blender::nodes::geo_node_subdivide_exec; + geo_node_type_base(&ntype, GEO_NODE_MESH_SUBDIVIDE, "Mesh Subdivide", NODE_CLASS_GEOMETRY, 0); + node_type_socket_templates(&ntype, geo_node_mesh_subdivide_in, geo_node_mesh_subdivide_out); + ntype.geometry_node_execute = blender::nodes::geo_node_mesh_subdivide_exec; nodeRegisterType(&ntype); } |