Geometry Nodes: move geometry set instance handling to separate file
In an upcoming commit I'll also move the make-instances-real functionality to this file. This code is not essential to working with geometry sets in general, so it makes sense to move it to a separate header.
This commit is contained in:
@@ -467,25 +467,3 @@ class VolumeComponent : public GeometryComponent {
|
||||
|
||||
static constexpr inline GeometryComponentType static_type = GeometryComponentType::Volume;
|
||||
};
|
||||
|
||||
/**
|
||||
* Used to keep track of a group of instances using the same geometry data.
|
||||
*/
|
||||
struct GeometryInstanceGroup {
|
||||
/**
|
||||
* The geometry set instanced on each of the transforms. The components are not necessarily
|
||||
* owned here. For example, they may be owned by the instanced object. This cannot be a
|
||||
* reference because not all instanced data will necessarily have a #geometry_set_eval.
|
||||
*/
|
||||
GeometrySet geometry_set;
|
||||
|
||||
/**
|
||||
* As an optimization to avoid copying, the same geometry set can be associated with multiple
|
||||
* instances. Each instance is stored as a transform matrix here. Again, these must be owned
|
||||
* because they may be transformed from the original data. TODO: Validate that last statement.
|
||||
*/
|
||||
blender::Vector<blender::float4x4> transforms;
|
||||
};
|
||||
|
||||
blender::Vector<GeometryInstanceGroup> BKE_geometry_set_gather_instances(
|
||||
const GeometrySet &geometry_set);
|
||||
|
||||
42
source/blender/blenkernel/BKE_geometry_set_instances.hh
Normal file
42
source/blender/blenkernel/BKE_geometry_set_instances.hh
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "BKE_geometry_set.hh"
|
||||
|
||||
namespace blender::bke {
|
||||
|
||||
/**
|
||||
* Used to keep track of a group of instances using the same geometry data.
|
||||
*/
|
||||
struct GeometryInstanceGroup {
|
||||
/**
|
||||
* The geometry set instanced on each of the transforms. The components are not necessarily
|
||||
* owned here. For example, they may be owned by the instanced object. This cannot be a
|
||||
* reference because not all instanced data will necessarily have a #geometry_set_eval.
|
||||
*/
|
||||
GeometrySet geometry_set;
|
||||
|
||||
/**
|
||||
* As an optimization to avoid copying, the same geometry set can be associated with multiple
|
||||
* instances. Each instance is stored as a transform matrix here. Again, these must be owned
|
||||
* because they may be transformed from the original data. TODO: Validate that last statement.
|
||||
*/
|
||||
Vector<float4x4> transforms;
|
||||
};
|
||||
|
||||
Vector<GeometryInstanceGroup> geometry_set_gather_instances(const GeometrySet &geometry_set);
|
||||
|
||||
} // namespace blender::bke
|
||||
@@ -130,6 +130,7 @@ set(SRC
|
||||
intern/font.c
|
||||
intern/freestyle.c
|
||||
intern/geometry_set.cc
|
||||
intern/geometry_set_instances.cc
|
||||
intern/gpencil.c
|
||||
intern/gpencil_curve.c
|
||||
intern/gpencil_geom.c
|
||||
@@ -327,6 +328,7 @@ set(SRC
|
||||
BKE_freestyle.h
|
||||
BKE_geometry_set.h
|
||||
BKE_geometry_set.hh
|
||||
BKE_geometry_set_instances.hh
|
||||
BKE_global.h
|
||||
BKE_gpencil.h
|
||||
BKE_gpencil_curve.h
|
||||
|
||||
@@ -586,149 +586,6 @@ bool InstancesComponent::is_empty() const
|
||||
return transforms_.size() == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \note This doesn't extract instances from the "dupli" system for non-geometry-nodes instances.
|
||||
*/
|
||||
static GeometrySet object_get_geometry_set_for_read(const Object &object)
|
||||
{
|
||||
/* Objects evaluated with a nodes modifier will have a geometry set already. */
|
||||
if (object.runtime.geometry_set_eval != nullptr) {
|
||||
return *object.runtime.geometry_set_eval;
|
||||
}
|
||||
|
||||
/* Otherwise, construct a new geometry set with the component based on the object type. */
|
||||
GeometrySet new_geometry_set;
|
||||
|
||||
if (object.type == OB_MESH) {
|
||||
Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(
|
||||
&const_cast<Object &>(object), false);
|
||||
|
||||
if (mesh != nullptr) {
|
||||
BKE_mesh_wrapper_ensure_mdata(mesh);
|
||||
|
||||
MeshComponent &mesh_component = new_geometry_set.get_component_for_write<MeshComponent>();
|
||||
mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly);
|
||||
mesh_component.copy_vertex_group_names_from_object(object);
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: Cover the case of point-clouds without modifiers-- they may not be covered by the
|
||||
* #geometry_set_eval case above. */
|
||||
|
||||
/* TODO: Add volume support. */
|
||||
|
||||
/* Return by value since there is not always an existing geometry set owned elsewhere to use. */
|
||||
return new_geometry_set;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Geometry Set Gather Recursive Instances
|
||||
* \{ */
|
||||
|
||||
static void geometry_set_collect_recursive(const GeometrySet &geometry_set,
|
||||
const float4x4 &transform,
|
||||
Vector<GeometryInstanceGroup> &r_sets);
|
||||
|
||||
static void geometry_set_collect_recursive_collection(const Collection &collection,
|
||||
const float4x4 &transform,
|
||||
Vector<GeometryInstanceGroup> &r_sets);
|
||||
|
||||
static void geometry_set_collect_recursive_collection_instance(
|
||||
const Collection &collection, const float4x4 &transform, Vector<GeometryInstanceGroup> &r_sets)
|
||||
{
|
||||
float4x4 offset_matrix;
|
||||
unit_m4(offset_matrix.values);
|
||||
sub_v3_v3(offset_matrix.values[3], collection.instance_offset);
|
||||
const float4x4 instance_transform = transform * offset_matrix;
|
||||
geometry_set_collect_recursive_collection(collection, instance_transform, r_sets);
|
||||
}
|
||||
|
||||
static void geometry_set_collect_recursive_object(const Object &object,
|
||||
const float4x4 &transform,
|
||||
Vector<GeometryInstanceGroup> &r_sets)
|
||||
{
|
||||
GeometrySet instance_geometry_set = object_get_geometry_set_for_read(object);
|
||||
geometry_set_collect_recursive(instance_geometry_set, transform, r_sets);
|
||||
|
||||
if (object.type == OB_EMPTY) {
|
||||
const Collection *collection_instance = object.instance_collection;
|
||||
if (collection_instance != nullptr) {
|
||||
geometry_set_collect_recursive_collection_instance(*collection_instance, transform, r_sets);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void geometry_set_collect_recursive_collection(const Collection &collection,
|
||||
const float4x4 &transform,
|
||||
Vector<GeometryInstanceGroup> &r_sets)
|
||||
{
|
||||
LISTBASE_FOREACH (const CollectionObject *, collection_object, &collection.gobject) {
|
||||
BLI_assert(collection_object->ob != nullptr);
|
||||
const Object &object = *collection_object->ob;
|
||||
const float4x4 object_transform = transform * object.obmat;
|
||||
geometry_set_collect_recursive_object(object, object_transform, r_sets);
|
||||
}
|
||||
LISTBASE_FOREACH (const CollectionChild *, collection_child, &collection.children) {
|
||||
BLI_assert(collection_child->collection != nullptr);
|
||||
const Collection &collection = *collection_child->collection;
|
||||
geometry_set_collect_recursive_collection(collection, transform, r_sets);
|
||||
}
|
||||
}
|
||||
|
||||
static void geometry_set_collect_recursive(const GeometrySet &geometry_set,
|
||||
const float4x4 &transform,
|
||||
Vector<GeometryInstanceGroup> &r_sets)
|
||||
{
|
||||
r_sets.append({geometry_set, {transform}});
|
||||
|
||||
if (geometry_set.has_instances()) {
|
||||
const InstancesComponent &instances_component =
|
||||
*geometry_set.get_component_for_read<InstancesComponent>();
|
||||
|
||||
Span<float4x4> transforms = instances_component.transforms();
|
||||
Span<InstancedData> instances = instances_component.instanced_data();
|
||||
for (const int i : instances.index_range()) {
|
||||
const InstancedData &data = instances[i];
|
||||
const float4x4 instance_transform = transform * transforms[i];
|
||||
|
||||
if (data.type == INSTANCE_DATA_TYPE_OBJECT) {
|
||||
BLI_assert(data.data.object != nullptr);
|
||||
const Object &object = *data.data.object;
|
||||
geometry_set_collect_recursive_object(object, instance_transform, r_sets);
|
||||
}
|
||||
else if (data.type == INSTANCE_DATA_TYPE_COLLECTION) {
|
||||
BLI_assert(data.data.collection != nullptr);
|
||||
const Collection &collection = *data.data.collection;
|
||||
geometry_set_collect_recursive_collection_instance(collection, instance_transform, r_sets);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return flattened vector of the geometry component's recursive instances. I.e. all collection
|
||||
* instances and object instances will be expanded into the instances of their geometry components.
|
||||
* Even the instances in those geometry components' will be included.
|
||||
*
|
||||
* \note For convenience (to avoid duplication in the caller), the returned vector also contains
|
||||
* the argument geometry set.
|
||||
*
|
||||
* \note This doesn't extract instances from the "dupli" system for non-geometry-nodes instances.
|
||||
*/
|
||||
Vector<GeometryInstanceGroup> BKE_geometry_set_gather_instances(const GeometrySet &geometry_set)
|
||||
{
|
||||
Vector<GeometryInstanceGroup> result_vector;
|
||||
|
||||
float4x4 unit_transform;
|
||||
unit_m4(unit_transform.values);
|
||||
|
||||
geometry_set_collect_recursive(geometry_set, unit_transform, result_vector);
|
||||
|
||||
return result_vector;
|
||||
}
|
||||
|
||||
static blender::Array<int> generate_unique_instance_ids(Span<int> original_ids)
|
||||
{
|
||||
using namespace blender;
|
||||
|
||||
163
source/blender/blenkernel/intern/geometry_set_instances.cc
Normal file
163
source/blender/blenkernel/intern/geometry_set_instances.cc
Normal file
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "BKE_geometry_set_instances.hh"
|
||||
#include "BKE_mesh_wrapper.h"
|
||||
#include "BKE_modifier.h"
|
||||
|
||||
#include "DNA_collection_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
namespace blender::bke {
|
||||
|
||||
static void geometry_set_collect_recursive(const GeometrySet &geometry_set,
|
||||
const float4x4 &transform,
|
||||
Vector<GeometryInstanceGroup> &r_sets);
|
||||
|
||||
static void geometry_set_collect_recursive_collection(const Collection &collection,
|
||||
const float4x4 &transform,
|
||||
Vector<GeometryInstanceGroup> &r_sets);
|
||||
|
||||
/**
|
||||
* \note This doesn't extract instances from the "dupli" system for non-geometry-nodes instances.
|
||||
*/
|
||||
static GeometrySet object_get_geometry_set_for_read(const Object &object)
|
||||
{
|
||||
/* Objects evaluated with a nodes modifier will have a geometry set already. */
|
||||
if (object.runtime.geometry_set_eval != nullptr) {
|
||||
return *object.runtime.geometry_set_eval;
|
||||
}
|
||||
|
||||
/* Otherwise, construct a new geometry set with the component based on the object type. */
|
||||
GeometrySet new_geometry_set;
|
||||
|
||||
if (object.type == OB_MESH) {
|
||||
Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(
|
||||
&const_cast<Object &>(object), false);
|
||||
|
||||
if (mesh != nullptr) {
|
||||
BKE_mesh_wrapper_ensure_mdata(mesh);
|
||||
|
||||
MeshComponent &mesh_component = new_geometry_set.get_component_for_write<MeshComponent>();
|
||||
mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly);
|
||||
mesh_component.copy_vertex_group_names_from_object(object);
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: Cover the case of point-clouds without modifiers-- they may not be covered by the
|
||||
* #geometry_set_eval case above. */
|
||||
|
||||
/* TODO: Add volume support. */
|
||||
|
||||
/* Return by value since there is not always an existing geometry set owned elsewhere to use. */
|
||||
return new_geometry_set;
|
||||
}
|
||||
|
||||
static void geometry_set_collect_recursive_collection_instance(
|
||||
const Collection &collection, const float4x4 &transform, Vector<GeometryInstanceGroup> &r_sets)
|
||||
{
|
||||
float4x4 offset_matrix;
|
||||
unit_m4(offset_matrix.values);
|
||||
sub_v3_v3(offset_matrix.values[3], collection.instance_offset);
|
||||
const float4x4 instance_transform = transform * offset_matrix;
|
||||
geometry_set_collect_recursive_collection(collection, instance_transform, r_sets);
|
||||
}
|
||||
|
||||
static void geometry_set_collect_recursive_object(const Object &object,
|
||||
const float4x4 &transform,
|
||||
Vector<GeometryInstanceGroup> &r_sets)
|
||||
{
|
||||
GeometrySet instance_geometry_set = object_get_geometry_set_for_read(object);
|
||||
geometry_set_collect_recursive(instance_geometry_set, transform, r_sets);
|
||||
|
||||
if (object.type == OB_EMPTY) {
|
||||
const Collection *collection_instance = object.instance_collection;
|
||||
if (collection_instance != nullptr) {
|
||||
geometry_set_collect_recursive_collection_instance(*collection_instance, transform, r_sets);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void geometry_set_collect_recursive_collection(const Collection &collection,
|
||||
const float4x4 &transform,
|
||||
Vector<GeometryInstanceGroup> &r_sets)
|
||||
{
|
||||
LISTBASE_FOREACH (const CollectionObject *, collection_object, &collection.gobject) {
|
||||
BLI_assert(collection_object->ob != nullptr);
|
||||
const Object &object = *collection_object->ob;
|
||||
const float4x4 object_transform = transform * object.obmat;
|
||||
geometry_set_collect_recursive_object(object, object_transform, r_sets);
|
||||
}
|
||||
LISTBASE_FOREACH (const CollectionChild *, collection_child, &collection.children) {
|
||||
BLI_assert(collection_child->collection != nullptr);
|
||||
const Collection &collection = *collection_child->collection;
|
||||
geometry_set_collect_recursive_collection(collection, transform, r_sets);
|
||||
}
|
||||
}
|
||||
|
||||
static void geometry_set_collect_recursive(const GeometrySet &geometry_set,
|
||||
const float4x4 &transform,
|
||||
Vector<GeometryInstanceGroup> &r_sets)
|
||||
{
|
||||
r_sets.append({geometry_set, {transform}});
|
||||
|
||||
if (geometry_set.has_instances()) {
|
||||
const InstancesComponent &instances_component =
|
||||
*geometry_set.get_component_for_read<InstancesComponent>();
|
||||
|
||||
Span<float4x4> transforms = instances_component.transforms();
|
||||
Span<InstancedData> instances = instances_component.instanced_data();
|
||||
for (const int i : instances.index_range()) {
|
||||
const InstancedData &data = instances[i];
|
||||
const float4x4 instance_transform = transform * transforms[i];
|
||||
|
||||
if (data.type == INSTANCE_DATA_TYPE_OBJECT) {
|
||||
BLI_assert(data.data.object != nullptr);
|
||||
const Object &object = *data.data.object;
|
||||
geometry_set_collect_recursive_object(object, instance_transform, r_sets);
|
||||
}
|
||||
else if (data.type == INSTANCE_DATA_TYPE_COLLECTION) {
|
||||
BLI_assert(data.data.collection != nullptr);
|
||||
const Collection &collection = *data.data.collection;
|
||||
geometry_set_collect_recursive_collection_instance(collection, instance_transform, r_sets);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return flattened vector of the geometry component's recursive instances. I.e. all collection
|
||||
* instances and object instances will be expanded into the instances of their geometry components.
|
||||
* Even the instances in those geometry components' will be included.
|
||||
*
|
||||
* \note For convenience (to avoid duplication in the caller), the returned vector also contains
|
||||
* the argument geometry set.
|
||||
*
|
||||
* \note This doesn't extract instances from the "dupli" system for non-geometry-nodes instances.
|
||||
*/
|
||||
Vector<GeometryInstanceGroup> geometry_set_gather_instances(const GeometrySet &geometry_set)
|
||||
{
|
||||
Vector<GeometryInstanceGroup> result_vector;
|
||||
|
||||
float4x4 unit_transform;
|
||||
unit_m4(unit_transform.values);
|
||||
|
||||
geometry_set_collect_recursive(geometry_set, unit_transform, result_vector);
|
||||
|
||||
return result_vector;
|
||||
}
|
||||
|
||||
} // namespace blender::bke
|
||||
@@ -26,6 +26,8 @@
|
||||
|
||||
namespace blender::nodes {
|
||||
|
||||
using bke::GeometryInstanceGroup;
|
||||
|
||||
void gather_attribute_info(Map<std::string, AttributeInfo> &attributes,
|
||||
const GeometryComponentType component_type,
|
||||
Span<GeometryInstanceGroup> set_groups,
|
||||
@@ -261,7 +263,7 @@ GeometrySet geometry_set_realize_instances(const GeometrySet &geometry_set)
|
||||
|
||||
GeometrySet new_geometry_set;
|
||||
|
||||
Vector<GeometryInstanceGroup> set_groups = BKE_geometry_set_gather_instances(geometry_set);
|
||||
Vector<GeometryInstanceGroup> set_groups = bke::geometry_set_gather_instances(geometry_set);
|
||||
join_instance_groups_mesh(set_groups, new_geometry_set);
|
||||
join_instance_groups_pointcloud(set_groups, new_geometry_set);
|
||||
join_instance_groups_volume(set_groups, new_geometry_set);
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#include "DNA_node_types.h"
|
||||
|
||||
#include "BKE_geometry_set_instances.hh"
|
||||
#include "BKE_node.h"
|
||||
|
||||
#include "BLT_translation.h"
|
||||
@@ -61,7 +62,7 @@ struct AttributeInfo {
|
||||
*/
|
||||
void gather_attribute_info(Map<std::string, AttributeInfo> &attributes,
|
||||
const GeometryComponentType component_type,
|
||||
Span<GeometryInstanceGroup> set_groups,
|
||||
Span<bke::GeometryInstanceGroup> set_groups,
|
||||
const Set<std::string> &ignored_attributes);
|
||||
|
||||
} // namespace blender::nodes
|
||||
|
||||
Reference in New Issue
Block a user