Geometry Nodes: simplify retrieving data of instance reference

Specifically it's now easier to get the name, geometry set and icon.
This commit is contained in:
Jacques Lucke 2024-07-06 15:38:12 +02:00
parent 406554c11e
commit 7bce839e25
8 changed files with 135 additions and 103 deletions

@ -86,6 +86,16 @@ class InstanceReference {
GeometrySet &geometry_set();
const GeometrySet &geometry_set() const;
/**
* Converts the instance reference to a geometry set, even if it was an object or collection
* before.
*
* \note Uses out-parameter to be able to use #GeometrySet forward declaration.
*/
void to_geometry_set(GeometrySet &r_geometry_set) const;
std::string name() const;
bool owns_direct_data() const;
void ensure_owns_direct_data();

@ -3,13 +3,20 @@
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_array_utils.hh"
#include "BLI_listbase.h"
#include "BLI_rand.hh"
#include "BLI_task.hh"
#include "DNA_collection_types.h"
#include "DNA_object_types.h"
#include "BKE_customdata.hh"
#include "BKE_geometry_set.hh"
#include "BKE_geometry_set_instances.hh"
#include "BKE_instances.hh"
#include "BLT_translation.hh"
namespace blender::bke {
InstanceReference::InstanceReference(GeometrySet geometry_set)
@ -35,6 +42,67 @@ bool InstanceReference::owns_direct_data() const
return geometry_set_->owns_direct_data();
}
static void convert_collection_to_instances(const Collection &collection,
bke::Instances &instances)
{
LISTBASE_FOREACH (CollectionChild *, collection_child, &collection.children) {
float4x4 transform = float4x4::identity();
transform.location() += float3(collection_child->collection->instance_offset);
transform.location() -= float3(collection.instance_offset);
const int handle = instances.add_reference(*collection_child->collection);
instances.add_instance(handle, transform);
}
LISTBASE_FOREACH (CollectionObject *, collection_object, &collection.gobject) {
float4x4 transform = float4x4::identity();
transform.location() -= float3(collection.instance_offset);
transform *= (collection_object->ob)->object_to_world();
const int handle = instances.add_reference(*collection_object->ob);
instances.add_instance(handle, transform);
}
}
void InstanceReference::to_geometry_set(GeometrySet &r_geometry_set) const
{
r_geometry_set.clear();
switch (type_) {
case Type::Object: {
const Object &object = this->object();
r_geometry_set = bke::object_get_evaluated_geometry_set(object);
break;
}
case Type::Collection: {
const Collection &collection = this->collection();
std::unique_ptr<bke::Instances> instances_ptr = std::make_unique<bke::Instances>();
convert_collection_to_instances(collection, *instances_ptr);
r_geometry_set.replace_instances(instances_ptr.release());
break;
}
case Type::GeometrySet: {
r_geometry_set = this->geometry_set();
break;
}
case Type::None: {
break;
}
}
}
std::string InstanceReference::name() const
{
switch (type_) {
case Type::Object:
return this->object().id.name + 2;
case Type::Collection:
return this->collection().id.name + 2;
case Type::GeometrySet:
return IFACE_("Geometry");
case Type::None:
break;
}
return "";
}
bool operator==(const InstanceReference &a, const InstanceReference &b)
{
if (a.geometry_set_ && b.geometry_set_) {

@ -12,6 +12,7 @@ struct Base;
struct ListBase;
struct SpaceOutliner;
struct bContext;
struct ID;
bool ED_outliner_collections_editor_poll(bContext *C);
@ -47,3 +48,5 @@ void ED_outliner_select_sync_from_outliner(bContext *C, SpaceOutliner *space_out
* Copy sync select dirty flag from window manager to all outliners to be synced lazily on draw.
*/
void ED_outliner_select_sync_flag_outliners(const bContext *C);
int ED_outliner_icon_from_id(const ID &id);

@ -4130,3 +4130,8 @@ void draw_outliner(const bContext *C)
/** \} */
} // namespace blender::ed::outliner
int ED_outliner_icon_from_id(const ID &id)
{
return blender::ed::outliner::tree_element_get_icon_from_id(&id);
}

@ -32,6 +32,7 @@
#include "DEG_depsgraph_query.hh"
#include "ED_curves.hh"
#include "ED_outliner.hh"
#include "ED_spreadsheet.hh"
#include "NOD_geometry_nodes_lazy_function.hh"
@ -42,6 +43,8 @@
#include "RNA_access.hh"
#include "RNA_enum_types.hh"
#include "UI_resources.hh"
#include "bmesh.hh"
#include "spreadsheet_data_source_geometry.hh"
@ -545,6 +548,26 @@ int VolumeDataSource::tot_rows() const
return BKE_volume_num_grids(volume);
}
int get_instance_reference_icon(const bke::InstanceReference &reference)
{
switch (reference.type()) {
case bke::InstanceReference::Type::Object: {
const Object &object = reference.object();
return ED_outliner_icon_from_id(object.id);
}
case bke::InstanceReference::Type::Collection: {
return ICON_OUTLINER_COLLECTION;
}
case bke::InstanceReference::Type::GeometrySet: {
return ICON_EMPTY_AXIS;
}
case bke::InstanceReference::Type::None: {
break;
}
}
return ICON_NONE;
}
bke::GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspreadsheet,
Object *object_eval)
{

@ -9,6 +9,7 @@
#include "BLI_resource_scope.hh"
#include "BKE_geometry_set.hh"
#include "BKE_instances.hh"
#include "spreadsheet_data_source.hh"
@ -109,6 +110,8 @@ class VolumeDataSource : public DataSource {
int tot_rows() const override;
};
int get_instance_reference_icon(const bke::InstanceReference &reference);
std::unique_ptr<DataSource> data_source_from_geometry(const bContext *C, Object *object_eval);
} // namespace blender::ed::spreadsheet

@ -15,6 +15,7 @@
#include "BKE_instances.hh"
#include "spreadsheet_column_values.hh"
#include "spreadsheet_data_source_geometry.hh"
#include "spreadsheet_layout.hh"
#include "DNA_collection_types.h"
@ -203,60 +204,22 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
}
else if (data.type().is<bke::InstanceReference>()) {
const bke::InstanceReference value = data.get<bke::InstanceReference>(real_index);
switch (value.type()) {
case bke::InstanceReference::Type::Object: {
const Object &object = value.object();
uiDefIconTextBut(params.block,
UI_BTYPE_LABEL,
0,
ICON_OBJECT_DATA,
object.id.name + 2,
params.xmin,
params.ymin,
params.width,
params.height,
nullptr,
0,
0,
nullptr);
break;
}
case bke::InstanceReference::Type::Collection: {
Collection &collection = value.collection();
uiDefIconTextBut(params.block,
UI_BTYPE_LABEL,
0,
ICON_OUTLINER_COLLECTION,
collection.id.name + 2,
params.xmin,
params.ymin,
params.width,
params.height,
nullptr,
0,
0,
nullptr);
break;
}
case bke::InstanceReference::Type::GeometrySet: {
uiDefIconTextBut(params.block,
UI_BTYPE_LABEL,
0,
ICON_MESH_DATA,
"Geometry",
params.xmin,
params.ymin,
params.width,
params.height,
nullptr,
0,
0,
nullptr);
break;
}
case bke::InstanceReference::Type::None: {
break;
}
const std::string name = value.name();
const int icon = get_instance_reference_icon(value);
if (!name.empty()) {
uiDefIconTextBut(params.block,
UI_BTYPE_LABEL,
0,
icon,
name.c_str(),
params.xmin,
params.ymin,
params.width,
params.height,
nullptr,
0,
0,
nullptr);
}
}
else if (data.type().is<std::string>()) {

@ -320,25 +320,6 @@ static int64_t get_final_points_num(const GatherTasks &tasks)
return points_num;
}
static void realize_collections(Collection &collection, bke::Instances &instances)
{
LISTBASE_FOREACH (CollectionChild *, collection_child, &collection.children) {
float4x4 transform = float4x4::identity();
transform.location() += float3(collection_child->collection->instance_offset);
transform.location() -= float3(collection.instance_offset);
const int handle = instances.add_reference(*collection_child->collection);
instances.add_instance(handle, transform);
}
LISTBASE_FOREACH (CollectionObject *, collection_object, &collection.gobject) {
float4x4 transform = float4x4::identity();
transform.location() -= float3(collection.instance_offset);
transform *= (collection_object->ob)->object_to_world();
const int handle = instances.add_reference(*collection_object->ob);
instances.add_instance(handle, transform);
}
}
static void copy_transformed_positions(const Span<float3> src,
const float4x4 &transform,
MutableSpan<float3> dst)
@ -500,33 +481,6 @@ static Vector<std::pair<int, GSpan>> prepare_attribute_fallbacks(
return attributes_to_override;
}
static bke::GeometrySet geometry_set_from_reference(const InstanceReference &reference)
{
switch (reference.type()) {
case InstanceReference::Type::Object: {
const Object &object = reference.object();
const bke::GeometrySet geometry_set = bke::object_get_evaluated_geometry_set(object);
return geometry_set;
}
case InstanceReference::Type::Collection: {
std::unique_ptr<bke::Instances> instances_ptr = std::make_unique<bke::Instances>();
realize_collections(reference.collection(), *instances_ptr);
bke::GeometrySet geometry_set;
geometry_set.replace_instances(instances_ptr.release());
return geometry_set;
}
case InstanceReference::Type::GeometrySet: {
const bke::GeometrySet geometry_set = reference.geometry_set();
return geometry_set;
}
case InstanceReference::Type::None: {
/* Return an empty GeometrySet for None type. */
return {};
}
}
return {};
}
/**
* Calls #fn for every geometry in the given #InstanceReference. Also passes on the transformation
* that is applied to every instance.
@ -538,7 +492,8 @@ static void foreach_geometry_in_reference(
FunctionRef<void(const bke::GeometrySet &geometry_set, const float4x4 &transform, uint32_t id)>
fn)
{
bke::GeometrySet geometry_set = geometry_set_from_reference(reference);
bke::GeometrySet geometry_set;
reference.to_geometry_set(geometry_set);
fn(geometry_set, base_transform, id);
}
@ -770,8 +725,10 @@ static bool attribute_foreach(const bke::GeometrySet &geometry_set,
IndexMask(IndexRange(instances.instances_num()));
indices.foreach_index([&](const int i) {
const int child_depth_target = (0 == current_depth) ? instance_depth[i] : depth_target;
bke::GeometrySet instance_geometry_set = geometry_set_from_reference(
instances.references()[instances.reference_handles()[i]]);
const bke::InstanceReference &reference =
instances.references()[instances.reference_handles()[i]];
bke::GeometrySet instance_geometry_set;
reference.to_geometry_set(instance_geometry_set);
/* Process child instances with a recursive call. */
if (current_depth != child_depth_target) {
child_has_component = child_has_component | attribute_foreach(instance_geometry_set,