Cleanup: Unify and clean up mesh transform & translation functions

Use C++ types, move to C++ header, use them consistently in the
geometry transform function.
This commit is contained in:
Hans Goudey
2025-03-28 11:36:39 -04:00
parent ac5dc94c40
commit 448d3d04d9
8 changed files with 53 additions and 53 deletions

View File

@@ -205,10 +205,6 @@ void BKE_mesh_nomain_to_meshkey(Mesh *mesh_src, Mesh *mesh_dst, KeyBlock *kb);
/* Vertex level transformations & checks (no evaluated mesh). */
/* basic vertex data functions */
void BKE_mesh_transform(Mesh *mesh, const float mat[4][4], bool do_keys);
void BKE_mesh_translate(Mesh *mesh, const float offset[3], bool do_keys);
void BKE_mesh_tessface_clear(Mesh *mesh);
void BKE_mesh_mselect_clear(Mesh *mesh);

View File

@@ -9,6 +9,7 @@
*/
#include "BLI_index_mask_fwd.hh"
#include "BLI_math_matrix_types.hh"
#include "BLI_offset_indices.hh"
#include "BLI_string_ref.hh"
@@ -363,6 +364,10 @@ Mesh *mesh_new_no_attributes(int verts_num, int edges_num, int faces_num, int co
/** Calculate edges from faces. */
void mesh_calc_edges(Mesh &mesh, bool keep_existing_edges, bool select_new_edges);
void mesh_translate(Mesh &mesh, const float3 &translation, bool do_shape_keys);
void mesh_transform(Mesh &mesh, const float4x4 &transform, bool do_shape_keys);
void mesh_flip_faces(Mesh &mesh, const IndexMask &selection);
void mesh_ensure_required_data_layers(Mesh &mesh);

View File

@@ -26,7 +26,7 @@
#include "BLI_implicit_sharing.hh"
#include "BLI_index_range.hh"
#include "BLI_listbase.h"
#include "BLI_math_matrix.h"
#include "BLI_math_matrix.hh"
#include "BLI_math_vector.hh"
#include "BLI_memory_counter.hh"
#include "BLI_set.hh"
@@ -1363,26 +1363,6 @@ void Mesh::bounds_set_eager(const blender::Bounds<float3> &bounds)
this->runtime->bounds_cache.ensure([&](blender::Bounds<float3> &r_data) { r_data = bounds; });
}
void BKE_mesh_transform(Mesh *mesh, const float mat[4][4], bool do_keys)
{
MutableSpan<float3> positions = mesh->vert_positions_for_write();
for (float3 &position : positions) {
mul_m4_v3(mat, position);
}
if (do_keys && mesh->key) {
LISTBASE_FOREACH (KeyBlock *, kb, &mesh->key->block) {
float *fp = (float *)kb->data;
for (int i = kb->totelem; i--; fp += 3) {
mul_m4_v3(mat, fp);
}
}
}
mesh->tag_positions_changed();
}
std::optional<int> Mesh::material_index_max() const
{
this->runtime->max_material_index.ensure([&](std::optional<int> &value) {
@@ -1415,9 +1395,19 @@ std::optional<int> Mesh::material_index_max() const
return this->runtime->max_material_index.data();
}
namespace blender::bke {
static void transform_positions(MutableSpan<float3> positions, const float4x4 &matrix)
{
threading::parallel_for(positions.index_range(), 1024, [&](const IndexRange range) {
for (float3 &position : positions.slice(range)) {
position = math::transform_point(matrix, position);
}
});
}
static void translate_positions(MutableSpan<float3> positions, const float3 &translation)
{
using namespace blender;
threading::parallel_for(positions.index_range(), 2048, [&](const IndexRange range) {
for (float3 &position : positions.slice(range)) {
position += translation;
@@ -1425,34 +1415,49 @@ static void translate_positions(MutableSpan<float3> positions, const float3 &tra
});
}
void BKE_mesh_translate(Mesh *mesh, const float offset[3], const bool do_keys)
void mesh_translate(Mesh &mesh, const float3 &translation, const bool do_shape_keys)
{
using namespace blender;
if (math::is_zero(float3(offset))) {
if (math::is_zero(translation)) {
return;
}
std::optional<Bounds<float3>> bounds;
if (mesh->runtime->bounds_cache.is_cached()) {
bounds = mesh->runtime->bounds_cache.data();
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<float3 *>(kb->data), kb->totelem}, offset);
translate_positions(mesh.vert_positions_for_write(), translation);
if (do_shape_keys && mesh.key) {
LISTBASE_FOREACH (KeyBlock *, kb, &mesh.key->block) {
translate_positions({static_cast<float3 *>(kb->data), kb->totelem}, translation);
}
}
mesh->tag_positions_changed_uniformly();
mesh.tag_positions_changed_uniformly();
if (bounds) {
bounds->min += offset;
bounds->max += offset;
mesh->bounds_set_eager(*bounds);
bounds->min += translation;
bounds->max += translation;
mesh.bounds_set_eager(*bounds);
}
}
void mesh_transform(Mesh &mesh, const float4x4 &transform, bool do_shape_keys)
{
transform_positions(mesh.vert_positions_for_write(), transform);
if (do_shape_keys && mesh.key) {
LISTBASE_FOREACH (KeyBlock *, kb, &mesh.key->block) {
transform_positions(MutableSpan(static_cast<float3 *>(kb->data), kb->totelem), transform);
}
}
mesh.tag_positions_changed();
}
} // namespace blender::bke
void BKE_mesh_tessface_clear(Mesh *mesh)
{
mesh_tessface_clear_intern(mesh, true);

View File

@@ -869,7 +869,7 @@ static wmOperatorStatus apply_objects_internal(bContext *C,
}
/* adjust data */
BKE_mesh_transform(mesh, mat, true);
bke::mesh_transform(*mesh, float4x4(mat), true);
}
else if (ob->type == OB_ARMATURE) {
bArmature *arm = static_cast<bArmature *>(ob->data);
@@ -1451,7 +1451,7 @@ static wmOperatorStatus object_origin_set_exec(bContext *C, wmOperator *op)
}
negate_v3_v3(cent_neg, cent);
BKE_mesh_translate(mesh, cent_neg, true);
bke::mesh_translate(*mesh, cent_neg, true);
tot_change++;
mesh->id.tag |= ID_TAG_DOIT;

View File

@@ -47,12 +47,6 @@ static void transform_positions(MutableSpan<float3> positions, const float4x4 &m
});
}
static void transform_mesh(Mesh &mesh, const float4x4 &transform)
{
transform_positions(mesh.vert_positions_for_write(), transform);
mesh.tag_positions_changed();
}
static void translate_pointcloud(PointCloud &pointcloud, const float3 translation)
{
if (math::is_zero(translation)) {
@@ -251,7 +245,7 @@ void translate_geometry(bke::GeometrySet &geometry, const float3 translation)
curves->geometry.wrap().translate(translation);
}
if (Mesh *mesh = geometry.get_mesh_for_write()) {
BKE_mesh_translate(mesh, translation, false);
bke::mesh_translate(*mesh, translation, false);
}
if (PointCloud *pointcloud = geometry.get_pointcloud_for_write()) {
translate_pointcloud(*pointcloud, translation);
@@ -284,7 +278,7 @@ std::optional<TransformGeometryErrors> transform_geometry(bke::GeometrySet &geom
curves->geometry.wrap().transform(transform);
}
if (Mesh *mesh = geometry.get_mesh_for_write()) {
transform_mesh(*mesh, transform);
bke::mesh_transform(*mesh, transform, false);
}
if (PointCloud *pointcloud = geometry.get_pointcloud_for_write()) {
transform_pointcloud(*pointcloud, transform);
@@ -322,7 +316,7 @@ void transform_mesh(Mesh &mesh,
const float3 scale)
{
const float4x4 matrix = math::from_loc_rot_scale<float4x4>(translation, rotation, scale);
transform_mesh(mesh, matrix);
bke::mesh_transform(mesh, matrix, false);
}
} // namespace blender::geometry

View File

@@ -163,7 +163,7 @@ static void rna_Mesh_normals_split_custom_set_from_vertices(Mesh *mesh,
static void rna_Mesh_transform(Mesh *mesh, const float mat[16], bool shape_keys)
{
BKE_mesh_transform(mesh, (const float(*)[4])mat, shape_keys);
blender::bke::mesh_transform(*mesh, blender::float4x4(mat), shape_keys);
DEG_id_tag_update(&mesh->id, 0);
}

View File

@@ -157,7 +157,7 @@ static Mesh *generate_bounding_box_mesh(const std::optional<Bounds<float3>> &bou
result->totcol = totcol;
}
BKE_mesh_translate(result, math::midpoint(bounds->min, bounds->max), false);
bke::mesh_translate(*result, math::midpoint(bounds->min, bounds->max), false);
return result;
}

View File

@@ -131,7 +131,7 @@ static void node_geo_exec(GeoNodeExecParams params)
BKE_id_material_eval_ensure_default_slot(&mesh->id);
/* Transform the mesh so that the base of the cone is at the origin. */
BKE_mesh_translate(mesh, float3(0.0f, 0.0f, depth * 0.5f), false);
bke::mesh_translate(*mesh, float3(0.0f, 0.0f, depth * 0.5f), false);
params.set_output("Mesh", GeometrySet::from_mesh(mesh));
}