Refactor: Deduplicate position transform utilities

The pattern of transforming many position vectors at once is quite
common, both with separate source and result arrays, and when modifying
an array in place. In some cases at least we used a separate function
with a consistent name across files, but there were also many duplicate
parallel transform implementations.

This commit adds these utilities to the BLI_math_matrix.hh API and uses
them where many positions from contiguous arrays are transformed at
once. While there might be a more ideal location for these utilities,
it's consistent with 3936d7a93e, and certainly better
than duplicating them.

This also reduces binary size of my build by 15 KB.

Pull Request: https://projects.blender.org/blender/blender/pulls/145352
This commit is contained in:
Hans Goudey
2025-08-28 12:11:03 -04:00
committed by Gitea
parent fbaf6d42f0
commit c01d4a4ee6
21 changed files with 122 additions and 235 deletions

View File

@@ -1249,15 +1249,6 @@ static void translate_positions(MutableSpan<float3> positions, const float3 &tra
});
}
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);
}
});
}
void CurvesGeometry::calculate_bezier_auto_handles()
{
if (!this->has_curve_with_type(CURVE_TYPE_BEZIER)) {
@@ -1319,12 +1310,12 @@ void CurvesGeometry::translate(const float3 &translation)
void CurvesGeometry::transform(const float4x4 &matrix)
{
transform_positions(this->positions_for_write(), matrix);
math::transform_points(matrix, this->positions_for_write());
if (this->handle_positions_left()) {
transform_positions(this->handle_positions_left_for_write(), matrix);
math::transform_points(matrix, this->handle_positions_left_for_write());
}
if (this->handle_positions_right()) {
transform_positions(this->handle_positions_right_for_write(), matrix);
math::transform_points(matrix, this->handle_positions_right_for_write());
}
MutableAttributeAccessor attributes = this->attributes_for_write();
transform_custom_normal_attribute(matrix, attributes);

View File

@@ -3432,19 +3432,6 @@ blender::bke::greasepencil::Drawing *GreasePencil::get_eval_drawing(
return this->get_drawing_at(layer, this->runtime->eval_frame);
}
static void transform_positions(const Span<blender::float3> src,
const blender::float4x4 &transform,
blender::MutableSpan<blender::float3> dst)
{
BLI_assert(src.size() == dst.size());
blender::threading::parallel_for(src.index_range(), 4096, [&](const blender::IndexRange range) {
for (const int i : range) {
dst[i] = blender::math::transform_point(transform, src[i]);
}
});
}
std::optional<blender::Bounds<blender::float3>> GreasePencil::bounds_min_max(
const int frame, const bool use_radius) const
{
@@ -3471,7 +3458,7 @@ std::optional<blender::Bounds<blender::float3>> GreasePencil::bounds_min_max(
}
const VArray<float> radius = curves.radius();
Array<float3> positions_world(curves.evaluated_points_num());
transform_positions(curves.evaluated_positions(), layer_to_object, positions_world);
math::transform_points(curves.evaluated_positions(), layer_to_object, positions_world);
if (!use_radius) {
const Bounds<float3> drawing_bounds = *bounds::min_max(positions_world.as_span());
bounds = bounds::merge(bounds, drawing_bounds);

View File

@@ -1838,15 +1838,6 @@ const blender::VectorSet<int> &Mesh::material_indices_used() const
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)
{
threading::parallel_for(positions.index_range(), 2048, [&](const IndexRange range) {
@@ -1886,11 +1877,11 @@ void mesh_translate(Mesh &mesh, const float3 &translation, const bool do_shape_k
void mesh_transform(Mesh &mesh, const float4x4 &transform, bool do_shape_keys)
{
transform_positions(mesh.vert_positions_for_write(), transform);
math::transform_points(transform, mesh.vert_positions_for_write());
if (do_shape_keys && mesh.key) {
LISTBASE_FOREACH (KeyBlock *, kb, &mesh.key->block) {
transform_positions(MutableSpan(static_cast<float3 *>(kb->data), kb->totelem), transform);
math::transform_points(transform, MutableSpan(static_cast<float3 *>(kb->data), kb->totelem));
}
}
MutableAttributeAccessor attributes = mesh.attributes_for_write();

View File

@@ -1813,4 +1813,13 @@ extern template float4x4 perspective(
void transform_normals(const float3x3 &transform, MutableSpan<float3> normals);
void transform_normals(Span<float3> src, const float3x3 &transform, MutableSpan<float3> dst);
/** Transform point vectors with matrix multiplication, optionally using multi-threading. */
void transform_points(const float4x4 &transform,
MutableSpan<float3> points,
bool use_threading = true);
void transform_points(Span<float3> src,
const float4x4 &transform,
MutableSpan<float3> dst,
bool use_threading = true);
} // namespace blender::math

View File

@@ -596,4 +596,62 @@ void transform_normals(Span<float3> src, const float3x3 &transform, MutableSpan<
}
}
static bool skip_transform(const float4x4 &transform)
{
return math::is_equal(transform, float4x4::identity(), 1e-6f);
}
static void transform_points_no_threading(const Span<float3> src,
const float4x4 &transform,
MutableSpan<float3> dst)
{
for (const int64_t i : src.index_range()) {
dst[i] = math::transform_point(transform, src[i]);
}
}
void transform_points(const Span<float3> src,
const float4x4 &transform,
MutableSpan<float3> dst,
const bool use_threading)
{
if (skip_transform(transform)) {
dst.copy_from(src);
}
else {
if (use_threading) {
threading::parallel_for(src.index_range(), 1024, [&](const IndexRange range) {
transform_points_no_threading(src.slice(range), transform, dst.slice(range));
});
}
else {
transform_points_no_threading(src, transform, dst);
}
}
}
static void transform_points_no_threading(const float4x4 &transform, MutableSpan<float3> points)
{
for (float3 &position : points) {
position = math::transform_point(transform, position);
}
}
void transform_points(const float4x4 &transform,
MutableSpan<float3> points,
const bool use_threading)
{
if (skip_transform(transform)) {
return;
}
if (use_threading) {
threading::parallel_for(points.index_range(), 1024, [&](const IndexRange range) {
transform_points_no_threading(transform, points.slice(range));
});
}
else {
transform_points_no_threading(transform, points);
}
}
} // namespace blender::math

View File

@@ -246,16 +246,6 @@ BLI_INLINE int32_t pack_rotation_aspect_hardness(float rot, float asp, float sof
return packed;
}
static void copy_transformed_positions(const Span<float3> src_positions,
const IndexRange range,
const float4x4 &transform,
MutableSpan<float3> dst_positions)
{
for (const int point_i : range) {
dst_positions[point_i] = math::transform_point(transform, src_positions[point_i]);
}
}
[[maybe_unused]] static bool grease_pencil_batch_cache_is_edit_discarded(
GreasePencilBatchCache *cache)
{
@@ -334,11 +324,8 @@ static void grease_pencil_weight_batch_ensure(Object &object,
object, info.drawing, memory);
const IndexRange points(drawing_start_offset, curves.points_num());
const Span<float3> positions = curves.positions();
MutableSpan<float3> positions_slice = points_pos.slice(points);
threading::parallel_for(curves.points_range(), 1024, [&](const IndexRange range) {
copy_transformed_positions(positions, range, layer_space_to_object_space, positions_slice);
});
math::transform_points(
curves.positions(), layer_space_to_object_space, points_pos.slice(points));
/* Get vertex weights of the active vertex group in this drawing. */
const VArray<float> weights = *curves.attributes().lookup_or_default<float>(
@@ -532,14 +519,8 @@ static void grease_pencil_cache_add_nurbs(Object &object,
MutableSpan<float3> positions_eval_slice = edit_line_points.slice(eval_slice);
/* This will copy over the position but without the layer transform. */
array_utils::gather(positions, nurbs_points, positions_eval_slice);
/* Go through the position and apply the layer transform. */
threading::parallel_for(nurbs_points.index_range(), 1024, [&](const IndexRange range) {
copy_transformed_positions(
positions_eval_slice, range, layer_space_to_object_space, positions_eval_slice);
});
math::transform_points(layer_space_to_object_space, positions_eval_slice);
MutableSpan<float> selection_eval_slice = edit_line_selection.slice(eval_slice);
@@ -844,22 +825,14 @@ static void grease_pencil_edit_batch_ensure(Object &object,
const IndexRange points(drawing_start_offset, curves.points_num());
const IndexRange points_eval(drawing_line_start_offset, curves.evaluated_points_num());
const Span<float3> positions = curves.positions();
if (!layer.is_locked()) {
MutableSpan<float3> positions_slice = edit_points.slice(points);
threading::parallel_for(curves.points_range(), 1024, [&](const IndexRange range) {
copy_transformed_positions(positions, range, layer_space_to_object_space, positions_slice);
});
math::transform_points(
curves.positions(), layer_space_to_object_space, edit_points.slice(points));
}
const Span<float3> positions_eval = curves.evaluated_positions();
MutableSpan<float3> positions_eval_slice = edit_line_points.slice(points_eval);
threading::parallel_for(
IndexRange(curves.evaluated_points_num()), 1024, [&](const IndexRange range) {
copy_transformed_positions(
positions_eval, range, layer_space_to_object_space, positions_eval_slice);
});
math::transform_points(curves.evaluated_positions(),
layer_space_to_object_space,
edit_line_points.slice(points_eval));
/* Do not show selection for locked layers. */
if (!layer.is_locked()) {
@@ -944,17 +917,11 @@ static void grease_pencil_edit_batch_ensure(Object &object,
const Span<float3> handles_left = *curves.handle_positions_left();
const Span<float3> handles_right = *curves.handle_positions_right();
/* This will copy over the position but without the layer transform. */
array_utils::gather(handles_left, bezier_points, positions_slice_left);
array_utils::gather(handles_right, bezier_points, positions_slice_right);
/* Go through the position and apply the layer transform. */
threading::parallel_for(bezier_points.index_range(), 1024, [&](const IndexRange range) {
copy_transformed_positions(
positions_slice_left, range, layer_space_to_object_space, positions_slice_left);
copy_transformed_positions(
positions_slice_right, range, layer_space_to_object_space, positions_slice_right);
});
math::transform_points(layer_space_to_object_space, positions_slice_left);
math::transform_points(layer_space_to_object_space, positions_slice_right);
const VArray<float> selected_left = *curves.attributes().lookup_or_default<float>(
".selection_handle_left", bke::AttrDomain::Point, true);

View File

@@ -263,11 +263,7 @@ static wmOperatorStatus bake_grease_pencil_animation_exec(bContext *C, wmOperato
target_material_indices.finish();
MutableSpan<float3> positions = target_strokes.positions_for_write();
threading::parallel_for(positions.index_range(), 4096, [&](IndexRange range) {
for (const int i : range) {
positions[i] = math::transform_point(to_target, positions[i]);
}
});
math::transform_points(to_target, positions);
if (drawing_placement) {
threading::parallel_for(positions.index_range(), 4096, [&](IndexRange range) {
for (const int i : range) {

View File

@@ -751,14 +751,11 @@ bke::CurvesGeometry create_curves_outline(const bke::greasepencil::Drawing &draw
"material_index", bke::AttrDomain::Curve, 0);
/* Transform positions and radii. */
const float scale = math::average(math::to_scale(transform));
Array<float3> transformed_positions(src_positions.size());
math::transform_points(src_positions, transform, transformed_positions);
Array<float> transformed_radii(src_radii.size());
threading::parallel_for(transformed_positions.index_range(), 4096, [&](const IndexRange range) {
for (const int i : range) {
transformed_positions[i] = math::transform_point(transform, src_positions[i]);
}
});
const float scale = math::average(math::to_scale(transform));
threading::parallel_for(transformed_radii.index_range(), 4096, [&](const IndexRange range) {
for (const int i : range) {
transformed_radii[i] = src_radii[i] * scale;
@@ -794,9 +791,8 @@ bke::CurvesGeometry create_curves_outline(const bke::greasepencil::Drawing &draw
data.point_indices);
/* Transform perimeter positions back into object space. */
for (float3 &pos : data.positions.as_mutable_span().drop_front(prev_point_num)) {
pos = math::transform_point(transform_inv, pos);
}
math::transform_points(transform_inv,
data.positions.as_mutable_span().drop_front(prev_point_num));
data.curve_indices.append_n_times(curve_i, data.point_counts.size() - prev_curve_num);
});

View File

@@ -340,14 +340,10 @@ void add_armature_envelope_weights(Scene &scene, Object &object, const Object &o
const float4x4 layer_to_world = layer.to_world_space(object);
CurvesGeometry &curves = info.drawing.strokes_for_write();
const Span<float3> src_positions = curves.positions();
/* Get all the positions in world space. */
Array<float3> positions(curves.points_num());
threading::parallel_for(positions.index_range(), 4096, [&](const IndexRange range) {
for (const int i : range) {
positions[i] = math::transform_point(layer_to_world, src_positions[i]);
}
});
math::transform_points(curves.positions(), layer_to_world, positions);
for (const int bone_i : skinnable_bones.index_range()) {
const Bone *bone = skinnable_bones[bone_i];
@@ -411,14 +407,10 @@ void add_armature_automatic_weights(Scene &scene, Object &object, const Object &
const float4x4 layer_to_world = layer.to_world_space(object);
CurvesGeometry &curves = info.drawing.strokes_for_write();
const Span<float3> src_positions = curves.positions();
/* Get all the positions in world space. */
Array<float3> positions(curves.points_num());
threading::parallel_for(positions.index_range(), 4096, [&](const IndexRange range) {
for (const int i : range) {
positions[i] = math::transform_point(layer_to_world, src_positions[i]);
}
});
math::transform_points(curves.positions(), layer_to_world, positions);
for (const int bone_i : skinnable_bones.index_range()) {
const char *deform_group_name = deform_group_names[bone_i].c_str();

View File

@@ -3534,10 +3534,7 @@ static Object *convert_grease_pencil_to_mesh(Base &base,
const bke::greasepencil::Layer *layer = grease_pencil->layers()[layer_index];
blender::float4x4 to_object = layer->to_object_space(*ob);
bke::CurvesGeometry &new_curves = curves_id->geometry.wrap();
MutableSpan<blender::float3> positions = new_curves.positions_for_write();
for (const int point_i : new_curves.points_range()) {
positions[point_i] = blender::math::transform_point(to_object, positions[point_i]);
}
math::transform_points(to_object, new_curves.positions_for_write());
geometries[i] = bke::GeometrySet::from_curves(curves_id);
}
if (geometries.size() > 0) {

View File

@@ -509,17 +509,6 @@ std::unique_ptr<XFormObjectData> data_xform_create_from_edit_mode(ID *id)
return data_xform_create_ex(id, true);
}
static void copy_transformed_positions(const Span<float3> src,
const float4x4 &transform,
MutableSpan<float3> dst)
{
threading::parallel_for(src.index_range(), 1024, [&](const IndexRange range) {
for (const int i : range) {
dst[i] = math::transform_point(transform, src[i]);
}
});
}
static void copy_transformed_radii(const Span<float> src,
const float4x4 &transform,
MutableSpan<float> dst)
@@ -549,7 +538,7 @@ void data_xform_by_mat4(XFormObjectData &xod_base, const float4x4 &transform)
// key_index = bm->shapenr - 1;
}
else {
copy_transformed_positions(xod.positions, transform, mesh->vert_positions_for_write());
math::transform_points(xod.positions, transform, mesh->vert_positions_for_write());
mesh->tag_positions_changed();
}
@@ -640,11 +629,11 @@ void data_xform_by_mat4(XFormObjectData &xod_base, const float4x4 &transform)
bke::CurvesGeometry &curves = curves_id->geometry.wrap();
const auto &xod = reinterpret_cast<const XFormObjectData_Curves &>(xod_base);
if (!curves.has_curve_with_type(CURVE_TYPE_BEZIER)) {
copy_transformed_positions(xod.positions, transform, curves.positions_for_write());
math::transform_points(xod.positions, transform, curves.positions_for_write());
}
else {
Array<float3> transformed_positions(xod.positions.size());
copy_transformed_positions(xod.positions, transform, transformed_positions);
math::transform_points(xod.positions, transform, transformed_positions);
bke::curves::bezier::write_all_positions(
curves, curves.curves_range(), transformed_positions);
}
@@ -654,7 +643,7 @@ void data_xform_by_mat4(XFormObjectData &xod_base, const float4x4 &transform)
case ID_PT: {
PointCloud *pointcloud = reinterpret_cast<PointCloud *>(xod_base.id);
const auto &xod = reinterpret_cast<const XFormObjectData_PointCloud &>(xod_base);
copy_transformed_positions(xod.positions, transform, pointcloud->positions_for_write());
math::transform_points(xod.positions, transform, pointcloud->positions_for_write());
copy_transformed_radii(xod.radii, transform, pointcloud->radius_for_write());
break;
}

View File

@@ -655,15 +655,6 @@ static bool apply_objects_internal_need_single_user(bContext *C)
return (ID_REAL_USERS(ob->data) > CTX_DATA_COUNT(C, selected_editable_objects));
}
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 wmOperatorStatus apply_objects_internal(bContext *C,
ReportList *reports,
bool apply_loc,
@@ -956,7 +947,7 @@ static wmOperatorStatus apply_objects_internal(bContext *C,
}
else if (ob->type == OB_POINTCLOUD) {
PointCloud &pointcloud = *static_cast<PointCloud *>(ob->data);
transform_positions(pointcloud.positions_for_write(), float4x4(mat));
math::transform_points(float4x4(mat), pointcloud.positions_for_write());
pointcloud.tag_positions_changed();
}
else if (ob->type == OB_CAMERA) {

View File

@@ -168,7 +168,7 @@ static void sample_node_surface_mesh(const Depsgraph &depsgraph,
tls.local_positions.resize(verts.size());
MutableSpan<float3> local_positions = tls.local_positions;
transform_positions(positions, mat, local_positions);
math::transform_points(positions, mat, local_positions, false);
const MutableSpan normals = gather_data_mesh(vert_normals, verts, tls.normals);
@@ -211,7 +211,7 @@ static void sample_node_surface_grids(const Depsgraph &depsgraph,
tls.local_positions.resize(positions.size());
MutableSpan<float3> local_positions = tls.local_positions;
transform_positions(positions, mat, local_positions);
math::transform_points(positions, mat, local_positions, false);
tls.normals.resize(positions.size());
MutableSpan<float3> normals = tls.normals;
@@ -257,7 +257,7 @@ static void sample_node_surface_bmesh(const Depsgraph &depsgraph,
tls.local_positions.resize(verts.size());
MutableSpan<float3> local_positions = tls.local_positions;
transform_positions(positions, mat, local_positions);
math::transform_points(positions, mat, local_positions, false);
tls.normals.resize(verts.size());
MutableSpan<float3> normals = tls.normals;
@@ -385,7 +385,7 @@ static void calc_faces(const Depsgraph &depsgraph,
tls.local_positions.resize(verts.size());
MutableSpan<float3> local_positions = tls.local_positions;
transform_positions(positions, mat, local_positions);
math::transform_points(positions, mat, local_positions, false);
if (angle >= 0.0f) {
filter_plane_side_factors(positions, local_positions, scrape_planes, factors);
@@ -447,7 +447,7 @@ static void calc_grids(const Depsgraph &depsgraph,
tls.local_positions.resize(positions.size());
MutableSpan<float3> local_positions = tls.local_positions;
transform_positions(positions, mat, local_positions);
math::transform_points(positions, mat, local_positions, false);
if (angle >= 0.0f) {
filter_plane_side_factors(positions, local_positions, scrape_planes, factors);
@@ -508,7 +508,7 @@ static void calc_bmesh(const Depsgraph &depsgraph,
tls.local_positions.resize(verts.size());
MutableSpan<float3> local_positions = tls.local_positions;
transform_positions(positions, mat, local_positions);
math::transform_points(positions, mat, local_positions, false);
if (angle >= 0.0f) {
filter_plane_side_factors(positions, local_positions, scrape_planes, factors);

View File

@@ -63,15 +63,6 @@ static void calc_local_positions(const float4x4 &mat,
}
}
static void calc_local_positions(const float4x4 &mat,
const Span<float3> positions,
const MutableSpan<float3> local_positions)
{
for (const int i : positions.index_range()) {
local_positions[i] = math::transform_point(mat, positions[i]);
}
}
/**
* Computes the local distances. For vertices above the plane,
* the z-distances are divided by `height`, effectively scaling the
@@ -280,7 +271,7 @@ static void calc_grids(const Depsgraph &depsgraph,
tls.local_positions.resize(positions.size());
const MutableSpan<float3> local_positions = tls.local_positions;
calc_local_positions(mat, positions, local_positions);
math::transform_points(positions, mat, local_positions);
tls.distances.resize(positions.size());
const MutableSpan<float> distances = tls.distances;
@@ -332,7 +323,7 @@ static void calc_bmesh(const Depsgraph &depsgraph,
tls.local_positions.resize(positions.size());
const MutableSpan<float3> local_positions = tls.local_positions;
calc_local_positions(mat, positions, local_positions);
math::transform_points(positions, mat, local_positions);
tls.distances.resize(positions.size());
const MutableSpan<float> distances = tls.distances;

View File

@@ -173,9 +173,7 @@ struct DensityAddOperationExecutor {
else {
BLI_assert_unreachable();
}
for (float3 &pos : new_positions_cu) {
pos = math::transform_point(transforms_.surface_to_curves, pos);
}
math::transform_points(transforms_.surface_to_curves, new_positions_cu);
if (stroke_extension.is_first) {
this->prepare_curve_roots_kdtrees();

View File

@@ -1591,11 +1591,7 @@ static void process_stroke_weights(const Scene &scene,
/* Update the position of the stroke to undo the movement caused by the modifier. */
MutableSpan<float3> positions = curves.positions_for_write().slice(points);
threading::parallel_for(positions.index_range(), 1024, [&](const IndexRange range) {
for (float3 &position : positions.slice(range)) {
position = math::transform_point(matrix, position);
}
});
math::transform_points(matrix, positions);
}
static bke::CurvesGeometry get_single_stroke(const bke::CurvesGeometry &src, const int curve)

View File

@@ -82,9 +82,6 @@ void translations_from_new_positions(Span<float3> new_positions,
Span<float3> old_positions,
MutableSpan<float3> translations);
void transform_positions(Span<float3> src, const float4x4 &transform, MutableSpan<float3> dst);
void transform_positions(const float4x4 &transform, MutableSpan<float3> positions);
/** Gather data from an array aligned with all geometry vertices. */
template<typename T> void gather_data_mesh(Span<T> src, Span<int> indices, MutableSpan<T> dst);
template<typename T>

View File

@@ -7553,24 +7553,6 @@ void translations_from_new_positions(const Span<float3> new_positions,
}
}
void transform_positions(const Span<float3> src,
const float4x4 &transform,
const MutableSpan<float3> dst)
{
BLI_assert(src.size() == dst.size());
for (const int i : src.index_range()) {
dst[i] = math::transform_point(transform, src[i]);
}
}
void transform_positions(const float4x4 &transform, const MutableSpan<float3> positions)
{
for (const int i : positions.index_range()) {
positions[i] = math::transform_point(transform, positions[i]);
}
}
OffsetIndices<int> create_node_vert_offsets(const Span<bke::pbvh::MeshNode> nodes,
const IndexMask &node_mask,
Array<int> &node_data)

View File

@@ -445,31 +445,6 @@ static bool skip_transform(const float4x4 &transform)
return math::is_equal(transform, float4x4::identity(), 1e-6f);
}
static void copy_transformed_positions(const Span<float3> src,
const float4x4 &transform,
MutableSpan<float3> dst)
{
if (skip_transform(transform)) {
dst.copy_from(src);
}
else {
threading::parallel_for(src.index_range(), 1024, [&](const IndexRange range) {
for (const int i : range) {
dst[i] = math::transform_point(transform, src[i]);
}
});
}
}
static void transform_positions(const float4x4 &transform, MutableSpan<float3> positions)
{
threading::parallel_for(positions.index_range(), 1024, [&](const IndexRange range) {
for (const int i : range) {
positions[i] = math::transform_point(transform, positions[i]);
}
});
}
static void threaded_copy(const GSpan src, GMutableSpan dst)
{
BLI_assert(src.size() == dst.size());
@@ -1236,7 +1211,7 @@ static void execute_realize_pointcloud_task(
const PointCloud &pointcloud = *pointcloud_info.pointcloud;
const IndexRange point_slice{task.start_index, pointcloud.totpoint};
copy_transformed_positions(
math::transform_points(
pointcloud_info.positions, task.transform, all_dst_positions.slice(point_slice));
/* Create point ids. */
@@ -1294,7 +1269,7 @@ static void execute_realize_pointcloud_tasks(const RealizeInstancesOptions &opti
const RealizePointCloudTask &task = tasks.first();
PointCloud *new_points = BKE_pointcloud_copy_for_eval(task.pointcloud_info->pointcloud);
if (!skip_transform(task.transform)) {
transform_positions(task.transform, new_points->positions_for_write());
math::transform_points(task.transform, new_points->positions_for_write());
new_points->tag_positions_changed();
}
add_instance_attributes_to_single_geometry(
@@ -1564,11 +1539,8 @@ static void execute_realize_mesh_task(const RealizeInstancesOptions &options,
MutableSpan<int> dst_corner_verts = all_dst_corner_verts.slice(dst_loop_range);
MutableSpan<int> dst_corner_edges = all_dst_corner_edges.slice(dst_loop_range);
threading::parallel_for(src_positions.index_range(), 1024, [&](const IndexRange vert_range) {
for (const int i : vert_range) {
dst_positions[i] = math::transform_point(task.transform, src_positions[i]);
}
});
math::transform_points(src_positions, task.transform, dst_positions);
threading::parallel_for(src_edges.index_range(), 1024, [&](const IndexRange edge_range) {
for (const int i : edge_range) {
dst_edges[i] = src_edges[i] + task.start_indices.vertex;
@@ -1989,7 +1961,7 @@ static void execute_realize_curve_task(const RealizeInstancesOptions &options,
const IndexRange dst_custom_knot_range{task.start_indices.custom_knot,
curves.nurbs_custom_knots_by_curve().total_size()};
copy_transformed_positions(
math::transform_points(
curves.positions(), task.transform, dst_curves.positions_for_write().slice(dst_point_range));
/* Copy and transform handle positions if necessary. */
@@ -1998,14 +1970,14 @@ static void execute_realize_curve_task(const RealizeInstancesOptions &options,
all_handle_left.slice(dst_point_range).fill(float3(0));
}
else {
copy_transformed_positions(
math::transform_points(
curves_info.handle_left, task.transform, all_handle_left.slice(dst_point_range));
}
if (curves_info.handle_right.is_empty()) {
all_handle_right.slice(dst_point_range).fill(float3(0));
}
else {
copy_transformed_positions(
math::transform_points(
curves_info.handle_right, task.transform, all_handle_right.slice(dst_point_range));
}
}

View File

@@ -38,15 +38,6 @@ static void translate_positions(MutableSpan<float3> positions, const float3 &tra
});
}
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_pointcloud(PointCloud &pointcloud, const float3 translation)
{
if (math::is_zero(translation)) {
@@ -76,7 +67,7 @@ static void transform_pointcloud(PointCloud &pointcloud, const float4x4 &transfo
bke::MutableAttributeAccessor attributes = pointcloud.attributes_for_write();
bke::SpanAttributeWriter position = attributes.lookup_or_add_for_write_span<float3>(
"position", bke::AttrDomain::Point);
transform_positions(position.span, transform);
math::transform_points(transform, position.span);
position.finish();
}
@@ -177,7 +168,7 @@ static void translate_volume(Volume &volume, const float3 translation)
static void transform_curve_edit_hints(bke::CurvesEditHints &edit_hints, const float4x4 &transform)
{
if (const std::optional<MutableSpan<float3>> positions = edit_hints.positions_for_write()) {
transform_positions(*positions, transform);
math::transform_points(transform, *positions);
}
float3x3 deform_mat;
copy_m3_m4(deform_mat.ptr(), transform.ptr());
@@ -203,7 +194,7 @@ static void transform_grease_pencil_edit_hints(bke::GreasePencilEditHints &edit_
for (bke::GreasePencilDrawingEditHints &drawing_hints : *edit_hints.drawing_hints) {
if (const std::optional<MutableSpan<float3>> positions = drawing_hints.positions_for_write()) {
transform_positions(*positions, transform);
math::transform_points(transform, *positions);
}
float3x3 deform_mat = transform.view<3, 3>();
if (drawing_hints.deform_mats.has_value()) {

View File

@@ -397,11 +397,7 @@ void GreasePencilExporter::foreach_stroke_in_layer(const Object &object,
const VArraySpan<ColorGeometry4f> vertex_colors = drawing.vertex_colors();
Array<float3> world_positions(positions.size());
threading::parallel_for(positions.index_range(), 4096, [&](const IndexRange range) {
for (const int i : range) {
world_positions[i] = math::transform_point(layer_to_world, positions[i]);
}
});
math::transform_points(positions, layer_to_world, world_positions);
for (const int i_curve : curves.curves_range()) {
const IndexRange points = points_by_curve[i_curve];
@@ -567,7 +563,7 @@ std::string GreasePencilExporter::coord_to_svg_string(const float2 &screen_co) c
if (camera_persmat_) {
return fmt::format("{},{}", screen_co.x, camera_rect_.size().y - screen_co.y);
}
return fmt::format("{},{}", screen_co.x, screen_rect_.size().y - screen_co.y);
}
return fmt::format("{},{}", screen_co.x, screen_rect_.size().y - screen_co.y);
}
} // namespace blender::io::grease_pencil