mirror of
https://github.com/blender/blender
synced 2026-09-29 04:37:17 +03:00
Merge branch 'blender-v5.1-release'
This commit is contained in:
commit
900a78c416
3 changed files with 100 additions and 10 deletions
|
|
@ -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;
|
||||
|
|
|
|||
3
tests/files/sculpting/non_uniform_scaling_monkey.blend
Normal file
3
tests/files/sculpting/non_uniform_scaling_monkey.blend
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:eb09bf405d5f67681fed238e8514cc206bccdb872707f066d11afc390c5b25e9
|
||||
size 112699
|
||||
76
tests/python/sculpt_paint/transform_operator_test.py
Normal file
76
tests/python/sculpt_paint/transform_operator_test.py
Normal 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()
|
||||
Loading…
Add table
Add a link
Reference in a new issue