2021-02-16 12:07:10 +01:00
|
|
|
/*
|
|
|
|
* 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"
|
2021-05-19 11:02:25 +02:00
|
|
|
#include "BKE_material.h"
|
2021-02-16 12:30:42 +01:00
|
|
|
#include "BKE_mesh.h"
|
2021-02-16 12:07:10 +01:00
|
|
|
#include "BKE_mesh_wrapper.h"
|
|
|
|
#include "BKE_modifier.h"
|
2021-02-16 12:30:42 +01:00
|
|
|
#include "BKE_pointcloud.h"
|
Geometry Nodes: Initial basic curve data support
This patch adds initial curve support to geometry nodes. Currently
there is only one node available, the "Curve to Mesh" node, T87428.
However, the aim of the changes here is larger than just supporting
curve data in nodes-- it also uses the opportunity to add better spline
data structures, intended to replace the existing curve evaluation code.
The curve code in Blender is quite old, and it's generally regarded as
some of the messiest, hardest-to-understand code as well. The classes
in `BKE_spline.hh` aim to be faster, more extensible, and much more
easily understandable. Further explanation can be found in comments in
that file.
Initial builtin spline attributes are supported-- reading and writing
from the `cyclic` and `resolution` attributes works with any of the
attribute nodes. Also, only Z-up normal calculation is implemented
at the moment, and tilts do not apply yet.
**Limitations**
- For now, you must bring curves into the node tree with an "Object
Info" node. Changes to the curve modifier stack will come later.
- Converting to a mesh is necessary to visualize the curve data.
Further progress can be tracked in: T87245
Higher level design document: https://wiki.blender.org/wiki/Modules/Physics_Nodes/Projects/EverythingNodes/CurveNodes
Differential Revision: https://developer.blender.org/D11091
2021-05-03 12:29:17 -05:00
|
|
|
#include "BKE_spline.hh"
|
2021-02-16 12:07:10 +01:00
|
|
|
|
|
|
|
#include "DNA_collection_types.h"
|
2021-02-16 12:30:42 +01:00
|
|
|
#include "DNA_mesh_types.h"
|
|
|
|
#include "DNA_meshdata_types.h"
|
2021-02-16 12:07:10 +01:00
|
|
|
#include "DNA_object_types.h"
|
2021-02-18 10:13:56 +01:00
|
|
|
#include "DNA_pointcloud_types.h"
|
2021-02-16 12:07:10 +01:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2021-04-16 13:05:32 +02:00
|
|
|
static void add_final_mesh_as_geometry_component(const Object &object, GeometrySet &geometry_set)
|
|
|
|
{
|
|
|
|
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 = geometry_set.get_component_for_write<MeshComponent>();
|
|
|
|
mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly);
|
|
|
|
mesh_component.copy_vertex_group_names_from_object(object);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Geometry Nodes: Initial basic curve data support
This patch adds initial curve support to geometry nodes. Currently
there is only one node available, the "Curve to Mesh" node, T87428.
However, the aim of the changes here is larger than just supporting
curve data in nodes-- it also uses the opportunity to add better spline
data structures, intended to replace the existing curve evaluation code.
The curve code in Blender is quite old, and it's generally regarded as
some of the messiest, hardest-to-understand code as well. The classes
in `BKE_spline.hh` aim to be faster, more extensible, and much more
easily understandable. Further explanation can be found in comments in
that file.
Initial builtin spline attributes are supported-- reading and writing
from the `cyclic` and `resolution` attributes works with any of the
attribute nodes. Also, only Z-up normal calculation is implemented
at the moment, and tilts do not apply yet.
**Limitations**
- For now, you must bring curves into the node tree with an "Object
Info" node. Changes to the curve modifier stack will come later.
- Converting to a mesh is necessary to visualize the curve data.
Further progress can be tracked in: T87245
Higher level design document: https://wiki.blender.org/wiki/Modules/Physics_Nodes/Projects/EverythingNodes/CurveNodes
Differential Revision: https://developer.blender.org/D11091
2021-05-03 12:29:17 -05:00
|
|
|
static void add_curve_data_as_geometry_component(const Object &object, GeometrySet &geometry_set)
|
|
|
|
{
|
|
|
|
BLI_assert(object.type == OB_CURVE);
|
|
|
|
if (object.data != nullptr) {
|
|
|
|
std::unique_ptr<CurveEval> curve = curve_eval_from_dna_curve(*(Curve *)object.data);
|
|
|
|
CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>();
|
|
|
|
curve_component.replace(curve.release(), GeometryOwnershipType::Owned);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-16 12:07:10 +01:00
|
|
|
/**
|
|
|
|
* \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)
|
|
|
|
{
|
2021-04-16 13:05:32 +02:00
|
|
|
if (object.type == OB_MESH && object.mode == OB_MODE_EDIT) {
|
|
|
|
GeometrySet geometry_set;
|
|
|
|
if (object.runtime.geometry_set_eval != nullptr) {
|
|
|
|
/* `geometry_set_eval` only contains non-mesh components, see `editbmesh_build_data`. */
|
|
|
|
geometry_set = *object.runtime.geometry_set_eval;
|
|
|
|
}
|
|
|
|
add_final_mesh_as_geometry_component(object, geometry_set);
|
|
|
|
return geometry_set;
|
|
|
|
}
|
2021-02-16 12:07:10 +01:00
|
|
|
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. */
|
2021-04-16 13:05:32 +02:00
|
|
|
GeometrySet geometry_set;
|
2021-02-16 12:07:10 +01:00
|
|
|
if (object.type == OB_MESH) {
|
2021-04-16 13:05:32 +02:00
|
|
|
add_final_mesh_as_geometry_component(object, geometry_set);
|
2021-02-16 12:07:10 +01:00
|
|
|
}
|
Geometry Nodes: Initial basic curve data support
This patch adds initial curve support to geometry nodes. Currently
there is only one node available, the "Curve to Mesh" node, T87428.
However, the aim of the changes here is larger than just supporting
curve data in nodes-- it also uses the opportunity to add better spline
data structures, intended to replace the existing curve evaluation code.
The curve code in Blender is quite old, and it's generally regarded as
some of the messiest, hardest-to-understand code as well. The classes
in `BKE_spline.hh` aim to be faster, more extensible, and much more
easily understandable. Further explanation can be found in comments in
that file.
Initial builtin spline attributes are supported-- reading and writing
from the `cyclic` and `resolution` attributes works with any of the
attribute nodes. Also, only Z-up normal calculation is implemented
at the moment, and tilts do not apply yet.
**Limitations**
- For now, you must bring curves into the node tree with an "Object
Info" node. Changes to the curve modifier stack will come later.
- Converting to a mesh is necessary to visualize the curve data.
Further progress can be tracked in: T87245
Higher level design document: https://wiki.blender.org/wiki/Modules/Physics_Nodes/Projects/EverythingNodes/CurveNodes
Differential Revision: https://developer.blender.org/D11091
2021-05-03 12:29:17 -05:00
|
|
|
else if (object.type == OB_CURVE) {
|
|
|
|
add_curve_data_as_geometry_component(object, geometry_set);
|
|
|
|
}
|
2021-02-16 12:07:10 +01:00
|
|
|
|
|
|
|
/* 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. */
|
2021-04-16 13:05:32 +02:00
|
|
|
return geometry_set;
|
2021-02-16 12:07:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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>();
|
|
|
|
|
2021-05-04 10:16:24 +02:00
|
|
|
Span<float4x4> transforms = instances_component.instance_transforms();
|
|
|
|
Span<int> handles = instances_component.instance_reference_handles();
|
|
|
|
Span<InstanceReference> references = instances_component.references();
|
|
|
|
for (const int i : transforms.index_range()) {
|
|
|
|
const InstanceReference &reference = references[handles[i]];
|
2021-02-16 12:07:10 +01:00
|
|
|
const float4x4 instance_transform = transform * transforms[i];
|
|
|
|
|
2021-05-04 10:16:24 +02:00
|
|
|
switch (reference.type()) {
|
|
|
|
case InstanceReference::Type::Object: {
|
|
|
|
Object &object = reference.object();
|
|
|
|
geometry_set_collect_recursive_object(object, instance_transform, r_sets);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case InstanceReference::Type::Collection: {
|
|
|
|
Collection &collection = reference.collection();
|
|
|
|
geometry_set_collect_recursive_collection_instance(
|
|
|
|
collection, instance_transform, r_sets);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case InstanceReference::Type::None: {
|
|
|
|
break;
|
|
|
|
}
|
2021-02-16 12:07:10 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
2021-03-25 14:54:27 -04:00
|
|
|
void geometry_set_gather_instances(const GeometrySet &geometry_set,
|
|
|
|
Vector<GeometryInstanceGroup> &r_instance_groups)
|
2021-02-16 12:07:10 +01:00
|
|
|
{
|
|
|
|
float4x4 unit_transform;
|
|
|
|
unit_m4(unit_transform.values);
|
|
|
|
|
2021-03-25 14:54:27 -04:00
|
|
|
geometry_set_collect_recursive(geometry_set, unit_transform, r_instance_groups);
|
2021-02-16 12:07:10 +01:00
|
|
|
}
|
|
|
|
|
2021-04-08 12:19:09 -05:00
|
|
|
static bool collection_instance_attribute_foreach(const Collection &collection,
|
|
|
|
const AttributeForeachCallback callback,
|
|
|
|
const int limit,
|
|
|
|
int &count);
|
|
|
|
|
|
|
|
static bool instances_attribute_foreach_recursive(const GeometrySet &geometry_set,
|
|
|
|
const AttributeForeachCallback callback,
|
|
|
|
const int limit,
|
|
|
|
int &count);
|
|
|
|
|
|
|
|
static bool object_instance_attribute_foreach(const Object &object,
|
|
|
|
const AttributeForeachCallback callback,
|
|
|
|
const int limit,
|
|
|
|
int &count)
|
|
|
|
{
|
|
|
|
GeometrySet instance_geometry_set = object_get_geometry_set_for_read(object);
|
|
|
|
if (!instances_attribute_foreach_recursive(instance_geometry_set, callback, limit, count)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (object.type == OB_EMPTY) {
|
|
|
|
const Collection *collection_instance = object.instance_collection;
|
|
|
|
if (collection_instance != nullptr) {
|
|
|
|
if (!collection_instance_attribute_foreach(*collection_instance, callback, limit, count)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool collection_instance_attribute_foreach(const Collection &collection,
|
|
|
|
const AttributeForeachCallback callback,
|
|
|
|
const int limit,
|
|
|
|
int &count)
|
|
|
|
{
|
|
|
|
LISTBASE_FOREACH (const CollectionObject *, collection_object, &collection.gobject) {
|
|
|
|
BLI_assert(collection_object->ob != nullptr);
|
|
|
|
const Object &object = *collection_object->ob;
|
|
|
|
if (!object_instance_attribute_foreach(object, callback, limit, count)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
LISTBASE_FOREACH (const CollectionChild *, collection_child, &collection.children) {
|
|
|
|
BLI_assert(collection_child->collection != nullptr);
|
|
|
|
const Collection &collection = *collection_child->collection;
|
|
|
|
if (!collection_instance_attribute_foreach(collection, callback, limit, count)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \return True if the recursive iteration should continue, false if the limit is reached or the
|
|
|
|
* callback has returned false indicating it should stop.
|
|
|
|
*/
|
|
|
|
static bool instances_attribute_foreach_recursive(const GeometrySet &geometry_set,
|
|
|
|
const AttributeForeachCallback callback,
|
|
|
|
const int limit,
|
|
|
|
int &count)
|
|
|
|
{
|
|
|
|
for (const GeometryComponent *component : geometry_set.get_components_for_read()) {
|
|
|
|
if (!component->attribute_foreach(callback)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now that this this geometry set is visited, increase the count and check with the limit. */
|
|
|
|
if (limit > 0 && count++ > limit) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const InstancesComponent *instances_component =
|
|
|
|
geometry_set.get_component_for_read<InstancesComponent>();
|
|
|
|
if (instances_component == nullptr) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-05-04 10:16:24 +02:00
|
|
|
for (const InstanceReference &reference : instances_component->references()) {
|
|
|
|
switch (reference.type()) {
|
|
|
|
case InstanceReference::Type::Object: {
|
|
|
|
const Object &object = reference.object();
|
|
|
|
if (!object_instance_attribute_foreach(object, callback, limit, count)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
break;
|
2021-04-08 12:19:09 -05:00
|
|
|
}
|
2021-05-04 10:16:24 +02:00
|
|
|
case InstanceReference::Type::Collection: {
|
|
|
|
const Collection &collection = reference.collection();
|
|
|
|
if (!collection_instance_attribute_foreach(collection, callback, limit, count)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case InstanceReference::Type::None: {
|
|
|
|
break;
|
2021-04-08 12:19:09 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Call the callback on all of this geometry set's components, including geometry sets from
|
|
|
|
* instances and recursive instances. This is necessary to access available attributes without
|
|
|
|
* making all of the set's geometry real.
|
|
|
|
*
|
|
|
|
* \param limit: The total number of geometry sets to visit before returning early. This is used
|
|
|
|
* to avoid looking through too many geometry sets recursively, as an explicit tradeoff in favor
|
|
|
|
* of performance at the cost of visiting every unique attribute.
|
|
|
|
*/
|
|
|
|
void geometry_set_instances_attribute_foreach(const GeometrySet &geometry_set,
|
|
|
|
const AttributeForeachCallback callback,
|
|
|
|
const int limit)
|
|
|
|
{
|
|
|
|
int count = 0;
|
|
|
|
instances_attribute_foreach_recursive(geometry_set, callback, limit, count);
|
|
|
|
}
|
|
|
|
|
2021-04-07 15:49:02 -05:00
|
|
|
void geometry_set_gather_instances_attribute_info(Span<GeometryInstanceGroup> set_groups,
|
|
|
|
Span<GeometryComponentType> component_types,
|
|
|
|
const Set<std::string> &ignored_attributes,
|
|
|
|
Map<std::string, AttributeKind> &r_attributes)
|
2021-02-16 12:30:42 +01:00
|
|
|
{
|
|
|
|
for (const GeometryInstanceGroup &set_group : set_groups) {
|
|
|
|
const GeometrySet &set = set_group.geometry_set;
|
2021-02-18 10:13:56 +01:00
|
|
|
for (const GeometryComponentType component_type : component_types) {
|
|
|
|
if (!set.has(component_type)) {
|
2021-02-16 12:30:42 +01:00
|
|
|
continue;
|
|
|
|
}
|
2021-02-18 10:13:56 +01:00
|
|
|
const GeometryComponent &component = *set.get_component_for_read(component_type);
|
|
|
|
|
2021-02-23 15:15:23 +01:00
|
|
|
component.attribute_foreach([&](StringRefNull name, const AttributeMetaData &meta_data) {
|
2021-02-18 10:13:56 +01:00
|
|
|
if (ignored_attributes.contains(name)) {
|
2021-02-23 15:15:23 +01:00
|
|
|
return true;
|
2021-02-18 10:13:56 +01:00
|
|
|
}
|
2021-02-23 15:15:23 +01:00
|
|
|
auto add_info = [&](AttributeKind *attribute_kind) {
|
|
|
|
attribute_kind->domain = meta_data.domain;
|
|
|
|
attribute_kind->data_type = meta_data.data_type;
|
2021-02-18 10:13:56 +01:00
|
|
|
};
|
2021-02-23 15:15:23 +01:00
|
|
|
auto modify_info = [&](AttributeKind *attribute_kind) {
|
|
|
|
attribute_kind->domain = meta_data.domain; /* TODO: Use highest priority domain. */
|
2021-02-18 12:32:34 +01:00
|
|
|
attribute_kind->data_type = bke::attribute_data_type_highest_complexity(
|
2021-02-23 15:15:23 +01:00
|
|
|
{attribute_kind->data_type, meta_data.data_type});
|
2021-02-18 10:13:56 +01:00
|
|
|
};
|
|
|
|
|
2021-04-07 15:49:02 -05:00
|
|
|
r_attributes.add_or_modify(name, add_info, modify_info);
|
2021-02-23 15:15:23 +01:00
|
|
|
return true;
|
|
|
|
});
|
2021-02-16 12:30:42 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-18 10:13:56 +01:00
|
|
|
static Mesh *join_mesh_topology_and_builtin_attributes(Span<GeometryInstanceGroup> set_groups,
|
|
|
|
const bool convert_points_to_vertices)
|
2021-02-16 12:30:42 +01:00
|
|
|
{
|
|
|
|
int totverts = 0;
|
|
|
|
int totloops = 0;
|
|
|
|
int totedges = 0;
|
|
|
|
int totpolys = 0;
|
|
|
|
int64_t cd_dirty_vert = 0;
|
|
|
|
int64_t cd_dirty_poly = 0;
|
|
|
|
int64_t cd_dirty_edge = 0;
|
|
|
|
int64_t cd_dirty_loop = 0;
|
2021-05-19 11:02:25 +02:00
|
|
|
VectorSet<Material *> materials;
|
|
|
|
|
2021-02-16 12:30:42 +01:00
|
|
|
for (const GeometryInstanceGroup &set_group : set_groups) {
|
|
|
|
const GeometrySet &set = set_group.geometry_set;
|
2021-02-18 10:13:56 +01:00
|
|
|
const int tot_transforms = set_group.transforms.size();
|
2021-02-16 12:30:42 +01:00
|
|
|
if (set.has_mesh()) {
|
|
|
|
const Mesh &mesh = *set.get_mesh_for_read();
|
2021-02-18 10:13:56 +01:00
|
|
|
totverts += mesh.totvert * tot_transforms;
|
|
|
|
totloops += mesh.totloop * tot_transforms;
|
|
|
|
totedges += mesh.totedge * tot_transforms;
|
|
|
|
totpolys += mesh.totpoly * tot_transforms;
|
2021-02-16 12:30:42 +01:00
|
|
|
cd_dirty_vert |= mesh.runtime.cd_dirty_vert;
|
|
|
|
cd_dirty_poly |= mesh.runtime.cd_dirty_poly;
|
|
|
|
cd_dirty_edge |= mesh.runtime.cd_dirty_edge;
|
|
|
|
cd_dirty_loop |= mesh.runtime.cd_dirty_loop;
|
2021-05-19 11:02:25 +02:00
|
|
|
for (const int slot_index : IndexRange(mesh.totcol)) {
|
|
|
|
Material *material = mesh.mat[slot_index];
|
|
|
|
materials.add(material);
|
|
|
|
}
|
2021-02-16 12:30:42 +01:00
|
|
|
}
|
2021-02-18 10:13:56 +01:00
|
|
|
if (convert_points_to_vertices && set.has_pointcloud()) {
|
|
|
|
const PointCloud &pointcloud = *set.get_pointcloud_for_read();
|
|
|
|
totverts += pointcloud.totpoint * tot_transforms;
|
|
|
|
}
|
2021-02-16 12:30:42 +01:00
|
|
|
}
|
|
|
|
|
2021-03-18 16:32:49 -04:00
|
|
|
/* Don't create an empty mesh. */
|
|
|
|
if ((totverts + totloops + totedges + totpolys) == 0) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2021-02-16 12:30:42 +01:00
|
|
|
Mesh *new_mesh = BKE_mesh_new_nomain(totverts, totedges, 0, totloops, totpolys);
|
|
|
|
/* Copy settings from the first input geometry set with a mesh. */
|
|
|
|
for (const GeometryInstanceGroup &set_group : set_groups) {
|
|
|
|
const GeometrySet &set = set_group.geometry_set;
|
|
|
|
if (set.has_mesh()) {
|
|
|
|
const Mesh &mesh = *set.get_mesh_for_read();
|
2021-06-17 14:56:39 +10:00
|
|
|
BKE_mesh_copy_parameters_for_eval(new_mesh, &mesh);
|
2021-02-16 12:30:42 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2021-05-19 11:02:25 +02:00
|
|
|
for (const int i : IndexRange(materials.size())) {
|
|
|
|
Material *material = materials[i];
|
|
|
|
BKE_id_material_eval_assign(&new_mesh->id, i + 1, material);
|
|
|
|
}
|
2021-02-16 12:30:42 +01:00
|
|
|
new_mesh->runtime.cd_dirty_vert = cd_dirty_vert;
|
|
|
|
new_mesh->runtime.cd_dirty_poly = cd_dirty_poly;
|
|
|
|
new_mesh->runtime.cd_dirty_edge = cd_dirty_edge;
|
|
|
|
new_mesh->runtime.cd_dirty_loop = cd_dirty_loop;
|
|
|
|
|
|
|
|
int vert_offset = 0;
|
|
|
|
int loop_offset = 0;
|
|
|
|
int edge_offset = 0;
|
|
|
|
int poly_offset = 0;
|
|
|
|
for (const GeometryInstanceGroup &set_group : set_groups) {
|
|
|
|
const GeometrySet &set = set_group.geometry_set;
|
|
|
|
if (set.has_mesh()) {
|
|
|
|
const Mesh &mesh = *set.get_mesh_for_read();
|
2021-05-19 11:02:25 +02:00
|
|
|
|
|
|
|
Array<int> material_index_map(mesh.totcol);
|
|
|
|
for (const int i : IndexRange(mesh.totcol)) {
|
|
|
|
Material *material = mesh.mat[i];
|
|
|
|
const int new_material_index = materials.index_of(material);
|
|
|
|
material_index_map[i] = new_material_index;
|
|
|
|
}
|
|
|
|
|
2021-02-16 12:30:42 +01:00
|
|
|
for (const float4x4 &transform : set_group.transforms) {
|
|
|
|
for (const int i : IndexRange(mesh.totvert)) {
|
|
|
|
const MVert &old_vert = mesh.mvert[i];
|
|
|
|
MVert &new_vert = new_mesh->mvert[vert_offset + i];
|
|
|
|
|
|
|
|
new_vert = old_vert;
|
|
|
|
|
|
|
|
const float3 new_position = transform * float3(old_vert.co);
|
|
|
|
copy_v3_v3(new_vert.co, new_position);
|
|
|
|
}
|
|
|
|
for (const int i : IndexRange(mesh.totedge)) {
|
|
|
|
const MEdge &old_edge = mesh.medge[i];
|
|
|
|
MEdge &new_edge = new_mesh->medge[edge_offset + i];
|
|
|
|
new_edge = old_edge;
|
|
|
|
new_edge.v1 += vert_offset;
|
|
|
|
new_edge.v2 += vert_offset;
|
|
|
|
}
|
|
|
|
for (const int i : IndexRange(mesh.totloop)) {
|
|
|
|
const MLoop &old_loop = mesh.mloop[i];
|
|
|
|
MLoop &new_loop = new_mesh->mloop[loop_offset + i];
|
|
|
|
new_loop = old_loop;
|
|
|
|
new_loop.v += vert_offset;
|
|
|
|
new_loop.e += edge_offset;
|
|
|
|
}
|
|
|
|
for (const int i : IndexRange(mesh.totpoly)) {
|
|
|
|
const MPoly &old_poly = mesh.mpoly[i];
|
|
|
|
MPoly &new_poly = new_mesh->mpoly[poly_offset + i];
|
|
|
|
new_poly = old_poly;
|
|
|
|
new_poly.loopstart += loop_offset;
|
2021-05-19 11:02:25 +02:00
|
|
|
if (old_poly.mat_nr >= 0 && old_poly.mat_nr < mesh.totcol) {
|
|
|
|
new_poly.mat_nr = material_index_map[new_poly.mat_nr];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* The material index was invalid before. */
|
|
|
|
new_poly.mat_nr = 0;
|
|
|
|
}
|
2021-02-16 12:30:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
vert_offset += mesh.totvert;
|
|
|
|
loop_offset += mesh.totloop;
|
|
|
|
edge_offset += mesh.totedge;
|
|
|
|
poly_offset += mesh.totpoly;
|
|
|
|
}
|
|
|
|
}
|
2021-06-14 11:07:31 +02:00
|
|
|
|
|
|
|
const float3 point_normal{0.0f, 0.0f, 1.0f};
|
|
|
|
short point_normal_short[3];
|
|
|
|
normal_float_to_short_v3(point_normal_short, point_normal);
|
|
|
|
|
2021-02-18 10:13:56 +01:00
|
|
|
if (convert_points_to_vertices && set.has_pointcloud()) {
|
|
|
|
const PointCloud &pointcloud = *set.get_pointcloud_for_read();
|
|
|
|
for (const float4x4 &transform : set_group.transforms) {
|
|
|
|
for (const int i : IndexRange(pointcloud.totpoint)) {
|
|
|
|
MVert &new_vert = new_mesh->mvert[vert_offset + i];
|
|
|
|
const float3 old_position = pointcloud.co[i];
|
|
|
|
const float3 new_position = transform * old_position;
|
|
|
|
copy_v3_v3(new_vert.co, new_position);
|
2021-06-14 11:07:31 +02:00
|
|
|
memcpy(&new_vert.no, point_normal_short, sizeof(point_normal_short));
|
2021-02-18 10:13:56 +01:00
|
|
|
}
|
|
|
|
vert_offset += pointcloud.totpoint;
|
|
|
|
}
|
|
|
|
}
|
2021-02-16 12:30:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return new_mesh;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void join_attributes(Span<GeometryInstanceGroup> set_groups,
|
2021-02-18 10:13:56 +01:00
|
|
|
Span<GeometryComponentType> component_types,
|
2021-02-18 12:32:34 +01:00
|
|
|
const Map<std::string, AttributeKind> &attribute_info,
|
2021-02-16 12:30:42 +01:00
|
|
|
GeometryComponent &result)
|
|
|
|
{
|
2021-02-18 12:32:34 +01:00
|
|
|
for (Map<std::string, AttributeKind>::Item entry : attribute_info.items()) {
|
2021-02-16 12:30:42 +01:00
|
|
|
StringRef name = entry.key;
|
|
|
|
const AttributeDomain domain_output = entry.value.domain;
|
|
|
|
const CustomDataType data_type_output = entry.value.data_type;
|
|
|
|
const CPPType *cpp_type = bke::custom_data_type_to_cpp_type(data_type_output);
|
|
|
|
BLI_assert(cpp_type != nullptr);
|
|
|
|
|
2021-04-22 09:20:03 -05:00
|
|
|
result.attribute_try_create(
|
|
|
|
entry.key, domain_output, data_type_output, AttributeInitDefault());
|
Geometry Nodes: use virtual arrays in internal attribute api
A virtual array is a data structure that is similar to a normal array
in that its elements can be accessed by an index. However, a virtual
array does not have to be a contiguous array internally. Instead, its
elements can be layed out arbitrarily while element access happens
through a virtual function call. However, the virtual array data
structures are designed so that the virtual function call can be avoided
in cases where it could become a bottleneck.
Most commonly, a virtual array is backed by an actual array/span or
is a single value internally, that is the same for every index.
Besides those, there are many more specialized virtual arrays like the
ones that provides vertex positions based on the `MVert` struct or
vertex group weights.
Not all attributes used by geometry nodes are stored in simple contiguous
arrays. To provide uniform access to all kinds of attributes, the attribute
API has to provide virtual array functionality that hides the implementation
details of attributes.
Before this refactor, the attribute API provided its own virtual array
implementation as part of the `ReadAttribute` and `WriteAttribute` types.
That resulted in unnecessary code duplication with the virtual array system.
Even worse, it bound many algorithms used by geometry nodes to the specifics
of the attribute API, even though they could also use different data sources
(such as data from sockets, default values, later results of expressions, ...).
This refactor removes the `ReadAttribute` and `WriteAttribute` types and
replaces them with `GVArray` and `GVMutableArray` respectively. The `GV`
stands for "generic virtual". The "generic" means that the data type contained
in those virtual arrays is only known at run-time. There are the corresponding
statically typed types `VArray<T>` and `VMutableArray<T>` as well.
No regressions are expected from this refactor. It does come with one
improvement for users. The attribute API can convert the data type
on write now. This is especially useful when writing to builtin attributes
like `material_index` with e.g. the Attribute Math node (which usually
just writes to float attributes, while `material_index` is an integer attribute).
Differential Revision: https://developer.blender.org/D10994
2021-04-17 16:41:03 +02:00
|
|
|
WriteAttributeLookup write_attribute = result.attribute_try_get_for_write(name);
|
|
|
|
if (!write_attribute || &write_attribute.varray->type() != cpp_type ||
|
|
|
|
write_attribute.domain != domain_output) {
|
2021-02-16 12:30:42 +01:00
|
|
|
continue;
|
|
|
|
}
|
Geometry Nodes: use virtual arrays in internal attribute api
A virtual array is a data structure that is similar to a normal array
in that its elements can be accessed by an index. However, a virtual
array does not have to be a contiguous array internally. Instead, its
elements can be layed out arbitrarily while element access happens
through a virtual function call. However, the virtual array data
structures are designed so that the virtual function call can be avoided
in cases where it could become a bottleneck.
Most commonly, a virtual array is backed by an actual array/span or
is a single value internally, that is the same for every index.
Besides those, there are many more specialized virtual arrays like the
ones that provides vertex positions based on the `MVert` struct or
vertex group weights.
Not all attributes used by geometry nodes are stored in simple contiguous
arrays. To provide uniform access to all kinds of attributes, the attribute
API has to provide virtual array functionality that hides the implementation
details of attributes.
Before this refactor, the attribute API provided its own virtual array
implementation as part of the `ReadAttribute` and `WriteAttribute` types.
That resulted in unnecessary code duplication with the virtual array system.
Even worse, it bound many algorithms used by geometry nodes to the specifics
of the attribute API, even though they could also use different data sources
(such as data from sockets, default values, later results of expressions, ...).
This refactor removes the `ReadAttribute` and `WriteAttribute` types and
replaces them with `GVArray` and `GVMutableArray` respectively. The `GV`
stands for "generic virtual". The "generic" means that the data type contained
in those virtual arrays is only known at run-time. There are the corresponding
statically typed types `VArray<T>` and `VMutableArray<T>` as well.
No regressions are expected from this refactor. It does come with one
improvement for users. The attribute API can convert the data type
on write now. This is especially useful when writing to builtin attributes
like `material_index` with e.g. the Attribute Math node (which usually
just writes to float attributes, while `material_index` is an integer attribute).
Differential Revision: https://developer.blender.org/D10994
2021-04-17 16:41:03 +02:00
|
|
|
|
|
|
|
fn::GVMutableArray_GSpan dst_span{*write_attribute.varray};
|
2021-02-16 12:30:42 +01:00
|
|
|
|
|
|
|
int offset = 0;
|
|
|
|
for (const GeometryInstanceGroup &set_group : set_groups) {
|
|
|
|
const GeometrySet &set = set_group.geometry_set;
|
2021-02-18 10:13:56 +01:00
|
|
|
for (const GeometryComponentType component_type : component_types) {
|
|
|
|
if (set.has(component_type)) {
|
|
|
|
const GeometryComponent &component = *set.get_component_for_read(component_type);
|
|
|
|
const int domain_size = component.attribute_domain_size(domain_output);
|
|
|
|
if (domain_size == 0) {
|
|
|
|
continue; /* Domain size is 0, so no need to increment the offset. */
|
|
|
|
}
|
Geometry Nodes: use virtual arrays in internal attribute api
A virtual array is a data structure that is similar to a normal array
in that its elements can be accessed by an index. However, a virtual
array does not have to be a contiguous array internally. Instead, its
elements can be layed out arbitrarily while element access happens
through a virtual function call. However, the virtual array data
structures are designed so that the virtual function call can be avoided
in cases where it could become a bottleneck.
Most commonly, a virtual array is backed by an actual array/span or
is a single value internally, that is the same for every index.
Besides those, there are many more specialized virtual arrays like the
ones that provides vertex positions based on the `MVert` struct or
vertex group weights.
Not all attributes used by geometry nodes are stored in simple contiguous
arrays. To provide uniform access to all kinds of attributes, the attribute
API has to provide virtual array functionality that hides the implementation
details of attributes.
Before this refactor, the attribute API provided its own virtual array
implementation as part of the `ReadAttribute` and `WriteAttribute` types.
That resulted in unnecessary code duplication with the virtual array system.
Even worse, it bound many algorithms used by geometry nodes to the specifics
of the attribute API, even though they could also use different data sources
(such as data from sockets, default values, later results of expressions, ...).
This refactor removes the `ReadAttribute` and `WriteAttribute` types and
replaces them with `GVArray` and `GVMutableArray` respectively. The `GV`
stands for "generic virtual". The "generic" means that the data type contained
in those virtual arrays is only known at run-time. There are the corresponding
statically typed types `VArray<T>` and `VMutableArray<T>` as well.
No regressions are expected from this refactor. It does come with one
improvement for users. The attribute API can convert the data type
on write now. This is especially useful when writing to builtin attributes
like `material_index` with e.g. the Attribute Math node (which usually
just writes to float attributes, while `material_index` is an integer attribute).
Differential Revision: https://developer.blender.org/D10994
2021-04-17 16:41:03 +02:00
|
|
|
GVArrayPtr source_attribute = component.attribute_try_get_for_read(
|
2021-02-18 10:13:56 +01:00
|
|
|
name, domain_output, data_type_output);
|
|
|
|
|
|
|
|
if (source_attribute) {
|
Geometry Nodes: use virtual arrays in internal attribute api
A virtual array is a data structure that is similar to a normal array
in that its elements can be accessed by an index. However, a virtual
array does not have to be a contiguous array internally. Instead, its
elements can be layed out arbitrarily while element access happens
through a virtual function call. However, the virtual array data
structures are designed so that the virtual function call can be avoided
in cases where it could become a bottleneck.
Most commonly, a virtual array is backed by an actual array/span or
is a single value internally, that is the same for every index.
Besides those, there are many more specialized virtual arrays like the
ones that provides vertex positions based on the `MVert` struct or
vertex group weights.
Not all attributes used by geometry nodes are stored in simple contiguous
arrays. To provide uniform access to all kinds of attributes, the attribute
API has to provide virtual array functionality that hides the implementation
details of attributes.
Before this refactor, the attribute API provided its own virtual array
implementation as part of the `ReadAttribute` and `WriteAttribute` types.
That resulted in unnecessary code duplication with the virtual array system.
Even worse, it bound many algorithms used by geometry nodes to the specifics
of the attribute API, even though they could also use different data sources
(such as data from sockets, default values, later results of expressions, ...).
This refactor removes the `ReadAttribute` and `WriteAttribute` types and
replaces them with `GVArray` and `GVMutableArray` respectively. The `GV`
stands for "generic virtual". The "generic" means that the data type contained
in those virtual arrays is only known at run-time. There are the corresponding
statically typed types `VArray<T>` and `VMutableArray<T>` as well.
No regressions are expected from this refactor. It does come with one
improvement for users. The attribute API can convert the data type
on write now. This is especially useful when writing to builtin attributes
like `material_index` with e.g. the Attribute Math node (which usually
just writes to float attributes, while `material_index` is an integer attribute).
Differential Revision: https://developer.blender.org/D10994
2021-04-17 16:41:03 +02:00
|
|
|
fn::GVArray_GSpan src_span{*source_attribute};
|
2021-02-18 10:13:56 +01:00
|
|
|
const void *src_buffer = src_span.data();
|
|
|
|
for (const int UNUSED(i) : set_group.transforms.index_range()) {
|
|
|
|
void *dst_buffer = dst_span[offset];
|
|
|
|
cpp_type->copy_to_initialized_n(src_buffer, dst_buffer, domain_size);
|
|
|
|
offset += domain_size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
offset += domain_size * set_group.transforms.size();
|
2021-02-16 12:30:42 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Geometry Nodes: use virtual arrays in internal attribute api
A virtual array is a data structure that is similar to a normal array
in that its elements can be accessed by an index. However, a virtual
array does not have to be a contiguous array internally. Instead, its
elements can be layed out arbitrarily while element access happens
through a virtual function call. However, the virtual array data
structures are designed so that the virtual function call can be avoided
in cases where it could become a bottleneck.
Most commonly, a virtual array is backed by an actual array/span or
is a single value internally, that is the same for every index.
Besides those, there are many more specialized virtual arrays like the
ones that provides vertex positions based on the `MVert` struct or
vertex group weights.
Not all attributes used by geometry nodes are stored in simple contiguous
arrays. To provide uniform access to all kinds of attributes, the attribute
API has to provide virtual array functionality that hides the implementation
details of attributes.
Before this refactor, the attribute API provided its own virtual array
implementation as part of the `ReadAttribute` and `WriteAttribute` types.
That resulted in unnecessary code duplication with the virtual array system.
Even worse, it bound many algorithms used by geometry nodes to the specifics
of the attribute API, even though they could also use different data sources
(such as data from sockets, default values, later results of expressions, ...).
This refactor removes the `ReadAttribute` and `WriteAttribute` types and
replaces them with `GVArray` and `GVMutableArray` respectively. The `GV`
stands for "generic virtual". The "generic" means that the data type contained
in those virtual arrays is only known at run-time. There are the corresponding
statically typed types `VArray<T>` and `VMutableArray<T>` as well.
No regressions are expected from this refactor. It does come with one
improvement for users. The attribute API can convert the data type
on write now. This is especially useful when writing to builtin attributes
like `material_index` with e.g. the Attribute Math node (which usually
just writes to float attributes, while `material_index` is an integer attribute).
Differential Revision: https://developer.blender.org/D10994
2021-04-17 16:41:03 +02:00
|
|
|
dst_span.save();
|
2021-02-16 12:30:42 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-31 11:12:39 +02:00
|
|
|
static CurveEval *join_curve_splines(Span<GeometryInstanceGroup> set_groups)
|
Geometry Nodes: Initial basic curve data support
This patch adds initial curve support to geometry nodes. Currently
there is only one node available, the "Curve to Mesh" node, T87428.
However, the aim of the changes here is larger than just supporting
curve data in nodes-- it also uses the opportunity to add better spline
data structures, intended to replace the existing curve evaluation code.
The curve code in Blender is quite old, and it's generally regarded as
some of the messiest, hardest-to-understand code as well. The classes
in `BKE_spline.hh` aim to be faster, more extensible, and much more
easily understandable. Further explanation can be found in comments in
that file.
Initial builtin spline attributes are supported-- reading and writing
from the `cyclic` and `resolution` attributes works with any of the
attribute nodes. Also, only Z-up normal calculation is implemented
at the moment, and tilts do not apply yet.
**Limitations**
- For now, you must bring curves into the node tree with an "Object
Info" node. Changes to the curve modifier stack will come later.
- Converting to a mesh is necessary to visualize the curve data.
Further progress can be tracked in: T87245
Higher level design document: https://wiki.blender.org/wiki/Modules/Physics_Nodes/Projects/EverythingNodes/CurveNodes
Differential Revision: https://developer.blender.org/D11091
2021-05-03 12:29:17 -05:00
|
|
|
{
|
2021-05-31 11:12:39 +02:00
|
|
|
Vector<SplinePtr> new_splines;
|
Geometry Nodes: Initial basic curve data support
This patch adds initial curve support to geometry nodes. Currently
there is only one node available, the "Curve to Mesh" node, T87428.
However, the aim of the changes here is larger than just supporting
curve data in nodes-- it also uses the opportunity to add better spline
data structures, intended to replace the existing curve evaluation code.
The curve code in Blender is quite old, and it's generally regarded as
some of the messiest, hardest-to-understand code as well. The classes
in `BKE_spline.hh` aim to be faster, more extensible, and much more
easily understandable. Further explanation can be found in comments in
that file.
Initial builtin spline attributes are supported-- reading and writing
from the `cyclic` and `resolution` attributes works with any of the
attribute nodes. Also, only Z-up normal calculation is implemented
at the moment, and tilts do not apply yet.
**Limitations**
- For now, you must bring curves into the node tree with an "Object
Info" node. Changes to the curve modifier stack will come later.
- Converting to a mesh is necessary to visualize the curve data.
Further progress can be tracked in: T87245
Higher level design document: https://wiki.blender.org/wiki/Modules/Physics_Nodes/Projects/EverythingNodes/CurveNodes
Differential Revision: https://developer.blender.org/D11091
2021-05-03 12:29:17 -05:00
|
|
|
for (const GeometryInstanceGroup &set_group : set_groups) {
|
|
|
|
const GeometrySet &set = set_group.geometry_set;
|
|
|
|
if (!set.has_curve()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
const CurveEval &source_curve = *set.get_curve_for_read();
|
2021-05-12 11:46:13 -05:00
|
|
|
for (const SplinePtr &source_spline : source_curve.splines()) {
|
Geometry Nodes: Initial basic curve data support
This patch adds initial curve support to geometry nodes. Currently
there is only one node available, the "Curve to Mesh" node, T87428.
However, the aim of the changes here is larger than just supporting
curve data in nodes-- it also uses the opportunity to add better spline
data structures, intended to replace the existing curve evaluation code.
The curve code in Blender is quite old, and it's generally regarded as
some of the messiest, hardest-to-understand code as well. The classes
in `BKE_spline.hh` aim to be faster, more extensible, and much more
easily understandable. Further explanation can be found in comments in
that file.
Initial builtin spline attributes are supported-- reading and writing
from the `cyclic` and `resolution` attributes works with any of the
attribute nodes. Also, only Z-up normal calculation is implemented
at the moment, and tilts do not apply yet.
**Limitations**
- For now, you must bring curves into the node tree with an "Object
Info" node. Changes to the curve modifier stack will come later.
- Converting to a mesh is necessary to visualize the curve data.
Further progress can be tracked in: T87245
Higher level design document: https://wiki.blender.org/wiki/Modules/Physics_Nodes/Projects/EverythingNodes/CurveNodes
Differential Revision: https://developer.blender.org/D11091
2021-05-03 12:29:17 -05:00
|
|
|
for (const float4x4 &transform : set_group.transforms) {
|
|
|
|
SplinePtr new_spline = source_spline->copy();
|
|
|
|
new_spline->transform(transform);
|
2021-05-31 11:12:39 +02:00
|
|
|
new_splines.append(std::move(new_spline));
|
Geometry Nodes: Initial basic curve data support
This patch adds initial curve support to geometry nodes. Currently
there is only one node available, the "Curve to Mesh" node, T87428.
However, the aim of the changes here is larger than just supporting
curve data in nodes-- it also uses the opportunity to add better spline
data structures, intended to replace the existing curve evaluation code.
The curve code in Blender is quite old, and it's generally regarded as
some of the messiest, hardest-to-understand code as well. The classes
in `BKE_spline.hh` aim to be faster, more extensible, and much more
easily understandable. Further explanation can be found in comments in
that file.
Initial builtin spline attributes are supported-- reading and writing
from the `cyclic` and `resolution` attributes works with any of the
attribute nodes. Also, only Z-up normal calculation is implemented
at the moment, and tilts do not apply yet.
**Limitations**
- For now, you must bring curves into the node tree with an "Object
Info" node. Changes to the curve modifier stack will come later.
- Converting to a mesh is necessary to visualize the curve data.
Further progress can be tracked in: T87245
Higher level design document: https://wiki.blender.org/wiki/Modules/Physics_Nodes/Projects/EverythingNodes/CurveNodes
Differential Revision: https://developer.blender.org/D11091
2021-05-03 12:29:17 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-05-31 11:12:39 +02:00
|
|
|
if (new_splines.is_empty()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
CurveEval *new_curve = new CurveEval();
|
|
|
|
for (SplinePtr &new_spline : new_splines) {
|
|
|
|
new_curve->add_spline(std::move(new_spline));
|
|
|
|
}
|
Geometry Nodes: Initial basic curve data support
This patch adds initial curve support to geometry nodes. Currently
there is only one node available, the "Curve to Mesh" node, T87428.
However, the aim of the changes here is larger than just supporting
curve data in nodes-- it also uses the opportunity to add better spline
data structures, intended to replace the existing curve evaluation code.
The curve code in Blender is quite old, and it's generally regarded as
some of the messiest, hardest-to-understand code as well. The classes
in `BKE_spline.hh` aim to be faster, more extensible, and much more
easily understandable. Further explanation can be found in comments in
that file.
Initial builtin spline attributes are supported-- reading and writing
from the `cyclic` and `resolution` attributes works with any of the
attribute nodes. Also, only Z-up normal calculation is implemented
at the moment, and tilts do not apply yet.
**Limitations**
- For now, you must bring curves into the node tree with an "Object
Info" node. Changes to the curve modifier stack will come later.
- Converting to a mesh is necessary to visualize the curve data.
Further progress can be tracked in: T87245
Higher level design document: https://wiki.blender.org/wiki/Modules/Physics_Nodes/Projects/EverythingNodes/CurveNodes
Differential Revision: https://developer.blender.org/D11091
2021-05-03 12:29:17 -05:00
|
|
|
|
2021-05-19 13:22:09 -04:00
|
|
|
for (SplinePtr &spline : new_curve->splines()) {
|
|
|
|
/* Spline instances should have no custom attributes, since they always come
|
2021-05-20 17:55:35 +10:00
|
|
|
* from original objects which currently do not support custom attributes.
|
2021-05-19 13:22:09 -04:00
|
|
|
*
|
2021-05-20 17:55:35 +10:00
|
|
|
* This is only true as long as a #GeometrySet cannot be instanced directly. */
|
2021-05-19 13:22:09 -04:00
|
|
|
BLI_assert(spline->attributes.data.totlayer == 0);
|
|
|
|
UNUSED_VARS_NDEBUG(spline);
|
|
|
|
}
|
|
|
|
|
|
|
|
new_curve->attributes.reallocate(new_curve->splines().size());
|
2021-05-31 11:12:39 +02:00
|
|
|
return new_curve;
|
Geometry Nodes: Initial basic curve data support
This patch adds initial curve support to geometry nodes. Currently
there is only one node available, the "Curve to Mesh" node, T87428.
However, the aim of the changes here is larger than just supporting
curve data in nodes-- it also uses the opportunity to add better spline
data structures, intended to replace the existing curve evaluation code.
The curve code in Blender is quite old, and it's generally regarded as
some of the messiest, hardest-to-understand code as well. The classes
in `BKE_spline.hh` aim to be faster, more extensible, and much more
easily understandable. Further explanation can be found in comments in
that file.
Initial builtin spline attributes are supported-- reading and writing
from the `cyclic` and `resolution` attributes works with any of the
attribute nodes. Also, only Z-up normal calculation is implemented
at the moment, and tilts do not apply yet.
**Limitations**
- For now, you must bring curves into the node tree with an "Object
Info" node. Changes to the curve modifier stack will come later.
- Converting to a mesh is necessary to visualize the curve data.
Further progress can be tracked in: T87245
Higher level design document: https://wiki.blender.org/wiki/Modules/Physics_Nodes/Projects/EverythingNodes/CurveNodes
Differential Revision: https://developer.blender.org/D11091
2021-05-03 12:29:17 -05:00
|
|
|
}
|
|
|
|
|
2021-02-18 10:13:56 +01:00
|
|
|
static void join_instance_groups_mesh(Span<GeometryInstanceGroup> set_groups,
|
|
|
|
bool convert_points_to_vertices,
|
|
|
|
GeometrySet &result)
|
2021-02-16 12:30:42 +01:00
|
|
|
{
|
2021-02-18 10:13:56 +01:00
|
|
|
Mesh *new_mesh = join_mesh_topology_and_builtin_attributes(set_groups,
|
|
|
|
convert_points_to_vertices);
|
2021-03-18 16:32:49 -04:00
|
|
|
if (new_mesh == nullptr) {
|
|
|
|
return;
|
|
|
|
}
|
2021-02-16 12:30:42 +01:00
|
|
|
|
|
|
|
MeshComponent &dst_component = result.get_component_for_write<MeshComponent>();
|
|
|
|
dst_component.replace(new_mesh);
|
|
|
|
|
2021-02-18 10:13:56 +01:00
|
|
|
Vector<GeometryComponentType> component_types;
|
2021-03-10 11:53:17 +01:00
|
|
|
component_types.append(GEO_COMPONENT_TYPE_MESH);
|
2021-02-18 10:13:56 +01:00
|
|
|
if (convert_points_to_vertices) {
|
2021-03-10 11:53:17 +01:00
|
|
|
component_types.append(GEO_COMPONENT_TYPE_POINT_CLOUD);
|
2021-02-18 10:13:56 +01:00
|
|
|
}
|
|
|
|
|
2021-02-17 08:30:15 -06:00
|
|
|
/* Don't copy attributes that are stored directly in the mesh data structs. */
|
2021-02-18 12:32:34 +01:00
|
|
|
Map<std::string, AttributeKind> attributes;
|
2021-04-07 15:49:02 -05:00
|
|
|
geometry_set_gather_instances_attribute_info(
|
|
|
|
set_groups,
|
|
|
|
component_types,
|
|
|
|
{"position", "material_index", "normal", "shade_smooth", "crease"},
|
|
|
|
attributes);
|
2021-02-18 10:13:56 +01:00
|
|
|
join_attributes(
|
|
|
|
set_groups, component_types, attributes, static_cast<GeometryComponent &>(dst_component));
|
2021-02-16 12:30:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void join_instance_groups_pointcloud(Span<GeometryInstanceGroup> set_groups,
|
|
|
|
GeometrySet &result)
|
|
|
|
{
|
|
|
|
int totpoint = 0;
|
|
|
|
for (const GeometryInstanceGroup &set_group : set_groups) {
|
|
|
|
const GeometrySet &set = set_group.geometry_set;
|
|
|
|
if (set.has<PointCloudComponent>()) {
|
|
|
|
const PointCloudComponent &component = *set.get_component_for_read<PointCloudComponent>();
|
|
|
|
totpoint += component.attribute_domain_size(ATTR_DOMAIN_POINT);
|
|
|
|
}
|
|
|
|
}
|
2021-03-18 16:32:49 -04:00
|
|
|
if (totpoint == 0) {
|
|
|
|
return;
|
|
|
|
}
|
2021-02-16 12:30:42 +01:00
|
|
|
|
|
|
|
PointCloudComponent &dst_component = result.get_component_for_write<PointCloudComponent>();
|
|
|
|
PointCloud *pointcloud = BKE_pointcloud_new_nomain(totpoint);
|
|
|
|
dst_component.replace(pointcloud);
|
2021-02-18 12:32:34 +01:00
|
|
|
Map<std::string, AttributeKind> attributes;
|
2021-04-07 15:49:02 -05:00
|
|
|
geometry_set_gather_instances_attribute_info(
|
|
|
|
set_groups, {GEO_COMPONENT_TYPE_POINT_CLOUD}, {}, attributes);
|
2021-02-16 12:30:42 +01:00
|
|
|
join_attributes(set_groups,
|
2021-03-10 11:53:17 +01:00
|
|
|
{GEO_COMPONENT_TYPE_POINT_CLOUD},
|
2021-02-16 12:30:42 +01:00
|
|
|
attributes,
|
|
|
|
static_cast<GeometryComponent &>(dst_component));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void join_instance_groups_volume(Span<GeometryInstanceGroup> set_groups,
|
|
|
|
GeometrySet &result)
|
|
|
|
{
|
2021-06-15 22:31:57 -05:00
|
|
|
/* Not yet supported; for now only return the first volume. Joining volume grids with the same
|
|
|
|
* name requires resampling of at least one of the grids. The cell size of the resulting volume
|
|
|
|
* has to be determined somehow. */
|
|
|
|
for (const GeometryInstanceGroup &set_group : set_groups) {
|
|
|
|
const GeometrySet &set = set_group.geometry_set;
|
|
|
|
if (set.has<VolumeComponent>()) {
|
|
|
|
result.add(*set.get_component_for_read<VolumeComponent>());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2021-02-16 12:30:42 +01:00
|
|
|
}
|
|
|
|
|
Geometry Nodes: Initial basic curve data support
This patch adds initial curve support to geometry nodes. Currently
there is only one node available, the "Curve to Mesh" node, T87428.
However, the aim of the changes here is larger than just supporting
curve data in nodes-- it also uses the opportunity to add better spline
data structures, intended to replace the existing curve evaluation code.
The curve code in Blender is quite old, and it's generally regarded as
some of the messiest, hardest-to-understand code as well. The classes
in `BKE_spline.hh` aim to be faster, more extensible, and much more
easily understandable. Further explanation can be found in comments in
that file.
Initial builtin spline attributes are supported-- reading and writing
from the `cyclic` and `resolution` attributes works with any of the
attribute nodes. Also, only Z-up normal calculation is implemented
at the moment, and tilts do not apply yet.
**Limitations**
- For now, you must bring curves into the node tree with an "Object
Info" node. Changes to the curve modifier stack will come later.
- Converting to a mesh is necessary to visualize the curve data.
Further progress can be tracked in: T87245
Higher level design document: https://wiki.blender.org/wiki/Modules/Physics_Nodes/Projects/EverythingNodes/CurveNodes
Differential Revision: https://developer.blender.org/D11091
2021-05-03 12:29:17 -05:00
|
|
|
static void join_instance_groups_curve(Span<GeometryInstanceGroup> set_groups, GeometrySet &result)
|
|
|
|
{
|
2021-05-31 11:12:39 +02:00
|
|
|
CurveEval *curve = join_curve_splines(set_groups);
|
|
|
|
if (curve == nullptr) {
|
|
|
|
return;
|
|
|
|
}
|
Geometry Nodes: Initial basic curve data support
This patch adds initial curve support to geometry nodes. Currently
there is only one node available, the "Curve to Mesh" node, T87428.
However, the aim of the changes here is larger than just supporting
curve data in nodes-- it also uses the opportunity to add better spline
data structures, intended to replace the existing curve evaluation code.
The curve code in Blender is quite old, and it's generally regarded as
some of the messiest, hardest-to-understand code as well. The classes
in `BKE_spline.hh` aim to be faster, more extensible, and much more
easily understandable. Further explanation can be found in comments in
that file.
Initial builtin spline attributes are supported-- reading and writing
from the `cyclic` and `resolution` attributes works with any of the
attribute nodes. Also, only Z-up normal calculation is implemented
at the moment, and tilts do not apply yet.
**Limitations**
- For now, you must bring curves into the node tree with an "Object
Info" node. Changes to the curve modifier stack will come later.
- Converting to a mesh is necessary to visualize the curve data.
Further progress can be tracked in: T87245
Higher level design document: https://wiki.blender.org/wiki/Modules/Physics_Nodes/Projects/EverythingNodes/CurveNodes
Differential Revision: https://developer.blender.org/D11091
2021-05-03 12:29:17 -05:00
|
|
|
CurveComponent &dst_component = result.get_component_for_write<CurveComponent>();
|
2021-05-31 11:12:39 +02:00
|
|
|
dst_component.replace(curve);
|
Geometry Nodes: Initial basic curve data support
This patch adds initial curve support to geometry nodes. Currently
there is only one node available, the "Curve to Mesh" node, T87428.
However, the aim of the changes here is larger than just supporting
curve data in nodes-- it also uses the opportunity to add better spline
data structures, intended to replace the existing curve evaluation code.
The curve code in Blender is quite old, and it's generally regarded as
some of the messiest, hardest-to-understand code as well. The classes
in `BKE_spline.hh` aim to be faster, more extensible, and much more
easily understandable. Further explanation can be found in comments in
that file.
Initial builtin spline attributes are supported-- reading and writing
from the `cyclic` and `resolution` attributes works with any of the
attribute nodes. Also, only Z-up normal calculation is implemented
at the moment, and tilts do not apply yet.
**Limitations**
- For now, you must bring curves into the node tree with an "Object
Info" node. Changes to the curve modifier stack will come later.
- Converting to a mesh is necessary to visualize the curve data.
Further progress can be tracked in: T87245
Higher level design document: https://wiki.blender.org/wiki/Modules/Physics_Nodes/Projects/EverythingNodes/CurveNodes
Differential Revision: https://developer.blender.org/D11091
2021-05-03 12:29:17 -05:00
|
|
|
}
|
|
|
|
|
2021-02-18 10:13:56 +01:00
|
|
|
GeometrySet geometry_set_realize_mesh_for_modifier(const GeometrySet &geometry_set)
|
|
|
|
{
|
|
|
|
if (!geometry_set.has_instances() && !geometry_set.has_pointcloud()) {
|
|
|
|
return geometry_set;
|
|
|
|
}
|
|
|
|
|
|
|
|
GeometrySet new_geometry_set = geometry_set;
|
2021-03-25 14:54:27 -04:00
|
|
|
Vector<GeometryInstanceGroup> set_groups;
|
|
|
|
geometry_set_gather_instances(geometry_set, set_groups);
|
2021-02-18 10:13:56 +01:00
|
|
|
join_instance_groups_mesh(set_groups, true, new_geometry_set);
|
|
|
|
/* Remove all instances, even though some might contain other non-mesh data. We can't really
|
|
|
|
* keep only non-mesh instances in general. */
|
|
|
|
new_geometry_set.remove<InstancesComponent>();
|
|
|
|
/* If there was a point cloud, it is now part of the mesh. */
|
|
|
|
new_geometry_set.remove<PointCloudComponent>();
|
|
|
|
return new_geometry_set;
|
|
|
|
}
|
|
|
|
|
2021-02-16 12:30:42 +01:00
|
|
|
GeometrySet geometry_set_realize_instances(const GeometrySet &geometry_set)
|
|
|
|
{
|
|
|
|
if (!geometry_set.has_instances()) {
|
|
|
|
return geometry_set;
|
|
|
|
}
|
|
|
|
|
|
|
|
GeometrySet new_geometry_set;
|
|
|
|
|
2021-03-25 14:54:27 -04:00
|
|
|
Vector<GeometryInstanceGroup> set_groups;
|
|
|
|
geometry_set_gather_instances(geometry_set, set_groups);
|
2021-02-18 10:13:56 +01:00
|
|
|
join_instance_groups_mesh(set_groups, false, new_geometry_set);
|
2021-02-16 12:30:42 +01:00
|
|
|
join_instance_groups_pointcloud(set_groups, new_geometry_set);
|
|
|
|
join_instance_groups_volume(set_groups, new_geometry_set);
|
Geometry Nodes: Initial basic curve data support
This patch adds initial curve support to geometry nodes. Currently
there is only one node available, the "Curve to Mesh" node, T87428.
However, the aim of the changes here is larger than just supporting
curve data in nodes-- it also uses the opportunity to add better spline
data structures, intended to replace the existing curve evaluation code.
The curve code in Blender is quite old, and it's generally regarded as
some of the messiest, hardest-to-understand code as well. The classes
in `BKE_spline.hh` aim to be faster, more extensible, and much more
easily understandable. Further explanation can be found in comments in
that file.
Initial builtin spline attributes are supported-- reading and writing
from the `cyclic` and `resolution` attributes works with any of the
attribute nodes. Also, only Z-up normal calculation is implemented
at the moment, and tilts do not apply yet.
**Limitations**
- For now, you must bring curves into the node tree with an "Object
Info" node. Changes to the curve modifier stack will come later.
- Converting to a mesh is necessary to visualize the curve data.
Further progress can be tracked in: T87245
Higher level design document: https://wiki.blender.org/wiki/Modules/Physics_Nodes/Projects/EverythingNodes/CurveNodes
Differential Revision: https://developer.blender.org/D11091
2021-05-03 12:29:17 -05:00
|
|
|
join_instance_groups_curve(set_groups, new_geometry_set);
|
2021-02-16 12:30:42 +01:00
|
|
|
|
|
|
|
return new_geometry_set;
|
|
|
|
}
|
|
|
|
|
2021-02-16 12:07:10 +01:00
|
|
|
} // namespace blender::bke
|