Geometry Nodes: add conversion nodes for Grease Pencil and Curves
This adds two new nodes: * `Grease Pencil to Curves`: Converts each grease pencil layer into an instance that contains curves. * `Curves to Grease Pencil`: Converts top-level curve instances into grease pencil layers. This opens up many new opportunities: * Use grease pencil as input to other procedural systems that don't necessarily output grease pencil. * Generate grease pencil from scratch using geometry nodes. * Temporarily convert grease pencil data to curves to use more powerful features for curves processing. Some data on layers are not attributes yet unfortunately, so there is some special case handling for the `opacity` attribute. This was previously discussed at the geometry nodes workshop: https://devtalk.blender.org/t/2024-05-13-geometry-nodes-workshop-notes/34760#grease-pencil-14 Pull Request: https://projects.blender.org/blender/blender/pulls/124279
This commit is contained in:
@@ -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")
|
||||
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")
|
||||
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();
|
||||
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);
|
||||
|
||||
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))
|
||||
{
|
||||
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")) {
|
||||
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;
|
||||
}
|
||||
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
|
||||
Reference in New Issue
Block a user