Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/nodes/geometry')
-rw-r--r--source/blender/nodes/geometry/node_geometry_tree.cc28
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.hh22
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_endpoints.cc223
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc241
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc17
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc47
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc2
-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 &params,
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);
}