Merge branch 'blender-v5.1-release'

This commit is contained in:
Sean Kim 2026-03-06 18:41:42 -08:00
commit 900a78c416
3 changed files with 100 additions and 10 deletions

View file

@ -83,13 +83,14 @@ void init_transform(bContext *C, Object &ob, const float mval_fl[2], const char
}
}
static std::array<float4x4, 8> transform_matrices_init(const SculptSession &ss,
static std::array<float4x4, 8> transform_matrices_init(const Object &ob,
const SculptSession &ss,
const ePaintSymmetryFlags symm,
const TransformDisplacementMode t_mode)
{
std::array<float4x4, 8> mats;
float3 final_pivot_pos, d_t, d_s;
float3 d_s;
float d_r[4];
float t_mat[4][4], r_mat[4][4], s_mat[4][4], pivot_mat[4][4], pivot_imat[4][4],
transform_mat[4][4];
@ -107,11 +108,20 @@ static std::array<float4x4, 8> transform_matrices_init(const SculptSession &ss,
copy_v3_v3(start_pivot_scale, ss.prev_pivot_scale);
break;
}
const float4x4 &ob_to_world = ob.object_to_world();
const float4x4 &world_to_ob = ob.world_to_object();
for (int i = 0; i < PAINT_SYMM_AREAS; i++) {
ePaintSymmetryAreas v_symm = ePaintSymmetryAreas(i);
copy_v3_v3(final_pivot_pos, ss.pivot_pos);
const float3 final_pivot_pos = SCULPT_flip_v3_by_symm_area(
ss.pivot_pos, symm, v_symm, start_pivot_pos);
const float3 start_pivot_local = SCULPT_flip_v3_by_symm_area(
start_pivot_pos, symm, v_symm, ss.init_pivot_pos);
const float3 final_pivot_world = math::transform_point(ob_to_world, final_pivot_pos);
const float3 start_pivot_world = math::transform_point(ob_to_world, start_pivot_local);
unit_m4(pivot_mat);
@ -120,9 +130,8 @@ static std::array<float4x4, 8> transform_matrices_init(const SculptSession &ss,
unit_m4(s_mat);
/* Translation matrix. */
sub_v3_v3v3(d_t, ss.pivot_pos, start_pivot_pos);
d_t = SCULPT_flip_v3_by_symm_area(d_t, symm, v_symm, ss.init_pivot_pos);
translate_m4(t_mat, d_t[0], d_t[1], d_t[2]);
const float3 d_t_world = final_pivot_world - start_pivot_world;
translate_m4(t_mat, d_t_world.x, d_t_world.y, d_t_world.z);
/* Rotation matrix. */
sub_qt_qtqt(d_r, ss.pivot_rot, start_pivot_rot);
@ -136,8 +145,7 @@ static std::array<float4x4, 8> transform_matrices_init(const SculptSession &ss,
size_to_mat4(s_mat, d_s);
/* Pivot matrix. */
final_pivot_pos = SCULPT_flip_v3_by_symm_area(final_pivot_pos, symm, v_symm, start_pivot_pos);
translate_m4(pivot_mat, final_pivot_pos[0], final_pivot_pos[1], final_pivot_pos[2]);
translate_m4(pivot_mat, final_pivot_world.x, final_pivot_world.y, final_pivot_world.z);
invert_m4_m4(pivot_imat, pivot_mat);
/* Final transform matrix. */
@ -145,6 +153,9 @@ static std::array<float4x4, 8> transform_matrices_init(const SculptSession &ss,
mul_m4_m4m4(transform_mat, transform_mat, s_mat);
mul_m4_m4m4(mats[i].ptr(), transform_mat, pivot_imat);
mul_m4_m4m4(mats[i].ptr(), pivot_mat, mats[i].ptr());
float temp[4][4];
mul_m4_m4m4(temp, mats[i].ptr(), ob_to_world.ptr());
mul_m4_m4m4(mats[i].ptr(), world_to_ob.ptr(), temp);
}
return mats;
@ -290,7 +301,7 @@ static void sculpt_transform_all_vertices(const Depsgraph &depsgraph, const Scul
const ePaintSymmetryFlags symm = SCULPT_mesh_symmetry_xyz_get(ob);
std::array<float4x4, 8> transform_mats = transform_matrices_init(
ss, symm, ss.filter_cache->transform_displacement_mode);
ob, ss, symm, ss.filter_cache->transform_displacement_mode);
/* Regular transform applies all symmetry passes at once as it is split by symmetry areas
* (each vertex can only be transformed once by the transform matrix of its area). */
@ -468,7 +479,7 @@ static void transform_radius_elastic(const Depsgraph &depsgraph,
const ePaintSymmetryFlags symm = SCULPT_mesh_symmetry_xyz_get(ob);
std::array<float4x4, 8> transform_mats = transform_matrices_init(
ss, symm, ss.filter_cache->transform_displacement_mode);
ob, ss, symm, ss.filter_cache->transform_displacement_mode);
bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(ob);
const IndexMask &node_mask = ss.filter_cache->node_mask;

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:eb09bf405d5f67681fed238e8514cc206bccdb872707f066d11afc390c5b25e9
size 112699

View file

@ -0,0 +1,76 @@
# SPDX-FileCopyrightText: 2026 Blender Authors
#
# SPDX-License-Identifier: GPL-2.0-or-later
__all__ = (
"main",
)
import unittest
import sys
import pathlib
import bpy
"""
blender -b --factory-startup --python tests/python/sculpt_paint/transform_operator_test.py -- --testdir tests/files/sculpting/
"""
args = None
# TODO: Current test should be rewritten with Mesh comparison
# framework(see voxel_remesh_compare_test.py) to reduce the amount of
# code, once framework supports context override.
class TransformTest(unittest.TestCase):
def setUp(self):
bpy.ops.wm.open_mainfile(filepath=str(args.testdir / "non_uniform_scaling_monkey.blend"), load_ui=False)
def test_scaling_and_rotating_in_sculpt_mode(self):
test_monkey = bpy.data.objects['test_Monkey']
expected_monkey = bpy.data.objects['Expected_test_Monkey']
bpy.context.view_layer.objects.active = test_monkey
window = bpy.context.window_manager.windows[0]
viewarea_3D = next(area for area in window.screen.areas if area.type == 'VIEW_3D')
window_region = next(region for region in viewarea_3D.regions if region.type == 'WINDOW')
override_context = {
"window": window,
"area": viewarea_3D,
"region": window_region,
"space_data": viewarea_3D.spaces.active,
"region_data": viewarea_3D.spaces.active.region_3d,
"active_object": test_monkey,
"object": test_monkey
}
bpy.ops.ed.undo_push('EXEC_DEFAULT')
with bpy.context.temp_override(**override_context):
bpy.ops.object.mode_set(mode='SCULPT')
bpy.ops.transform.rotate(value=1.5708, orient_axis='Y', orient_type='GLOBAL')
bpy.ops.object.mode_set(mode='OBJECT')
result = expected_monkey.data.unit_test_compare(mesh=test_monkey.data)
self.assertEqual(result, 'Same')
def main():
global args
import argparse
argv = [sys.argv[0]]
if '--' in sys.argv:
argv += sys.argv[sys.argv.index('--') + 1:]
parser = argparse.ArgumentParser()
parser.add_argument('--testdir', required=True, type=pathlib.Path)
args, remaining = parser.parse_known_args(argv)
unittest.main(argv=remaining)
if __name__ == '__main__':
main()