diff options
author | Hans Goudey <h.goudey@me.com> | 2021-10-15 22:20:53 +0300 |
---|---|---|
committer | Hans Goudey <h.goudey@me.com> | 2021-10-15 22:20:53 +0300 |
commit | 19bab2a5360708242a5f6ea11b6e2ff03568a679 (patch) | |
tree | 50c4a4862ed08ca62809b462e273a3925649c9d8 /source/blender/nodes | |
parent | 76f386a37a9cf14ac729be048230f81a0a397fc8 (diff) |
Geometry Nodes: Object info node optional instance output
The object info node output an instance as a performance optimization.
Before that optimization was (almost) invisible to the user, but now
that we aren't automatically realizing instances, it isn't intuitive
for a single object to become an instance.
I refactored the transform node so its ability to translate/transform
an entire geometry set was more usable from elsewhere and exposed the
function to get a geometry set from an object.
Differential Revision: https://developer.blender.org/D12833
Diffstat (limited to 'source/blender/nodes')
5 files changed, 132 insertions, 98 deletions
diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh index 21404525748..f382ff6c132 100644 --- a/source/blender/nodes/geometry/node_geometry_util.hh +++ b/source/blender/nodes/geometry/node_geometry_util.hh @@ -50,11 +50,15 @@ void update_attribute_input_socket_availabilities(bNode &node, Array<uint32_t> get_geometry_element_ids_as_uints(const GeometryComponent &component, const AttributeDomain domain); -void transform_mesh(Mesh *mesh, +void transform_mesh(Mesh &mesh, const float3 translation, const float3 rotation, const float3 scale); +void transform_geometry_set(GeometrySet &geometry, + const float4x4 &transform, + const Depsgraph &depsgraph); + Mesh *create_line_mesh(const float3 start, const float3 delta, const int count); Mesh *create_grid_mesh(const int verts_x, diff --git a/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc b/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc index fdc6b12095c..8b90595a641 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc @@ -153,7 +153,7 @@ static void geo_node_bounding_box_exec(GeoNodeExecParams params) const float3 scale = max - min; const float3 center = min + scale / 2.0f; Mesh *mesh = create_cuboid_mesh(scale, 2, 2, 2); - transform_mesh(mesh, center, float3(0), float3(1)); + transform_mesh(*mesh, center, float3(0), float3(1)); params.set_output("Bounding Box", GeometrySet::create_with_mesh(mesh)); params.set_output("Min", min); params.set_output("Max", max); diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc index af8ce02b3c1..5a520d36296 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc @@ -456,12 +456,12 @@ static Mesh *create_cube_mesh(const float3 size, } if (verts_y == 1) { /* XZ plane. */ Mesh *mesh = create_grid_mesh(verts_x, verts_z, size.x, size.z); - transform_mesh(mesh, float3(0), float3(M_PI_2, 0.0f, 0.0f), float3(1)); + transform_mesh(*mesh, float3(0), float3(M_PI_2, 0.0f, 0.0f), float3(1)); return mesh; } /* YZ plane. */ Mesh *mesh = create_grid_mesh(verts_z, verts_y, size.z, size.y); - transform_mesh(mesh, float3(0), float3(0.0f, M_PI_2, 0.0f), float3(1)); + transform_mesh(*mesh, float3(0), float3(0.0f, M_PI_2, 0.0f), float3(1)); return mesh; } diff --git a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc index 389acc40f0f..e61709ed86a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc @@ -26,6 +26,10 @@ namespace blender::nodes { static void geo_node_object_info_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Object>("Object").hide_label(); + b.add_input<decl::Bool>("As Instance") + .description( + "Output the entire object as single instance. " + "This allows instancing non-geometry object types"); b.add_output<decl::Vector>("Location"); b.add_output<decl::Vector>("Rotation"); b.add_output<decl::Vector>("Scale"); @@ -54,12 +58,11 @@ static void geo_node_object_info_exec(GeoNodeExecParams params) const Object *self_object = params.self_object(); if (object != nullptr) { - float transform[4][4]; - mul_m4_m4m4(transform, self_object->imat, object->obmat); + const float4x4 transform = float4x4(self_object->imat) * float4x4(object->obmat); float quaternion[4]; if (transform_space_relative) { - mat4_decompose(location, quaternion, scale, transform); + mat4_decompose(location, quaternion, scale, transform.values); } else { mat4_decompose(location, quaternion, scale, object->obmat); @@ -67,16 +70,23 @@ static void geo_node_object_info_exec(GeoNodeExecParams params) quat_to_eul(rotation, quaternion); if (object != self_object) { - InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>(); - const int handle = instances.add_reference(*object); - - if (transform_space_relative) { - instances.add_instance(handle, transform); + if (params.get_input<bool>("As Instance")) { + InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>(); + const int handle = instances.add_reference(*object); + if (transform_space_relative) { + instances.add_instance(handle, transform); + } + else { + float unit_transform[4][4]; + unit_m4(unit_transform); + instances.add_instance(handle, unit_transform); + } } else { - float unit_transform[4][4]; - unit_m4(unit_transform); - instances.add_instance(handle, unit_transform); + geometry_set = bke::object_get_evaluated_geometry_set(*object); + if (transform_space_relative) { + transform_geometry_set(geometry_set, transform, *params.depsgraph()); + } } } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_transform.cc b/source/blender/nodes/geometry/nodes/node_geo_transform.cc index d5eb067cad0..005714a9580 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_transform.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_transform.cc @@ -25,6 +25,7 @@ #include "DNA_volume_types.h" #include "BKE_mesh.h" +#include "BKE_pointcloud.h" #include "BKE_spline.hh" #include "BKE_volume.h" @@ -55,112 +56,142 @@ static bool use_translate(const float3 rotation, const float3 scale) return true; } -void transform_mesh(Mesh *mesh, +static void translate_mesh(Mesh &mesh, const float3 translation) +{ + if (!translation.is_zero()) { + BKE_mesh_translate(&mesh, translation, false); + } +} + +static void transform_mesh(Mesh &mesh, const float4x4 &transform) +{ + BKE_mesh_transform(&mesh, transform.values, false); + BKE_mesh_normals_tag_dirty(&mesh); +} + +void transform_mesh(Mesh &mesh, const float3 translation, const float3 rotation, const float3 scale) { - /* Use only translation if rotation and scale are zero. */ - if (use_translate(rotation, scale)) { - if (!translation.is_zero()) { - BKE_mesh_translate(mesh, translation, false); - } - } - else { - const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, scale); - BKE_mesh_transform(mesh, matrix.values, false); - BKE_mesh_normals_tag_dirty(mesh); - } + const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, scale); + transform_mesh(mesh, matrix); } -static void transform_pointcloud(PointCloud *pointcloud, - const float3 translation, - const float3 rotation, - const float3 scale) +static void translate_pointcloud(PointCloud &pointcloud, const float3 translation) { - /* Use only translation if rotation and scale don't apply. */ - if (use_translate(rotation, scale)) { - for (const int i : IndexRange(pointcloud->totpoint)) { - add_v3_v3(pointcloud->co[i], translation); - } + CustomData_duplicate_referenced_layer(&pointcloud.pdata, CD_PROP_FLOAT3, pointcloud.totpoint); + BKE_pointcloud_update_customdata_pointers(&pointcloud); + for (const int i : IndexRange(pointcloud.totpoint)) { + add_v3_v3(pointcloud.co[i], translation); } - else { - const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, scale); - for (const int i : IndexRange(pointcloud->totpoint)) { - float3 &co = *(float3 *)pointcloud->co[i]; - co = matrix * co; - } +} + +static void transform_pointcloud(PointCloud &pointcloud, const float4x4 &transform) +{ + CustomData_duplicate_referenced_layer(&pointcloud.pdata, CD_PROP_FLOAT3, pointcloud.totpoint); + BKE_pointcloud_update_customdata_pointers(&pointcloud); + for (const int i : IndexRange(pointcloud.totpoint)) { + float3 &co = *(float3 *)pointcloud.co[i]; + co = transform * co; } } -static void transform_instances(InstancesComponent &instances, - const float3 translation, - const float3 rotation, - const float3 scale) +static void translate_instances(InstancesComponent &instances, const float3 translation) { MutableSpan<float4x4> transforms = instances.instance_transforms(); - - /* Use only translation if rotation and scale don't apply. */ - if (use_translate(rotation, scale)) { - for (float4x4 &transform : transforms) { - add_v3_v3(transform.ptr()[3], translation); - } + for (float4x4 &transform : transforms) { + add_v3_v3(transform.ptr()[3], translation); } - else { - const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, scale); - for (float4x4 &transform : transforms) { - transform = matrix * transform; - } +} + +static void transform_instances(InstancesComponent &instances, const float4x4 &transform) +{ + MutableSpan<float4x4> instance_transforms = instances.instance_transforms(); + for (float4x4 &instance_transform : instance_transforms) { + instance_transform = transform * instance_transform; } } -static void transform_volume(Volume *volume, - const float3 translation, - const float3 rotation, - const float3 scale, - GeoNodeExecParams ¶ms) +static void transform_volume(Volume &volume, const float4x4 &transform, const Depsgraph &depsgraph) { #ifdef WITH_OPENVDB /* Scaling an axis to zero is not supported for volumes. */ + const float3 translation = transform.translation(); + const float3 rotation = transform.to_euler(); + const float3 scale = transform.scale(); const float3 limited_scale = { (scale.x == 0.0f) ? FLT_EPSILON : scale.x, (scale.y == 0.0f) ? FLT_EPSILON : scale.y, (scale.z == 0.0f) ? FLT_EPSILON : scale.z, }; + const float4x4 scale_limited_transform = float4x4::from_loc_eul_scale( + translation, rotation, limited_scale); - const Main *bmain = DEG_get_bmain(params.depsgraph()); - BKE_volume_load(volume, bmain); - - const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, limited_scale); + const Main *bmain = DEG_get_bmain(&depsgraph); + BKE_volume_load(&volume, bmain); openvdb::Mat4s vdb_matrix; - memcpy(vdb_matrix.asPointer(), matrix, sizeof(float[4][4])); + memcpy(vdb_matrix.asPointer(), &scale_limited_transform, sizeof(float[4][4])); openvdb::Mat4d vdb_matrix_d{vdb_matrix}; - const int num_grids = BKE_volume_num_grids(volume); + const int num_grids = BKE_volume_num_grids(&volume); for (const int i : IndexRange(num_grids)) { - VolumeGrid *volume_grid = BKE_volume_grid_get_for_write(volume, i); + VolumeGrid *volume_grid = BKE_volume_grid_get_for_write(&volume, i); - openvdb::GridBase::Ptr grid = BKE_volume_grid_openvdb_for_write(volume, volume_grid, false); + openvdb::GridBase::Ptr grid = BKE_volume_grid_openvdb_for_write(&volume, volume_grid, false); openvdb::math::Transform &grid_transform = grid->transform(); grid_transform.postMult(vdb_matrix_d); } #else - UNUSED_VARS(volume, translation, rotation, scale, params); + UNUSED_VARS(volume, transform, depsgraph); #endif } -static void transform_curve(CurveEval &curve, - const float3 translation, - const float3 rotation, - const float3 scale) +static void translate_volume(Volume &volume, const float3 translation, const Depsgraph &depsgraph) { - if (use_translate(rotation, scale)) { - curve.translate(translation); + transform_volume(volume, float4x4::from_location(translation), depsgraph); +} + +void transform_geometry_set(GeometrySet &geometry, + const float4x4 &transform, + const Depsgraph &depsgraph) +{ + if (CurveEval *curve = geometry.get_curve_for_write()) { + curve->transform(transform); } - else { - const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, scale); - curve.transform(matrix); + if (Mesh *mesh = geometry.get_mesh_for_write()) { + transform_mesh(*mesh, transform); + } + if (PointCloud *pointcloud = geometry.get_pointcloud_for_write()) { + transform_pointcloud(*pointcloud, transform); + } + if (Volume *volume = geometry.get_volume_for_write()) { + transform_volume(*volume, transform, depsgraph); + } + if (geometry.has_instances()) { + transform_instances(geometry.get_component_for_write<InstancesComponent>(), transform); + } +} + +static void translate_geometry_set(GeometrySet &geometry, + const float3 translation, + const Depsgraph &depsgraph) +{ + if (CurveEval *curve = geometry.get_curve_for_write()) { + curve->translate(translation); + } + if (Mesh *mesh = geometry.get_mesh_for_write()) { + translate_mesh(*mesh, translation); + } + if (PointCloud *pointcloud = geometry.get_pointcloud_for_write()) { + translate_pointcloud(*pointcloud, translation); + } + if (Volume *volume = geometry.get_volume_for_write()) { + translate_volume(*volume, translation, depsgraph); + } + if (geometry.has_instances()) { + translate_instances(geometry.get_component_for_write<InstancesComponent>(), translation); } } @@ -171,25 +202,14 @@ static void geo_node_transform_exec(GeoNodeExecParams params) const float3 rotation = params.extract_input<float3>("Rotation"); const float3 scale = params.extract_input<float3>("Scale"); - if (geometry_set.has_mesh()) { - Mesh *mesh = geometry_set.get_mesh_for_write(); - transform_mesh(mesh, translation, rotation, scale); - } - if (geometry_set.has_pointcloud()) { - PointCloud *pointcloud = geometry_set.get_pointcloud_for_write(); - transform_pointcloud(pointcloud, translation, rotation, scale); - } - if (geometry_set.has_instances()) { - InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>(); - transform_instances(instances, translation, rotation, scale); - } - if (geometry_set.has_volume()) { - Volume *volume = geometry_set.get_volume_for_write(); - transform_volume(volume, translation, rotation, scale, params); + /* Use only translation if rotation and scale don't apply. */ + if (use_translate(rotation, scale)) { + translate_geometry_set(geometry_set, translation, *params.depsgraph()); } - if (geometry_set.has_curve()) { - CurveEval *curve = geometry_set.get_curve_for_write(); - transform_curve(*curve, translation, rotation, scale); + else { + transform_geometry_set(geometry_set, + float4x4::from_loc_eul_scale(translation, rotation, scale), + *params.depsgraph()); } params.set_output("Geometry", std::move(geometry_set)); |