From 41ce4cf630eb92fd8d9566e94ab806cd6d05044f Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Sun, 26 Mar 2023 21:27:13 -0400 Subject: [PATCH] Geometry: Skip recomputing bounds after translation Translating meshes, point clouds, and curves and recomputing the bounds is equivalent to just translating the bounds. Now that mesh primitive nodes calculate their bounds in constant time, it's worth updating the bounds eagerly when translating a geometry since doing so should be very cheap and might save a more significant amount of time if they're needed later. --- .../blenkernel/intern/curves_geometry.cc | 15 +++++++ source/blender/blenkernel/intern/mesh.cc | 43 +++++++++++++------ .../nodes/node_geo_transform_geometry.cc | 25 +++++++---- 3 files changed, 62 insertions(+), 21 deletions(-) diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc index cc2ca265cfc..108841b0bcc 100644 --- a/source/blender/blenkernel/intern/curves_geometry.cc +++ b/source/blender/blenkernel/intern/curves_geometry.cc @@ -1037,6 +1037,15 @@ void CurvesGeometry::calculate_bezier_auto_handles() void CurvesGeometry::translate(const float3 &translation) { + if (math::is_zero(translation)) { + return; + } + + std::optional> bounds; + if (this->runtime->bounds_cache.is_cached()) { + bounds = this->runtime->bounds_cache.data(); + } + translate_positions(this->positions_for_write(), translation); if (!this->handle_positions_left().is_empty()) { translate_positions(this->handle_positions_left_for_write(), translation); @@ -1045,6 +1054,12 @@ void CurvesGeometry::translate(const float3 &translation) translate_positions(this->handle_positions_right_for_write(), translation); } this->tag_positions_changed(); + + if (bounds) { + bounds->min += translation; + bounds->max += translation; + this->runtime->bounds_cache.ensure([&](blender::Bounds &r_data) { r_data = *bounds; }); + } } void CurvesGeometry::transform(const float4x4 &matrix) diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 6b4eaa36f93..79e03ccd933 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -1582,23 +1582,42 @@ void BKE_mesh_transform(Mesh *me, const float mat[4][4], bool do_keys) BKE_mesh_tag_positions_changed(me); } -void BKE_mesh_translate(Mesh *me, const float offset[3], const bool do_keys) +static void translate_positions(MutableSpan positions, const float3 &translation) { - MutableSpan positions = me->vert_positions_for_write(); - for (float3 &position : positions) { - position += offset; + using namespace blender; + threading::parallel_for(positions.index_range(), 2048, [&](const IndexRange range) { + for (float3 &position : positions.slice(range)) { + position += translation; + } + }); +} + +void BKE_mesh_translate(Mesh *mesh, const float offset[3], const bool do_keys) +{ + using namespace blender; + if (math::is_zero(float3(offset))) { + return; } - int i; - if (do_keys && me->key) { - LISTBASE_FOREACH (KeyBlock *, kb, &me->key->block) { - float *fp = (float *)kb->data; - for (i = kb->totelem; i--; fp += 3) { - add_v3_v3(fp, offset); - } + std::optional> bounds; + if (mesh->runtime->bounds_cache.is_cached()) { + bounds = mesh->runtime->bounds_cache.data(); + } + + translate_positions(mesh->vert_positions_for_write(), offset); + if (do_keys && mesh->key) { + LISTBASE_FOREACH (KeyBlock *, kb, &mesh->key->block) { + translate_positions({static_cast(kb->data), kb->totelem}, offset); } } - BKE_mesh_tag_positions_changed_uniformly(me); + + BKE_mesh_tag_positions_changed_uniformly(mesh); + + if (bounds) { + bounds->min += offset; + bounds->max += offset; + mesh->bounds_set_eager(*bounds); + } } void BKE_mesh_tessface_clear(Mesh *mesh) diff --git a/source/blender/nodes/geometry/nodes/node_geo_transform_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_transform_geometry.cc index 7eac7bc87aa..10e9182c598 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_transform_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_transform_geometry.cc @@ -54,14 +54,6 @@ static void transform_positions(MutableSpan positions, const float4x4 &m }); } -static void translate_mesh(Mesh &mesh, const float3 translation) -{ - if (!math::is_zero(translation)) { - translate_positions(mesh.vert_positions_for_write(), translation); - BKE_mesh_tag_positions_changed_uniformly(&mesh); - } -} - static void transform_mesh(Mesh &mesh, const float4x4 &transform) { transform_positions(mesh.vert_positions_for_write(), transform); @@ -70,11 +62,26 @@ static void transform_mesh(Mesh &mesh, const float4x4 &transform) static void translate_pointcloud(PointCloud &pointcloud, const float3 translation) { + if (math::is_zero(translation)) { + return; + } + + std::optional> bounds; + if (pointcloud.runtime->bounds_cache.is_cached()) { + bounds = pointcloud.runtime->bounds_cache.data(); + } + MutableAttributeAccessor attributes = pointcloud.attributes_for_write(); SpanAttributeWriter position = attributes.lookup_or_add_for_write_span( "position", ATTR_DOMAIN_POINT); translate_positions(position.span, translation); position.finish(); + + if (bounds) { + bounds->min += translation; + bounds->max += translation; + pointcloud.runtime->bounds_cache.ensure([&](Bounds &r_data) { r_data = *bounds; }); + } } static void transform_pointcloud(PointCloud &pointcloud, const float4x4 &transform) @@ -199,7 +206,7 @@ static void translate_geometry_set(GeoNodeExecParams ¶ms, curves->geometry.wrap().translate(translation); } if (Mesh *mesh = geometry.get_mesh_for_write()) { - translate_mesh(*mesh, translation); + BKE_mesh_translate(mesh, translation, false); } if (PointCloud *pointcloud = geometry.get_pointcloud_for_write()) { translate_pointcloud(*pointcloud, translation); -- 2.30.2