Geometry Nodes: Support curve data in the geometry delete node

This commit implements support for deleting curve data in the geometry
delete node. Spline domain and point domain attributes are supported.

Differential Revision: https://developer.blender.org/D11464
This commit is contained in:
Hans Goudey 2021-06-03 18:33:37 -04:00
parent c18675b12c
commit e5a1cadb2f
Notes: blender-bot 2023-02-14 05:59:31 +01:00
Referenced by issue #86640, Geometry Delete Node
1 changed files with 151 additions and 0 deletions

View File

@ -26,6 +26,8 @@
#include "node_geometry_util.hh"
using blender::bke::CustomDataAttributes;
/* Code from the mask modifier in MOD_mask.cc. */
extern void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh,
Mesh &dst_mesh,
@ -55,6 +57,149 @@ static bNodeSocketTemplate geo_node_delete_geometry_out[] = {
namespace blender::nodes {
template<typename T> static void copy_data(Span<T> data, MutableSpan<T> r_data, IndexMask mask)
{
for (const int i_out : mask.index_range()) {
r_data[i_out] = data[mask[i_out]];
}
}
static void spline_copy_builtin_attributes(const Spline &spline,
Spline &r_spline,
const IndexMask mask)
{
copy_data(spline.positions(), r_spline.positions(), mask);
copy_data(spline.radii(), r_spline.radii(), mask);
copy_data(spline.tilts(), r_spline.tilts(), mask);
switch (spline.type()) {
case Spline::Type::Poly:
break;
case Spline::Type::Bezier: {
const BezierSpline &src = static_cast<const BezierSpline &>(spline);
BezierSpline &dst = static_cast<BezierSpline &>(r_spline);
copy_data(src.handle_positions_left(), dst.handle_positions_left(), mask);
copy_data(src.handle_positions_right(), dst.handle_positions_right(), mask);
copy_data(src.handle_types_left(), dst.handle_types_left(), mask);
copy_data(src.handle_types_right(), dst.handle_types_right(), mask);
break;
}
case Spline::Type::NURBS: {
const NURBSpline &src = static_cast<const NURBSpline &>(spline);
NURBSpline &dst = static_cast<NURBSpline &>(r_spline);
copy_data(src.weights(), dst.weights(), mask);
break;
}
}
}
static void copy_dynamic_attributes(const CustomDataAttributes &src,
CustomDataAttributes &dst,
const IndexMask mask)
{
src.foreach_attribute(
[&](StringRefNull name, const AttributeMetaData &meta_data) {
std::optional<GSpan> src_attribute = src.get_for_read(name);
BLI_assert(src_attribute);
if (!dst.create(name, meta_data.data_type)) {
/* Since the source spline of the same type had the attribute, adding it should work. */
BLI_assert_unreachable();
}
std::optional<GMutableSpan> new_attribute = dst.get_for_write(name);
BLI_assert(new_attribute);
attribute_math::convert_to_static_type(new_attribute->type(), [&](auto dummy) {
using T = decltype(dummy);
copy_data(src_attribute->typed<T>(), new_attribute->typed<T>(), mask);
});
return true;
},
ATTR_DOMAIN_POINT);
}
static SplinePtr spline_delete(const Spline &spline, const IndexMask mask)
{
SplinePtr new_spline = spline.copy_settings();
new_spline->resize(mask.size());
spline_copy_builtin_attributes(spline, *new_spline, mask);
copy_dynamic_attributes(spline.attributes, new_spline->attributes, mask);
return new_spline;
}
static std::unique_ptr<CurveEval> curve_delete(const CurveEval &input_curve,
const StringRef name,
const bool invert)
{
Span<SplinePtr> input_splines = input_curve.splines();
std::unique_ptr<CurveEval> output_curve = std::make_unique<CurveEval>();
/* Keep track of which splines were copied to the result to copy spline domain attributes. */
Vector<int64_t> copied_splines;
if (input_curve.attributes.get_for_read(name)) {
GVArray_Typed<bool> selection = input_curve.attributes.get_for_read<bool>(name, false);
for (const int i : input_splines.index_range()) {
if (selection[i] == invert) {
output_curve->add_spline(input_splines[i]->copy());
copied_splines.append(i);
}
}
}
else {
/* Reuse index vector for each spline. */
Vector<int64_t> indices_to_copy;
for (const int i : input_splines.index_range()) {
const Spline &spline = *input_splines[i];
GVArray_Typed<bool> selection = spline.attributes.get_for_read<bool>(name, false);
indices_to_copy.clear();
for (const int i_point : IndexRange(spline.size())) {
if (selection[i_point] == invert) {
indices_to_copy.append(i_point);
}
}
/* Avoid creating an empty spline. */
if (indices_to_copy.is_empty()) {
continue;
}
SplinePtr new_spline = spline_delete(spline, IndexMask(indices_to_copy));
output_curve->add_spline(std::move(new_spline));
copied_splines.append(i);
}
}
if (copied_splines.is_empty()) {
return {};
}
output_curve->attributes.reallocate(output_curve->splines().size());
copy_dynamic_attributes(
input_curve.attributes, output_curve->attributes, IndexMask(copied_splines));
return output_curve;
}
static void delete_curve_selection(const CurveComponent &in_component,
CurveComponent &r_component,
const StringRef selection_name,
const bool invert)
{
std::unique_ptr<CurveEval> r_curve = curve_delete(
*in_component.get_for_read(), selection_name, invert);
if (r_curve) {
r_component.replace(r_curve.release());
}
else {
r_component.clear();
}
}
static void delete_point_cloud_selection(const PointCloudComponent &in_component,
PointCloudComponent &out_component,
const StringRef selection_name,
@ -509,6 +654,12 @@ static void geo_node_delete_geometry_exec(GeoNodeExecParams params)
selection_name,
invert);
}
if (geometry_set.has<CurveComponent>()) {
delete_curve_selection(*geometry_set.get_component_for_read<CurveComponent>(),
out_set.get_component_for_write<CurveComponent>(),
selection_name,
invert);
}
params.set_output("Geometry", std::move(out_set));
}