GPv3: Curve to Points node

Part of #113602.
Ref !113634.
This commit is contained in:
Dalai Felinto
2023-10-13 10:09:12 +02:00
parent 6853d787db
commit 1f680c3859

View File

@@ -9,6 +9,8 @@
#include "DNA_pointcloud_types.h"
#include "BKE_grease_pencil.hh"
#include "BKE_instances.hh"
#include "BKE_pointcloud.h"
#include "GEO_resample_curves.hh"
@@ -26,7 +28,8 @@ NODE_STORAGE_FUNCS(NodeGeometryCurveToPoints)
static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Curve").supported_type(GeometryComponent::Type::Curve);
b.add_input<decl::Geometry>("Curve").supported_type(
{GeometryComponent::Type::Curve, GeometryComponent::Type::GreasePencil});
b.add_input<decl::Int>("Count")
.default_value(10)
.min(2)
@@ -131,26 +134,12 @@ static PointCloud *pointcloud_from_curves(bke::CurvesGeometry curves,
return pointcloud;
}
static void node_geo_exec(GeoNodeExecParams params)
static void curve_to_points(GeometrySet &geometry_set,
GeoNodeExecParams params,
const GeometryNodeCurveResampleMode mode,
geometry::ResampleCurvesOutputAttributeIDs resample_attributes,
AnonymousAttributeIDPtr rotation_anonymous_id)
{
const NodeGeometryCurveToPoints &storage = node_storage(params.node());
const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)storage.mode;
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
GeometryComponentEditData::remember_deformed_positions_if_necessary(geometry_set);
AnonymousAttributeIDPtr rotation_anonymous_id =
params.get_output_anonymous_attribute_id_if_needed("Rotation");
const bool need_tangent_and_normal = bool(rotation_anonymous_id);
AnonymousAttributeIDPtr tangent_anonymous_id =
params.get_output_anonymous_attribute_id_if_needed("Tangent", need_tangent_and_normal);
AnonymousAttributeIDPtr normal_anonymous_id = params.get_output_anonymous_attribute_id_if_needed(
"Normal", need_tangent_and_normal);
geometry::ResampleCurvesOutputAttributeIDs resample_attributes;
resample_attributes.tangent_id = tangent_anonymous_id.get();
resample_attributes.normal_id = normal_anonymous_id.get();
switch (mode) {
case GEO_NODE_CURVE_RESAMPLE_COUNT: {
Field<int> count = params.extract_input<Field<int>>("Count");
@@ -165,7 +154,6 @@ static void node_geo_exec(GeoNodeExecParams params)
count,
resample_attributes);
PointCloud *pointcloud = pointcloud_from_curves(std::move(dst_curves),
resample_attributes.tangent_id,
resample_attributes.normal_id,
rotation_anonymous_id.get());
@@ -197,7 +185,7 @@ static void node_geo_exec(GeoNodeExecParams params)
});
break;
}
case GEO_NODE_CURVE_RESAMPLE_EVALUATED:
case GEO_NODE_CURVE_RESAMPLE_EVALUATED: {
geometry_set.modify_geometry_sets([&](GeometrySet &geometry) {
if (const Curves *src_curves_id = geometry.get_curves()) {
const bke::CurvesGeometry &src_curves = src_curves_id->geometry.wrap();
@@ -213,6 +201,135 @@ static void node_geo_exec(GeoNodeExecParams params)
}
});
break;
}
}
}
static void grease_pencil_to_points(GeometrySet &geometry_set,
GeoNodeExecParams params,
const GeometryNodeCurveResampleMode mode,
geometry::ResampleCurvesOutputAttributeIDs resample_attributes,
AnonymousAttributeIDPtr rotation_anonymous_id,
const AnonymousAttributePropagationInfo &propagation_info)
{
Field<int> count;
Field<float> length;
switch (mode) {
case GEO_NODE_CURVE_RESAMPLE_COUNT:
count = params.extract_input<Field<int>>("Count");
break;
case GEO_NODE_CURVE_RESAMPLE_LENGTH:
length = params.extract_input<Field<float>>("Length");
break;
case GEO_NODE_CURVE_RESAMPLE_EVALUATED:
break;
}
geometry_set.modify_geometry_sets([&](GeometrySet &geometry) {
using namespace blender::bke::greasepencil;
if (geometry.has_grease_pencil()) {
const GreasePencil &grease_pencil = *geometry.get_grease_pencil();
Vector<PointCloud *> pointcloud_by_layer(grease_pencil.layers().size(), nullptr);
for (const int layer_index : grease_pencil.layers().index_range()) {
const Drawing *drawing = get_eval_grease_pencil_layer_drawing(grease_pencil, layer_index);
if (drawing == nullptr) {
continue;
}
const bke::CurvesGeometry &src_curves = drawing->strokes();
bke::GreasePencilLayerFieldContext field_context(
grease_pencil, ATTR_DOMAIN_CURVE, layer_index);
bke::CurvesGeometry dst_curves;
switch (mode) {
case GEO_NODE_CURVE_RESAMPLE_COUNT: {
dst_curves = geometry::resample_to_count(src_curves,
field_context,
fn::make_constant_field<bool>(true),
count,
resample_attributes);
break;
}
case GEO_NODE_CURVE_RESAMPLE_LENGTH: {
dst_curves = geometry::resample_to_length(src_curves,
field_context,
fn::make_constant_field<bool>(true),
length,
resample_attributes);
break;
}
case GEO_NODE_CURVE_RESAMPLE_EVALUATED: {
dst_curves = geometry::resample_to_evaluated(src_curves,
field_context,
fn::make_constant_field<bool>(true),
resample_attributes);
break;
}
}
pointcloud_by_layer[layer_index] = pointcloud_from_curves(std::move(dst_curves),
resample_attributes.tangent_id,
resample_attributes.normal_id,
rotation_anonymous_id.get());
}
if (!pointcloud_by_layer.is_empty()) {
InstancesComponent &instances_component =
geometry_set.get_component_for_write<InstancesComponent>();
bke::Instances *instances = instances_component.get_for_write();
if (instances == nullptr) {
instances = new bke::Instances();
instances_component.replace(instances);
}
for (PointCloud *pointcloud : pointcloud_by_layer) {
if (!pointcloud) {
/* Add an empty reference so the number of layers and instances match.
* This makes it easy to reconstruct the layers afterwards and keep their
* attributes. */
const int handle = instances->add_reference(bke::InstanceReference());
instances->add_instance(handle, float4x4::identity());
continue;
}
GeometrySet temp_set = GeometrySet::from_pointcloud(pointcloud);
const int handle = instances->add_reference(bke::InstanceReference{temp_set});
instances->add_instance(handle, float4x4::identity());
}
GeometrySet::propagate_attributes_from_layer_to_instances(
geometry.get_grease_pencil()->attributes(),
geometry.get_instances_for_write()->attributes_for_write(),
propagation_info);
}
}
});
geometry_set.replace_grease_pencil(nullptr);
}
static void node_geo_exec(GeoNodeExecParams params)
{
const NodeGeometryCurveToPoints &storage = node_storage(params.node());
const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)storage.mode;
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
GeometryComponentEditData::remember_deformed_positions_if_necessary(geometry_set);
AnonymousAttributeIDPtr rotation_anonymous_id =
params.get_output_anonymous_attribute_id_if_needed("Rotation");
const bool need_tangent_and_normal = bool(rotation_anonymous_id);
AnonymousAttributeIDPtr tangent_anonymous_id =
params.get_output_anonymous_attribute_id_if_needed("Tangent", need_tangent_and_normal);
AnonymousAttributeIDPtr normal_anonymous_id = params.get_output_anonymous_attribute_id_if_needed(
"Normal", need_tangent_and_normal);
geometry::ResampleCurvesOutputAttributeIDs resample_attributes;
resample_attributes.tangent_id = tangent_anonymous_id.get();
resample_attributes.normal_id = normal_anonymous_id.get();
const AnonymousAttributePropagationInfo &propagation_info = params.get_output_propagation_info(
"Points");
if (geometry_set.has_curves()) {
curve_to_points(geometry_set, params, mode, resample_attributes, rotation_anonymous_id);
}
if (geometry_set.has_grease_pencil()) {
grease_pencil_to_points(
geometry_set, params, mode, resample_attributes, rotation_anonymous_id, propagation_info);
}
params.set_output("Points", std::move(geometry_set));