diff options
author | Hans Goudey <h.goudey@me.com> | 2021-07-15 15:25:20 +0300 |
---|---|---|
committer | Hans Goudey <h.goudey@me.com> | 2021-07-15 15:25:20 +0300 |
commit | 36ea32a3f03164b89db12d8d1f1ce6b8ec8d25a7 (patch) | |
tree | 81b2ef4f30558e1d99f20e716b9ef480300be922 /source/blender/nodes | |
parent | dc0c71d3ae772c9afdec0718ae135b9b91f57e8b (diff) |
Basic structure is funcitonal, needs polishing and additional options (may crash)
Diffstat (limited to 'source/blender/nodes')
-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/geometry/nodes/node_geo_curve_sample.cc | 172 |
3 files changed, 101 insertions, 75 deletions
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); } |