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:
-rw-r--r--release/scripts/startup/nodeitems_builtins.py1
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.hh12
-rw-r--r--source/blender/blenkernel/BKE_spline.hh9
-rw-r--r--source/blender/blenkernel/intern/node.cc2
-rw-r--r--source/blender/blenkernel/intern/spline_base.cc20
-rw-r--r--source/blender/nodes/CMakeLists.txt2
-rw-r--r--source/blender/nodes/NOD_geometry.h2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc172
8 files changed, 124 insertions, 96 deletions
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index d617cfab988..783a55c6500 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -504,6 +504,7 @@ geometry_node_categories = [
NodeItem("GeometryNodeCurveSubdivide"),
NodeItem("GeometryNodeCurveToMesh"),
NodeItem("GeometryNodeCurveResample"),
+ NodeItem("GeometryNodeCurveSample"),
NodeItem("GeometryNodeMeshToCurve"),
NodeItem("GeometryNodeCurveToPoints"),
NodeItem("GeometryNodeCurveEndpoints"),
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index c79977752c9..77e827bf6f2 100644
--- a/source/blender/blenkernel/BKE_geometry_set.hh
+++ b/source/blender/blenkernel/BKE_geometry_set.hh
@@ -180,18 +180,6 @@ class GeometryComponent {
return blender::fn::GVArray_Typed<T>(std::move(varray));
}
- /* Should be used instead of the method above when the requested data type is known at compile
- * time for better type safety. */
- template<typename T>
- blender::fn::GVArray_Typed<T> attribute_get_for_read(const blender::StringRef attribute_name,
- const T &default_value) const
- {
- const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>();
- const CustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
- std::unique_ptr varray = this->attribute_get_for_read(attribute_name, type, &default_value);
- return blender::fn::GVArray_Typed<T>(std::move(varray));
- }
-
/**
* Returns an "output attribute", which is essentially a mutable virtual array with some commonly
* used convince features. The returned output attribute might be empty if requested attribute
diff --git a/source/blender/blenkernel/BKE_spline.hh b/source/blender/blenkernel/BKE_spline.hh
index f1c66de7773..176e44b3245 100644
--- a/source/blender/blenkernel/BKE_spline.hh
+++ b/source/blender/blenkernel/BKE_spline.hh
@@ -56,7 +56,7 @@ using SplinePtr = std::unique_ptr<Spline>;
* along the length of a curve.
* 3. #sample_uniform_index_factors returns an array that stores uniform-length samples
* along the spline which can be used to interpolate data from method 1.
- * 4. #sample_length_parameters_to_index_factors does the same, but uses arbitrary parameter
+ * 4. #sample_lengths_to_index_factors does the same, but uses arbitrary parameter
* inputs, instead of sampling uniformly.
*
* Commonly used evaluated data is stored in caches on the spline itself so that operations on
@@ -172,13 +172,16 @@ class Spline {
LookupResult lookup_evaluated_length(const float length) const;
blender::Array<float> sample_uniform_index_factors(const int samples_size) const;
- void sample_length_parameters_to_index_factors(blender::MutableSpan<float> parameters) const;
+ blender::Array<float> sample_lengths_to_index_factors(blender::Span<float> parameters) const;
LookupResult lookup_data_from_index_factor(const float index_factor) const;
void sample_with_index_factors(const blender::fn::GVArray &src,
blender::Span<float> index_factors,
blender::fn::GMutableSpan dst) const;
+ void sample_with_index_factors(blender::fn::GSpan src,
+ blender::Span<float> index_factors,
+ blender::fn::GMutableSpan dst) const;
template<typename T>
void sample_with_index_factors(const blender::VArray<T> &src,
blender::Span<float> index_factors,
@@ -209,8 +212,6 @@ class Spline {
return blender::fn::GVArray_Typed<T>(this->interpolate_to_evaluated(blender::fn::GSpan(data)));
}
- blender::fn::GVArrayPtr get_evaluated_attribute(const blender::StringRef name) const;
-
protected:
virtual void correct_end_tangents() const = 0;
virtual void copy_settings(Spline &dst) const = 0;
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index 715c2fa91d2..cc71151c1b0 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -5116,8 +5116,6 @@ static void registerGeometryNodes()
register_node_type_geo_curve_primitive_spiral();
register_node_type_geo_curve_primitive_star();
register_node_type_geo_curve_sample();
- register_node_type_geo_curve_to_mesh();
- register_node_type_geo_curve_to_points();
register_node_type_geo_curve_resample();
register_node_type_geo_curve_reverse();
register_node_type_geo_curve_subdivide();
diff --git a/source/blender/blenkernel/intern/spline_base.cc b/source/blender/blenkernel/intern/spline_base.cc
index e5e2fd7e87e..87d8825ad90 100644
--- a/source/blender/blenkernel/intern/spline_base.cc
+++ b/source/blender/blenkernel/intern/spline_base.cc
@@ -484,14 +484,19 @@ static void assert_sorted_array_in_range(Span<float> data, const float min, cons
*
* \note The implementation is similar to #sample_uniform_index_factors(), though
* the two loops are inverted, and obviously custom parameters are provided.
+ *
+ * \note This could have a result data argument instead of returning a span in the future.
*/
-void Spline::sample_length_parameters_to_index_factors(MutableSpan<float> parameters) const
+Array<float> Spline::sample_lengths_to_index_factors(const Span<float> parameters) const
{
const Span<float> lengths = this->evaluated_lengths();
+ const float total_length = this->length();
#ifdef DEBUG
- assert_sorted_array_in_range(parameters, 0.0f, this->length());
+ // assert_sorted_array_in_range(parameters, 0.0f, this->length());
#endif
+ Array<float> index_factors(parameters.size());
+
/* Store the length at the previous evaluated point in a variable so it can
* start out at zero (the lengths array doesn't contain 0 for the first point). */
float prev_length = 0.0f;
@@ -506,8 +511,10 @@ void Spline::sample_length_parameters_to_index_factors(MutableSpan<float> parame
}
const float factor = (sample_length - prev_length) / (lengths[i_evaluated] - prev_length);
- parameters[i_sample] = i_evaluated + factor;
+ index_factors[i_sample] = i_evaluated + factor;
}
+
+ return index_factors;
}
Spline::LookupResult Spline::lookup_data_from_index_factor(const float index_factor) const
@@ -544,6 +551,13 @@ GVArrayPtr Spline::interpolate_to_evaluated(GSpan data) const
return this->interpolate_to_evaluated(GVArray_For_GSpan(data));
}
+void Spline::sample_with_index_factors(GSpan src,
+ Span<float> index_factors,
+ GMutableSpan dst) const
+{
+ return this->sample_with_index_factors(GVArray_For_GSpan(src), index_factors, dst);
+}
+
/**
* Sample any input data with a value for each evaluated point (already interpolated to evaluated
* points) to arbitrary parameters in between the evaluated points. The interpolation is quite
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 09085ac8799..e9ce823967e 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -174,8 +174,6 @@ set(SRC
geometry/nodes/node_geo_curve_primitive_spiral.cc
geometry/nodes/node_geo_curve_primitive_star.cc
geometry/nodes/node_geo_curve_sample.cc
- geometry/nodes/node_geo_curve_to_mesh.cc
- geometry/nodes/node_geo_curve_to_points.cc
geometry/nodes/node_geo_curve_resample.cc
geometry/nodes/node_geo_curve_reverse.cc
geometry/nodes/node_geo_curve_subdivide.cc
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h
index 8a2b77118e5..73e711eb401 100644
--- a/source/blender/nodes/NOD_geometry.h
+++ b/source/blender/nodes/NOD_geometry.h
@@ -61,8 +61,6 @@ void register_node_type_geo_curve_primitive_quadrilateral(void);
void register_node_type_geo_curve_primitive_spiral(void);
void register_node_type_geo_curve_primitive_star(void);
void register_node_type_geo_curve_sample(void);
-void register_node_type_geo_curve_to_mesh(void);
-void register_node_type_geo_curve_to_points(void);
void register_node_type_geo_curve_resample(void);
void register_node_type_geo_curve_reverse(void);
void register_node_type_geo_curve_subdivide(void);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
index 5e8094169d7..d7f8bdd6bc4 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
@@ -30,26 +30,29 @@ using blender::fn::GVArray_For_GSpan;
using blender::fn::GVArray_For_Span;
using blender::fn::GVArray_Typed;
-static bNodeSocketTemplate geo_node_curve_resample_in[] = {
+static bNodeSocketTemplate geo_node_curve_sample_in[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{SOCK_STRING, N_("Parameter")},
{SOCK_GEOMETRY, N_("Curve")},
- {SOCK_GEOMETRY, N_("Attribute")},
- {SOCK_GEOMETRY, N_("Result")},
+ {SOCK_STRING, N_("Position")},
+ {SOCK_STRING, N_("Tangent")},
+ {SOCK_STRING, N_("Normal")},
+ {SOCK_STRING, N_("Attribute")},
+ {SOCK_STRING, N_("Result")},
{-1, ""},
};
-static bNodeSocketTemplate geo_node_curve_resample_out[] = {
+static bNodeSocketTemplate geo_node_curve_sample_out[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{-1, ""},
};
-static void geo_node_curve_resample_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void geo_node_curve_sample_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
}
-static void geo_node_curve_resample_init(bNodeTree *UNUSED(tree), bNode *node)
+static void geo_node_curve_sample_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurveSample *data = (NodeGeometryCurveSample *)MEM_callocN(
sizeof(NodeGeometryCurveSample), __func__);
@@ -58,7 +61,7 @@ static void geo_node_curve_resample_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-static void geo_node_curve_resample_update(bNodeTree *UNUSED(ntree), bNode *node)
+static void geo_node_curve_sample_update(bNodeTree *UNUSED(ntree), bNode *node)
{
const NodeGeometryCurveSample &node_storage = *(NodeGeometryCurveSample *)node->storage;
const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)node_storage.mode;
@@ -92,85 +95,107 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
return ATTR_DOMAIN_POINT;
}
-Array<float> calculate_spline_accumulated_lengths(Span<SplinePtr> splines)
+static CustomDataType get_result_type(const CurveComponent &curve_component,
+ const StringRef attribute_name)
{
- Array<float> lengths(splines.size() + 1);
- float length = 0.0f;
- for (const int i : splines.index_range()) {
- length += splines[i]->length();
- lengths[i] = length;
- }
- lengths.last() = length;
- return lengths;
+ std::optional<AttributeMetaData> curve_meta_data = curve_component.attribute_get_meta_data(
+ attribute_name);
+ return curve_meta_data->data_type;
}
-static void spline_sample_data(const Span<GSpan> evaluated_spans)
-{
-}
+using SamplePair = std::pair<GSpan, GMutableSpan>;
-/**
- * 1. Sort input parameters
- * 2. For each spline in the curve, sample the values on it.
- */
-static void curve_sample_attributes(const Span<SplinePtr> splines,
- const Span<float> spline_lengths,
- const Span<GSpan> evaluated_spans,
- const Span<float> parameters,
- GMutableSpan result)
+/** TODO: Investigate chunkifying the first part,
+ * since #sample_lengths_to_index_factors is single threaded. */
+static void spline_sample_attributes(const Spline &spline,
+ Span<float> lengths,
+ Span<SamplePair> samples_extrapolated,
+ Span<SamplePair> samples)
{
- Array<int> original_indices(parameters.size());
+ Array<int> original_indices(lengths.size());
for (const int i : original_indices.index_range()) {
original_indices[i] = i;
}
- std::sort(original_indices.begin(), original_indices.end(), [parameters](int a, int b) {
- return parameters[a] > parameters[b];
+ std::sort(original_indices.begin(), original_indices.end(), [lengths](int a, int b) {
+ return lengths[a] > lengths[b];
});
- Span<float> remaining_parameters = parameters;
-
- std::lower_bound
+ const Array<float> index_factors = spline.sample_lengths_to_index_factors(lengths);
- int spline_start_index = 0;
- int spline_end_index = 0;
- for (const int i : splines.index_range()) {
+ for (const SamplePair &sample : samples_extrapolated) {
+ spline.sample_with_index_factors(sample.first, index_factors, sample.second);
}
- for (const int i : range) {
+ /* TODO: Clamp index factors. */
+
+ for (const SamplePair &sample : samples) {
+ spline.sample_with_index_factors(sample.first, index_factors, sample.second);
}
}
static void execute_on_component(GeometryComponent &component,
const CurveComponent &curve_component,
const StringRef pararameter_name,
+ const StringRef position_name,
+ const StringRef tangent_name,
+ const StringRef normal_name,
const StringRef attribute_name,
const StringRef result_name)
{
+ const CurveEval &curve = *curve_component.get_for_read();
+ const Spline &spline = *curve.splines().first();
+
const AttributeDomain domain = get_result_domain(component, pararameter_name, result_name);
- GVArray_Typed<float> parameters = component.attribute_get_for_read<float>(pararameter_name,
- 0.0f);
+ GVArray_Typed<float> parameters = component.attribute_get_for_read<float>(
+ pararameter_name, domain, 0.0f);
VArray_Span<float> parameters_span{parameters};
- std::optional<AttributeMetaData> curve_meta_data = curve_component.attribute_get_meta_data(
- attribute_name);
+ /* TODO: Multiply by length if in factor mode. */
+
+ Vector<OutputAttribute> output_attributes;
+ Vector<GVArrayPtr> owned_curve_attributes;
+ Vector<SamplePair> sample_data;
+ Vector<SamplePair> sample_data_extrapolated;
+
+ if (!position_name.is_empty()) {
+ OutputAttribute result = component.attribute_try_get_for_output_only(
+ position_name, domain, CD_PROP_FLOAT3);
+ sample_data_extrapolated.append({spline.evaluated_positions(), result.as_span()});
+ output_attributes.append(std::move(result));
+ }
+ if (!tangent_name.is_empty()) {
+ OutputAttribute result = component.attribute_try_get_for_output_only(
+ tangent_name, domain, CD_PROP_FLOAT3);
+ sample_data.append({spline.evaluated_tangents(), result.as_span()});
+ output_attributes.append(std::move(result));
+ }
+ if (!normal_name.is_empty()) {
+ OutputAttribute result = component.attribute_try_get_for_output_only(
+ normal_name, domain, CD_PROP_FLOAT3);
+ sample_data.append({spline.evaluated_normals(), result.as_span()});
+ output_attributes.append(std::move(result));
+ }
+ if (!attribute_name.is_empty() && !result_name.is_empty()) {
+ OutputAttribute result = component.attribute_try_get_for_output_only(
+ result_name, domain, get_result_type(curve_component, attribute_name));
+ std::optional<GSpan> attribute = spline.attributes.get_for_read(attribute_name);
+ if (attribute) {
+ GVArrayPtr attribute_interpolated = spline.interpolate_to_evaluated(*attribute);
+ sample_data.append({attribute_interpolated->get_internal_span(), result.as_span()});
+ output_attributes.append(std::move(result));
+ owned_curve_attributes.append(std::move(attribute_interpolated));
+ }
+ }
- OutputAttribute result = component.attribute_try_get_for_output_only(
- result_name, domain, curve_meta_data->data_type);
- GMutableSpan result_span = result.as_span();
+ spline_sample_attributes(spline, parameters_span, sample_data_extrapolated, sample_data);
- const CurveEval &curve = *curve_component.get_for_read();
- const Array<float> lengths = calculate_spline_accumulated_lengths(curve.splines());
-
- threading::parallel_for(IndexRange(result_span.size()), 1024, [&](IndexRange range) {
- curve_sample_attributes(curve,
- lengths,
- attribute_name,
- parameters_span.slice(range.start(), range.size()),
- result_span.slice(range.start(), range.size()));
- });
+ for (OutputAttribute &output_attribute : output_attributes) {
+ output_attribute.save();
+ }
}
-static void geo_node_resample_exec(GeoNodeExecParams params)
+static void geo_node_sample_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
GeometrySet curve_set = params.extract_input<GeometrySet>("Curve");
@@ -184,21 +209,23 @@ static void geo_node_resample_exec(GeoNodeExecParams params)
}
const std::string pararameter_name = params.extract_input<std::string>("Parameter");
+ const std::string position_name = params.extract_input<std::string>("Position");
+ const std::string tangent_name = params.extract_input<std::string>("Tangent");
+ const std::string normal_name = params.extract_input<std::string>("Normal");
const std::string attribute_name = params.extract_input<std::string>("Attribute");
const std::string result_name = params.extract_input<std::string>("Result");
- if (pararameter_name.empty() || attribute_name.empty() || result_name.empty()) {
- params.set_output("Geometry", geometry_set);
- return;
- }
const CurveComponent &curve_component = *curve_set.get_component_for_read<CurveComponent>();
- const CurveEval &curve = *curve_component.get_for_read();
- if (!curve_component.attribute_exists(attribute_name)) {
+ if (attribute_name.empty()) {
+ if (position_name.empty() && tangent_name.empty() && normal_name.empty()) {
+ params.set_output("Geometry", geometry_set);
+ return;
+ }
+ }
+ else if (!curve_component.attribute_exists(attribute_name)) {
params.error_message_add(NodeWarningType::Error,
TIP_("No attribute with name \"") + attribute_name + "\"");
- params.set_output("Geometry", geometry_set);
- return;
}
for (const GeometryComponentType type :
@@ -207,6 +234,9 @@ static void geo_node_resample_exec(GeoNodeExecParams params)
execute_on_component(geometry_set.get_component_for_write(type),
curve_component,
pararameter_name,
+ position_name,
+ tangent_name,
+ normal_name,
attribute_name,
result_name);
}
@@ -217,17 +247,17 @@ static void geo_node_resample_exec(GeoNodeExecParams params)
} // namespace blender::nodes
-void register_node_type_geo_curve_resample()
+void register_node_type_geo_curve_sample()
{
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_CURVE_RESAMPLE, "Resample Curve", NODE_CLASS_GEOMETRY, 0);
- node_type_socket_templates(&ntype, geo_node_curve_resample_in, geo_node_curve_resample_out);
- ntype.draw_buttons = geo_node_curve_resample_layout;
+ geo_node_type_base(&ntype, GEO_NODE_CURVE_SAMPLE, "Sample Curve", NODE_CLASS_GEOMETRY, 0);
+ node_type_socket_templates(&ntype, geo_node_curve_sample_in, geo_node_curve_sample_out);
+ ntype.draw_buttons = geo_node_curve_sample_layout;
node_type_storage(
&ntype, "NodeGeometryCurveSample", node_free_standard_storage, node_copy_standard_storage);
- node_type_init(&ntype, geo_node_curve_resample_init);
- node_type_update(&ntype, geo_node_curve_resample_update);
- ntype.geometry_node_execute = blender::nodes::geo_node_resample_exec;
+ node_type_init(&ntype, geo_node_curve_sample_init);
+ node_type_update(&ntype, geo_node_curve_sample_update);
+ ntype.geometry_node_execute = blender::nodes::geo_node_sample_exec;
nodeRegisterType(&ntype);
}