Geometry Nodes: add conversion nodes for Grease Pencil and Curves #124279
@ -114,11 +114,13 @@ class NODE_MT_geometry_node_GEO_CURVE_OPERATIONS(Menu):
|
||||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeCurvesToGreasePencil")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeCurveToMesh")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeCurveToPoints")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeDeformCurvesOnSurface")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeFillCurve")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeFilletCurve")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeGreasePencilToCurves")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeInterpolateCurves")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeResampleCurve")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeReverseCurve")
|
||||
|
@ -1371,6 +1371,8 @@ void BKE_nodetree_remove_layer_n(bNodeTree *ntree, Scene *scene, int layer_index
|
||||
#define GEO_NODE_GIZMO_LINEAR 2141
|
||||
#define GEO_NODE_GIZMO_DIAL 2142
|
||||
#define GEO_NODE_GIZMO_TRANSFORM 2143
|
||||
#define GEO_NODE_CURVES_TO_GREASE_PENCIL 2144
|
||||
#define GEO_NODE_GREASE_PENCIL_TO_CURVES 2145
|
||||
|
||||
/** \} */
|
||||
|
||||
|
@ -332,6 +332,7 @@ DefNode(GeometryNode, GEO_NODE_CURVE_TO_MESH, 0, "CURVE_TO_MESH", CurveToMesh, "
|
||||
DefNode(GeometryNode, GEO_NODE_CURVE_TO_POINTS, 0, "CURVE_TO_POINTS", CurveToPoints, "Curve to Points", "Generate a point cloud by sampling positions along curves")
|
||||
DefNode(GeometryNode, GEO_NODE_CURVE_TOPOLOGY_CURVE_OF_POINT, 0, "CURVE_OF_POINT", CurveOfPoint, "Curve of Point", "Retrieve the curve a control point is part of")
|
||||
DefNode(GeometryNode, GEO_NODE_CURVE_TOPOLOGY_POINTS_OF_CURVE, 0, "POINTS_OF_CURVE", PointsOfCurve, "Points of Curve", "Retrieve a point index within a curve")
|
||||
DefNode(GeometryNode, GEO_NODE_CURVES_TO_GREASE_PENCIL, 0, "CURVES_TO_GREASE_PENCIL", CurvesToGreasePencil, "Curves to Grease Pencil", "Convert the curves in each top-level instance into Grease Pencil layer")
|
||||
JacquesLucke marked this conversation as resolved
Outdated
|
||||
DefNode(GeometryNode, GEO_NODE_DEFORM_CURVES_ON_SURFACE, 0, "DEFORM_CURVES_ON_SURFACE", DeformCurvesOnSurface, "Deform Curves on Surface", "Translate and rotate curves based on changes between the object's original and evaluated surface mesh")
|
||||
DefNode(GeometryNode, GEO_NODE_DELETE_GEOMETRY, 0, "DELETE_GEOMETRY", DeleteGeometry, "Delete Geometry", "Remove selected elements of a geometry")
|
||||
DefNode(GeometryNode, GEO_NODE_DISTRIBUTE_POINTS_IN_GRID, 0, "DISTRIBUTE_POINTS_IN_GRID", DistributePointsInGrid, "Distribute Points in Grid", "Generate points inside a volume grid")
|
||||
@ -353,6 +354,7 @@ DefNode(GeometryNode, GEO_NODE_GET_NAMED_GRID, 0, "GET_NAMED_GRID", GetNamedGrid
|
||||
DefNode(GeometryNode, GEO_NODE_GIZMO_LINEAR, 0, "GIZMO_LINEAR", GizmoLinear, "Linear Gizmo", "Show a linear gizmo in the viewport for a value")
|
||||
DefNode(GeometryNode, GEO_NODE_GIZMO_DIAL, 0, "GIZMO_DIAL", GizmoDial, "Dial Gizmo", "Show a dial gizmo in the viewport for a value")
|
||||
DefNode(GeometryNode, GEO_NODE_GIZMO_TRANSFORM, rna_def_geo_gizmo_transform, "GIZMO_TRANSFORM", GizmoTransform, "Transform Gizmo", "Show a transform gizmo in the viewport")
|
||||
DefNode(GeometryNode, GEO_NODE_GREASE_PENCIL_TO_CURVES, 0, "GREASE_PENCIL_TO_CURVES", GreasePencilToCurves, "Grease Pencil to Curves", "Convert Grease Pencil layers into curve instances")
|
||||
JacquesLucke marked this conversation as resolved
Outdated
Hans Goudey
commented
Here too Here too
|
||||
DefNode(GeometryNode, GEO_NODE_GRID_TO_MESH, 0, "GRID_TO_MESH", GridToMesh, "Grid to Mesh", "Generate a mesh on the \"surface\" of a volume grid")
|
||||
DefNode(GeometryNode, GEO_NODE_IMAGE_INFO, 0, "IMAGE_INFO", ImageInfo, "Image Info", "Retrieve information about an image")
|
||||
DefNode(GeometryNode, GEO_NODE_IMAGE_TEXTURE, def_geo_image_texture, "IMAGE_TEXTURE", ImageTexture, "Image Texture", "Sample values from an image texture")
|
||||
|
@ -67,6 +67,7 @@ set(SRC
|
||||
nodes/node_geo_curve_topology_curve_of_point.cc
|
||||
nodes/node_geo_curve_topology_points_of_curve.cc
|
||||
nodes/node_geo_curve_trim.cc
|
||||
nodes/node_geo_curves_to_grease_pencil.cc
|
||||
nodes/node_geo_deform_curves_on_surface.cc
|
||||
nodes/node_geo_delete_geometry.cc
|
||||
nodes/node_geo_distribute_points_in_grid.cc
|
||||
@ -87,6 +88,7 @@ set(SRC
|
||||
nodes/node_geo_gizmo_dial.cc
|
||||
nodes/node_geo_gizmo_linear.cc
|
||||
nodes/node_geo_gizmo_transform.cc
|
||||
nodes/node_geo_grease_pencil_to_curves.cc
|
||||
nodes/node_geo_grid_to_mesh.cc
|
||||
nodes/node_geo_image.cc
|
||||
nodes/node_geo_image_info.cc
|
||||
|
@ -0,0 +1,238 @@
|
||||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
#include "BKE_instances.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_curves_to_grease_pencil_cc {
|
||||
|
||||
static void node_declare(NodeDeclarationBuilder &b)
|
||||
{
|
||||
b.add_input<decl::Geometry>("Curves").description("Either plain curves or curve instances");
|
||||
b.add_input<decl::Bool>("Selection")
|
||||
.default_value(true)
|
||||
.hide_value()
|
||||
.field_on_all()
|
||||
.description("Either a curve or instance selection");
|
||||
b.add_input<decl::Bool>("Instances as Layers")
|
||||
.default_value(true)
|
||||
.description("Create a separate layer for each instance");
|
||||
b.add_output<decl::Geometry>("Grease Pencil").propagate_all();
|
||||
}
|
||||
|
||||
static GreasePencil *curves_to_grease_pencil_with_one_layer(
|
||||
const Curves &curves_id,
|
||||
const Field<bool> &selection_field,
|
||||
const StringRefNull layer_name,
|
||||
const AnonymousAttributePropagationInfo &propagation_info)
|
||||
{
|
||||
bke::CurvesGeometry curves = curves_id.geometry.wrap();
|
||||
|
||||
const bke::CurvesFieldContext field_context{curves, AttrDomain::Curve};
|
||||
FieldEvaluator evaluator{field_context, curves.curves_num()};
|
||||
evaluator.set_selection(selection_field);
|
||||
evaluator.evaluate();
|
||||
const IndexMask curves_selection = evaluator.get_evaluated_selection_as_mask();
|
||||
IndexMaskMemory memory;
|
||||
const IndexMask curves_to_delete = curves_selection.complement(curves.curves_range(), memory);
|
||||
curves.remove_curves(curves_to_delete, propagation_info);
|
||||
|
||||
GreasePencil *grease_pencil = BKE_grease_pencil_new_nomain();
|
||||
JacquesLucke marked this conversation as resolved
Outdated
Falk David
commented
I'd prefer if we didn't use I'd prefer if we didn't use `grease_pencil->add_empty_drawings(instances_num);` and just call
`bke::greasepencil::Drawing *drawing = grease_pencil.insert_frame(layer, framenum);` instead.
Jacques Lucke
commented
Am I missing something or does it result in quadratic run-time if I add the drawings one by one? Am I missing something or does it result in quadratic run-time if I add the drawings one by one?
Falk David
commented
If you want to add multiple keyframes at once, then we should add a Manipulating the drawings array and drawing indices on frames should ideally only happen within the If you want to add multiple keyframes at once, then we should add a `grease_pencil.insert_frames` API.
Manipulating the drawings array and drawing indices on frames should ideally only happen within the `GreasePencil` methods.
|
||||
bke::greasepencil::Layer &layer = grease_pencil->add_layer(layer_name);
|
||||
bke::greasepencil::Drawing *drawing = grease_pencil->insert_frame(
|
||||
layer, grease_pencil->runtime->eval_frame);
|
||||
BLI_assert(drawing);
|
||||
drawing->strokes_for_write() = std::move(curves);
|
||||
|
||||
/* Transfer materials. */
|
||||
const int materials_num = curves_id.totcol;
|
||||
grease_pencil->material_array_num = materials_num;
|
||||
grease_pencil->material_array = MEM_cnew_array<Material *>(materials_num, __func__);
|
||||
initialized_copy_n(curves_id.mat, materials_num, grease_pencil->material_array);
|
||||
JacquesLucke marked this conversation as resolved
Outdated
Falk David
commented
Seems like Seems like `layer_i` is unused.
|
||||
|
||||
return grease_pencil;
|
||||
}
|
||||
|
||||
static GreasePencil *curve_instances_to_grease_pencil_layers(
|
||||
const bke::Instances &instances,
|
||||
const Field<bool> &selection_field,
|
||||
const AnonymousAttributePropagationInfo &propagation_info)
|
||||
{
|
||||
const Span<int> reference_handles = instances.reference_handles();
|
||||
const Span<bke::InstanceReference> references = instances.references();
|
||||
const Span<float4x4> transforms = instances.transforms();
|
||||
|
||||
const int instances_num = instances.instances_num();
|
||||
if (instances_num == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const bke::InstancesFieldContext field_context{instances};
|
||||
FieldEvaluator evaluator{field_context, instances_num};
|
||||
evaluator.set_selection(selection_field);
|
||||
evaluator.evaluate();
|
||||
const IndexMask instance_selection = evaluator.get_evaluated_selection_as_mask();
|
||||
|
||||
const int layer_num = instance_selection.size();
|
||||
if (layer_num == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GreasePencil *grease_pencil = BKE_grease_pencil_new_nomain();
|
||||
|
||||
VectorSet<Material *> all_materials;
|
||||
|
||||
instance_selection.foreach_index([&](const int instance_i) {
|
||||
const bke::InstanceReference &reference = references[reference_handles[instance_i]];
|
||||
|
||||
bke::greasepencil::Layer &layer = grease_pencil->add_layer(reference.name());
|
||||
grease_pencil->insert_frame(layer, grease_pencil->runtime->eval_frame);
|
||||
layer.set_local_transform(transforms[instance_i]);
|
||||
|
||||
bke::greasepencil::Drawing *drawing = grease_pencil->get_eval_drawing(layer);
|
||||
BLI_assert(drawing);
|
||||
|
||||
GeometrySet instance_geometry;
|
||||
reference.to_geometry_set(instance_geometry);
|
||||
const Curves *instance_curves = instance_geometry.get_curves();
|
||||
if (!instance_curves) {
|
||||
return;
|
||||
}
|
||||
|
||||
bke::CurvesGeometry &strokes = drawing->strokes_for_write();
|
||||
strokes = instance_curves->geometry.wrap();
|
||||
|
||||
Vector<int> new_material_indices;
|
||||
for (Material *material : Span{instance_curves->mat, instance_curves->totcol}) {
|
||||
new_material_indices.append(all_materials.index_of_or_add(material));
|
||||
}
|
||||
|
||||
/* Remap material indices. */
|
||||
bke::SpanAttributeWriter<int> material_indices =
|
||||
strokes.attributes_for_write().lookup_or_add_for_write_span<int>("material_index",
|
||||
bke::AttrDomain::Curve);
|
||||
for (int &material_index : material_indices.span) {
|
||||
if (material_index >= 0 && material_index < new_material_indices.size()) {
|
||||
material_index = new_material_indices[material_index];
|
||||
}
|
||||
}
|
||||
material_indices.finish();
|
||||
});
|
||||
|
||||
grease_pencil->material_array_num = all_materials.size();
|
||||
grease_pencil->material_array = MEM_cnew_array<Material *>(all_materials.size(), __func__);
|
||||
initialized_copy_n(all_materials.data(), all_materials.size(), grease_pencil->material_array);
|
||||
|
||||
const bke::AttributeAccessor instances_attributes = instances.attributes();
|
||||
bke::MutableAttributeAccessor grease_pencil_attributes = grease_pencil->attributes_for_write();
|
||||
instances_attributes.for_all([&](const AttributeIDRef &attribute_id,
|
||||
const AttributeMetaData &meta_data) {
|
||||
if (instances_attributes.is_builtin(attribute_id) &&
|
||||
!grease_pencil_attributes.is_builtin(attribute_id))
|
||||
{
|
||||
JacquesLucke marked this conversation as resolved
Outdated
Falk David
commented
I would probably add a comment here saying that we're now manually transfering the opacity to the layers and that this should be removed once the opacity is just a layer attribute. I would probably add a comment here saying that we're now manually transfering the opacity to the layers and that this should be removed once the opacity is just a layer attribute.
|
||||
return true;
|
||||
}
|
||||
if (ELEM(attribute_id, "opacity")) {
|
||||
return true;
|
||||
}
|
||||
if (attribute_id.is_anonymous() && !propagation_info.propagate(attribute_id.anonymous_id())) {
|
||||
return true;
|
||||
}
|
||||
const GAttributeReader src_attribute = instances_attributes.lookup(attribute_id);
|
||||
if (!src_attribute) {
|
||||
return true;
|
||||
}
|
||||
if (instance_selection.size() == instances_num && src_attribute.varray.is_span() &&
|
||||
src_attribute.sharing_info)
|
||||
{
|
||||
/* Try reusing existing attribute array. */
|
||||
grease_pencil_attributes.add(
|
||||
attribute_id,
|
||||
AttrDomain::Layer,
|
||||
meta_data.data_type,
|
||||
bke::AttributeInitShared{src_attribute.varray.get_internal_span().data(),
|
||||
*src_attribute.sharing_info});
|
||||
return true;
|
||||
}
|
||||
if (!grease_pencil_attributes.add(
|
||||
attribute_id, AttrDomain::Layer, meta_data.data_type, bke::AttributeInitConstruct()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
bke::GSpanAttributeWriter dst_attribute = grease_pencil_attributes.lookup_for_write_span(
|
||||
attribute_id);
|
||||
array_utils::gather(src_attribute.varray, instance_selection, dst_attribute.span);
|
||||
dst_attribute.finish();
|
||||
return true;
|
||||
});
|
||||
|
||||
{
|
||||
/* Manually propagate "opacity" data, because it's not a layer attribute on grease pencil
|
||||
* yet. */
|
||||
if (const AttributeReader opacity_attribute = instances_attributes.lookup<float>("opacity")) {
|
||||
JacquesLucke marked this conversation as resolved
Outdated
Hans Goudey
commented
Would probably wrap nicer without the outer braces and using Would probably wrap nicer without the outer braces and using `AttributeReader` instead of `AttributeReader<float>`
|
||||
instance_selection.foreach_index([&](const int instance_i, const int layer_i) {
|
||||
grease_pencil->layer(layer_i)->opacity = opacity_attribute.varray[instance_i];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return grease_pencil;
|
||||
}
|
||||
|
||||
static void node_geo_exec(GeoNodeExecParams params)
|
||||
{
|
||||
GeometrySet curves_geometry = params.extract_input<GeometrySet>("Curves");
|
||||
const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
|
||||
const bool instances_as_layers = params.extract_input<bool>("Instances as Layers");
|
||||
const AnonymousAttributePropagationInfo &propagation_info = params.get_output_propagation_info(
|
||||
"Grease Pencil");
|
||||
|
||||
GreasePencil *grease_pencil = nullptr;
|
||||
if (instances_as_layers) {
|
||||
if (curves_geometry.has_curves()) {
|
||||
params.error_message_add(NodeWarningType::Info, TIP_("Non-instance curves are ignored"));
|
||||
}
|
||||
const bke::Instances *instances = curves_geometry.get_instances();
|
||||
if (!instances) {
|
||||
params.set_default_remaining_outputs();
|
||||
return;
|
||||
}
|
||||
grease_pencil = curve_instances_to_grease_pencil_layers(
|
||||
*instances, selection_field, propagation_info);
|
||||
}
|
||||
else {
|
||||
if (curves_geometry.has_instances()) {
|
||||
params.error_message_add(NodeWarningType::Info, TIP_("Instances are ignored"));
|
||||
}
|
||||
const Curves *curves_id = curves_geometry.get_curves();
|
||||
if (!curves_id) {
|
||||
params.set_default_remaining_outputs();
|
||||
return;
|
||||
}
|
||||
grease_pencil = curves_to_grease_pencil_with_one_layer(
|
||||
*curves_id, selection_field, curves_geometry.name, propagation_info);
|
||||
}
|
||||
|
||||
GeometrySet grease_pencil_geometry = GeometrySet::from_grease_pencil(grease_pencil);
|
||||
grease_pencil_geometry.name = std::move(curves_geometry.name);
|
||||
params.set_output("Grease Pencil", std::move(grease_pencil_geometry));
|
||||
}
|
||||
|
||||
static void node_register()
|
||||
{
|
||||
static bke::bNodeType ntype;
|
||||
geo_node_type_base(
|
||||
&ntype, GEO_NODE_CURVES_TO_GREASE_PENCIL, "Curves to Grease Pencil", NODE_CLASS_GEOMETRY);
|
||||
ntype.geometry_node_execute = node_geo_exec;
|
||||
ntype.declare = node_declare;
|
||||
bke::node_type_size(&ntype, 160, 100, 320);
|
||||
|
||||
bke::nodeRegisterType(&ntype);
|
||||
}
|
||||
NOD_REGISTER_NODE(node_register)
|
||||
|
||||
} // namespace blender::nodes::node_geo_curves_to_grease_pencil_cc
|
@ -0,0 +1,152 @@
|
||||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
#include "BKE_instances.hh"
|
||||
|
||||
#include "GEO_realize_instances.hh"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_grease_pencil_to_curves_cc {
|
||||
|
||||
static void node_declare(NodeDeclarationBuilder &b)
|
||||
{
|
||||
b.add_input<decl::Geometry>("Grease Pencil")
|
||||
.supported_type(bke::GeometryComponent::Type::GreasePencil);
|
||||
b.add_input<decl::Bool>("Selection")
|
||||
.default_value(true)
|
||||
.hide_value()
|
||||
.field_on_all()
|
||||
.description("Select the layers to convert");
|
||||
b.add_input<decl::Bool>("Layers as Instances")
|
||||
.default_value(true)
|
||||
.description("Create a separate curve instance for every layer");
|
||||
b.add_output<decl::Geometry>("Curves").propagate_all();
|
||||
}
|
||||
|
||||
static void node_geo_exec(GeoNodeExecParams params)
|
||||
{
|
||||
GeometrySet grease_pencil_geometry = params.extract_input<GeometrySet>("Grease Pencil");
|
||||
const GreasePencil *grease_pencil = grease_pencil_geometry.get_grease_pencil();
|
||||
if (!grease_pencil) {
|
||||
params.set_default_remaining_outputs();
|
||||
return;
|
||||
}
|
||||
|
||||
const Span<const bke::greasepencil::Layer *> layers = grease_pencil->layers();
|
||||
const int layers_num = layers.size();
|
||||
|
||||
const bke::GreasePencilFieldContext field_context{*grease_pencil};
|
||||
const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
|
||||
FieldEvaluator evaluator{field_context, layers_num};
|
||||
evaluator.set_selection(selection_field);
|
||||
evaluator.evaluate();
|
||||
const IndexMask layer_selection = evaluator.get_evaluated_selection_as_mask();
|
||||
|
||||
const int instances_num = layer_selection.size();
|
||||
if (instances_num == 0) {
|
||||
params.set_default_remaining_outputs();
|
||||
return;
|
||||
}
|
||||
|
||||
bke::Instances *instances = new bke::Instances();
|
||||
std::optional<int> empty_geometry_handle;
|
||||
|
||||
layer_selection.foreach_index([&](const int layer_i) {
|
||||
const bke::greasepencil::Layer &layer = *layers[layer_i];
|
||||
const bke::greasepencil::Drawing *drawing = grease_pencil->get_eval_drawing(layer);
|
||||
const float4x4 transform = layer.local_transform();
|
||||
if (!drawing) {
|
||||
if (!empty_geometry_handle.has_value()) {
|
||||
empty_geometry_handle = instances->add_reference(bke::InstanceReference());
|
||||
}
|
||||
instances->add_instance(*empty_geometry_handle, transform);
|
||||
return;
|
||||
}
|
||||
const bke::CurvesGeometry &layer_strokes = drawing->strokes();
|
||||
Curves *curves_id = bke::curves_new_nomain(layer_strokes);
|
||||
curves_id->mat = static_cast<Material **>(MEM_dupallocN(grease_pencil->material_array));
|
||||
curves_id->totcol = grease_pencil->material_array_num;
|
||||
GeometrySet curves_geometry = GeometrySet::from_curves(curves_id);
|
||||
curves_geometry.name = layer.name();
|
||||
const int handle = instances->add_reference(std::move(curves_geometry));
|
||||
instances->add_instance(handle, transform);
|
||||
});
|
||||
|
||||
const bke::AttributeAccessor grease_pencil_attributes = grease_pencil->attributes();
|
||||
bke::MutableAttributeAccessor instances_attributes = instances->attributes_for_write();
|
||||
grease_pencil_attributes.for_all(
|
||||
[&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
|
||||
if (ELEM(attribute_id, "opacity")) {
|
||||
return true;
|
||||
}
|
||||
const GAttributeReader src_attribute = grease_pencil_attributes.lookup(attribute_id);
|
||||
if (!src_attribute) {
|
||||
return true;
|
||||
}
|
||||
if (src_attribute.varray.is_span() && src_attribute.sharing_info) {
|
||||
/* Try reusing existing attribute array. */
|
||||
instances_attributes.add(
|
||||
attribute_id,
|
||||
AttrDomain::Instance,
|
||||
meta_data.data_type,
|
||||
bke::AttributeInitShared{src_attribute.varray.get_internal_span().data(),
|
||||
*src_attribute.sharing_info});
|
||||
return true;
|
||||
}
|
||||
if (!instances_attributes.add(attribute_id,
|
||||
AttrDomain::Instance,
|
||||
meta_data.data_type,
|
||||
bke::AttributeInitConstruct()))
|
||||
{
|
||||
return true;
|
||||
JacquesLucke marked this conversation as resolved
Outdated
Falk David
commented
Same as above. Same as above.
|
||||
}
|
||||
bke::GSpanAttributeWriter dst_attribute = instances_attributes.lookup_for_write_span(
|
||||
attribute_id);
|
||||
array_utils::gather(src_attribute.varray, layer_selection, dst_attribute.span);
|
||||
dst_attribute.finish();
|
||||
return true;
|
||||
});
|
||||
|
||||
{
|
||||
/* Manually propagate "opacity" data, because it's not a layer attribute on grease pencil
|
||||
* yet. */
|
||||
SpanAttributeWriter<float> opacity_attribute =
|
||||
instances_attributes.lookup_or_add_for_write_only_span<float>("opacity",
|
||||
AttrDomain::Instance);
|
||||
layer_selection.foreach_index([&](const int layer_i, const int instance_i) {
|
||||
opacity_attribute.span[instance_i] = grease_pencil->layer(layer_i)->opacity;
|
||||
});
|
||||
opacity_attribute.finish();
|
||||
}
|
||||
|
||||
GeometrySet curves_geometry = GeometrySet::from_instances(instances);
|
||||
curves_geometry.name = std::move(grease_pencil_geometry.name);
|
||||
|
||||
const bool layers_as_instances = params.get_input<bool>("Layers as Instances");
|
||||
if (!layers_as_instances) {
|
||||
geometry::RealizeInstancesOptions options;
|
||||
options.propagation_info = params.get_output_propagation_info("Curves");
|
||||
curves_geometry = geometry::realize_instances(curves_geometry, options);
|
||||
}
|
||||
|
||||
params.set_output("Curves", std::move(curves_geometry));
|
||||
}
|
||||
|
||||
static void node_register()
|
||||
{
|
||||
static bke::bNodeType ntype;
|
||||
geo_node_type_base(
|
||||
&ntype, GEO_NODE_GREASE_PENCIL_TO_CURVES, "Grease Pencil to Curves", NODE_CLASS_GEOMETRY);
|
||||
ntype.geometry_node_execute = node_geo_exec;
|
||||
ntype.declare = node_declare;
|
||||
bke::node_type_size(&ntype, 160, 100, 320);
|
||||
|
||||
bke::nodeRegisterType(&ntype);
|
||||
}
|
||||
NOD_REGISTER_NODE(node_register)
|
||||
|
||||
} // namespace blender::nodes::node_geo_grease_pencil_to_curves_cc
|
a grease pencil layer
->Grease Pencil layers
A layer is created for each instance so better if it was plural. And GP is a "brand name" so it should be capitalized. At least I heard Pablo say something like that. (Same in the other description).
Correct.
Grease Pencil
always needs to be capitalized in the UI 👍