Fix: Geometry Nodes: crash when converting layers to instances

The crash/assert happened because the case when there are instances already was not handled.

Pull Request: https://projects.blender.org/blender/blender/pulls/127299
This commit is contained in:
Iliya Katueshenock
2024-11-05 11:05:28 +01:00
committed by Jacques Lucke
parent 334e9be8f4
commit 74f98b1e92
5 changed files with 50 additions and 29 deletions
@@ -658,6 +658,8 @@ class InstancesComponent : public GeometryComponent {
bool is_empty() const final;
Instances *release();
bool owns_direct_data() const override;
void ensure_owns_direct_data() override;
@@ -102,6 +102,14 @@ void InstancesComponent::replace(Instances *instances, GeometryOwnershipType own
ownership_ = ownership;
}
Instances *InstancesComponent::release()
{
BLI_assert(this->is_mutable());
Instances *instance = instances_;
instances_ = nullptr;
return instance;
}
void InstancesComponent::count_memory(MemoryCounter &memory) const
{
if (instances_) {
@@ -10,6 +10,7 @@
#include "UI_resources.hh"
#include "GEO_join_geometries.hh"
#include "GEO_randomize.hh"
#include "node_geometry_util.hh"
@@ -70,13 +71,7 @@ static void grease_pencil_to_mesh(GeometrySet &geometry_set,
return;
}
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);
}
bke::Instances *instances = new bke::Instances();
for (Mesh *mesh : mesh_by_layer) {
if (!mesh) {
/* Add an empty reference so the number of layers and instances match.
@@ -92,8 +87,14 @@ static void grease_pencil_to_mesh(GeometrySet &geometry_set,
}
GeometrySet::propagate_attributes_from_layer_to_instances(
geometry_set.get_grease_pencil()->attributes(),
geometry_set.get_instances_for_write()->attributes_for_write(),
instances->attributes_for_write(),
attribute_filter);
InstancesComponent &dst_component = geometry_set.get_component_for_write<InstancesComponent>();
GeometrySet new_instances = geometry::join_geometries(
{GeometrySet::from_instances(dst_component.release()),
GeometrySet::from_instances(instances)},
attribute_filter);
dst_component.replace(new_instances.get_component_for_write<InstancesComponent>().release());
geometry_set.replace_grease_pencil(nullptr);
}
@@ -13,6 +13,7 @@
#include "BKE_instances.hh"
#include "BKE_pointcloud.hh"
#include "GEO_join_geometries.hh"
#include "GEO_resample_curves.hh"
#include "NOD_rna_define.hh"
@@ -272,13 +273,7 @@ static void grease_pencil_to_points(GeometrySet &geometry_set,
rotation_anonymous_id);
}
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);
}
bke::Instances *instances = new bke::Instances();
for (PointCloud *pointcloud : pointcloud_by_layer) {
if (!pointcloud) {
/* Add an empty reference so the number of layers and instances match.
@@ -294,8 +289,15 @@ static void grease_pencil_to_points(GeometrySet &geometry_set,
}
GeometrySet::propagate_attributes_from_layer_to_instances(
geometry.get_grease_pencil()->attributes(),
geometry.get_instances_for_write()->attributes_for_write(),
instances->attributes_for_write(),
attribute_filter);
InstancesComponent &dst_component = geometry.get_component_for_write<InstancesComponent>();
GeometrySet new_instances = geometry::join_geometries(
{GeometrySet::from_instances(dst_component.release()),
GeometrySet::from_instances(instances)},
attribute_filter);
dst_component.replace(
new_instances.get_component_for_write<InstancesComponent>().release());
}
}
});
@@ -12,6 +12,8 @@
#include "BKE_grease_pencil.hh"
#include "BKE_instances.hh"
#include "GEO_join_geometries.hh"
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_instance_on_points_cc {
@@ -225,6 +227,7 @@ static void node_geo_exec(GeoNodeExecParams params)
if (geometry_set.has_grease_pencil()) {
using namespace bke::greasepencil;
const GreasePencil &grease_pencil = *geometry_set.get_grease_pencil();
bke::Instances *instances = new bke::Instances();
for (const int layer_index : grease_pencil.layers().index_range()) {
const Drawing *drawing = grease_pencil.get_eval_drawing(grease_pencil.layer(layer_index));
if (drawing == nullptr) {
@@ -235,30 +238,35 @@ static void node_geo_exec(GeoNodeExecParams params)
/* 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.
* Although in this particular case we don't propagate the attributes. */
const int handle = dst_instances->add_reference(bke::InstanceReference());
dst_instances->add_instance(handle, float4x4::identity());
const int handle = instances->add_reference(bke::InstanceReference());
instances->add_instance(handle, float4x4::identity());
continue;
}
/* TODO: Attributes are not propagating from the curves or the points. */
bke::Instances *instances = new bke::Instances();
bke::Instances *layer_instances = new bke::Instances();
const bke::GreasePencilLayerFieldContext field_context(
grease_pencil, AttrDomain::Point, layer_index);
add_instances_from_component(*instances,
add_instances_from_component(*layer_instances,
src_curves.attributes(),
instance,
field_context,
params,
attributes_to_propagate);
GeometrySet temp_set = GeometrySet::from_instances(instances);
const int handle = dst_instances->add_reference(bke::InstanceReference{temp_set});
dst_instances->add_instance(handle, float4x4::identity());
}
if (geometry_set.has_instances()) {
GeometrySet::propagate_attributes_from_layer_to_instances(
geometry_set.get_grease_pencil()->attributes(),
geometry_set.get_instances_for_write()->attributes_for_write(),
attribute_filter);
GeometrySet temp_set = GeometrySet::from_instances(layer_instances);
const int handle = instances->add_reference(bke::InstanceReference{temp_set});
instances->add_instance(handle, float4x4::identity());
}
GeometrySet::propagate_attributes_from_layer_to_instances(
geometry_set.get_grease_pencil()->attributes(),
instances->attributes_for_write(),
attribute_filter);
GeometrySet new_instances = geometry::join_geometries(
{GeometrySet::from_instances(dst_instances, bke::GeometryOwnershipType::Editable),
GeometrySet::from_instances(instances)},
attribute_filter);
instances_component.replace(
new_instances.get_component_for_write<InstancesComponent>().release());
geometry_set.replace_grease_pencil(nullptr);
}
geometry_set.remove_geometry_during_modify();