From d4c2d7386405ad801b86854403b7dd52f869c911 Mon Sep 17 00:00:00 2001 From: Jesse Yurkovich Date: Sun, 26 Jan 2025 04:43:16 +0100 Subject: [PATCH] USD: Add test coverage for parent-child transforms during animation Makes use of recently added test data to ensure proper handling of child objects, with animated transform constraints, parented to other objects who also have animated transform constraints. Also uses the `colored_print` module to better segment the test output. Pull Request: https://projects.blender.org/blender/blender/pulls/133600 --- tests/data | 2 +- tests/python/bl_usd_export_test.py | 32 ++++++++++++++++++++++----- tests/python/bl_usd_import_test.py | 25 ++++++++++++++++++++- tests/python/modules/colored_print.py | 4 ++-- 4 files changed, 53 insertions(+), 10 deletions(-) diff --git a/tests/data b/tests/data index 6147e32e517..02bedf6aa5b 160000 --- a/tests/data +++ b/tests/data @@ -1 +1 @@ -Subproject commit 6147e32e517a42a39d7af95e3c1c8757af6edb7d +Subproject commit 02bedf6aa5bf8ece10006a07b380edd3f2843191 diff --git a/tests/python/bl_usd_export_test.py b/tests/python/bl_usd_export_test.py index a3589e98137..ed05f2b5b30 100644 --- a/tests/python/bl_usd_export_test.py +++ b/tests/python/bl_usd_export_test.py @@ -3,6 +3,7 @@ # SPDX-License-Identifier: GPL-2.0-or-later import math +import os import pathlib import pprint import sys @@ -12,6 +13,10 @@ from pxr import Gf, Sdf, Usd, UsdGeom, UsdShade, UsdSkel, UsdUtils, UsdVol import bpy +sys.path.append(str(pathlib.Path(__file__).parent.absolute())) +from modules.colored_print import (print_message, use_message_colors) + + args = None @@ -21,17 +26,23 @@ class AbstractUSDTest(unittest.TestCase): cls._tempdir = tempfile.TemporaryDirectory() cls.testdir = args.testdir cls.tempdir = pathlib.Path(cls._tempdir.name) - - return cls + if os.environ.get("BLENDER_TEST_COLOR") is not None: + use_message_colors() def setUp(self): - self.assertTrue( - self.testdir.exists(), "Test dir {0} should exist".format(self.testdir) - ) + self.assertTrue(self.testdir.exists(), "Test dir {0} should exist".format(self.testdir)) + print_message(self._testMethodName, 'SUCCESS', 'RUN') def tearDown(self): self._tempdir.cleanup() + result = self._outcome.result + ok = all(test != self for test, _ in result.errors + result.failures) + if not ok: + print_message(self._testMethodName, 'FAILURE', 'FAILED') + else: + print_message(self._testMethodName, 'SUCCESS', 'PASSED') + def export_and_validate(self, **kwargs): """Export and validate the resulting USD file.""" @@ -926,6 +937,15 @@ class USDExportTest(AbstractUSDTest): self.assertEqual(rot_samples, [1.0]) self.assertEqual(scale_samples, [1.0]) + prim = stage.GetPrimAtPath("/root/cube_anim_xform/cube_anim_child") + self.assertEqual(prim.GetTypeName(), "Xform") + loc_samples = UsdGeom.Xformable(prim).GetTranslateOp().GetTimeSamples() + rot_samples = UsdGeom.Xformable(prim).GetRotateXYZOp().GetTimeSamples() + scale_samples = UsdGeom.Xformable(prim).GetScaleOp().GetTimeSamples() + self.assertEqual(loc_samples, [1.0]) + self.assertEqual(rot_samples, [1.0, 2.0, 3.0, 4.0]) + self.assertEqual(scale_samples, [1.0]) + # Validate the armature animation prim = stage.GetPrimAtPath("/root/Armature/Armature") self.assertEqual(prim.GetTypeName(), "Skeleton") @@ -1548,7 +1568,7 @@ def main(): parser.add_argument("--testdir", required=True, type=pathlib.Path) args, remaining = parser.parse_known_args(argv) - unittest.main(argv=remaining) + unittest.main(argv=remaining, verbosity=0) if __name__ == "__main__": diff --git a/tests/python/bl_usd_import_test.py b/tests/python/bl_usd_import_test.py index 7d36dc015e1..a52dd83aca9 100644 --- a/tests/python/bl_usd_import_test.py +++ b/tests/python/bl_usd_import_test.py @@ -3,6 +3,7 @@ # SPDX-License-Identifier: GPL-2.0-or-later import math +import os import pathlib import sys import tempfile @@ -11,6 +12,10 @@ from pxr import Ar, Gf, Sdf, Usd, UsdGeom, UsdShade import bpy +sys.path.append(str(pathlib.Path(__file__).parent.absolute())) +from modules.colored_print import (print_message, use_message_colors) + + args = None @@ -18,6 +23,8 @@ class AbstractUSDTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.testdir = args.testdir + if os.environ.get("BLENDER_TEST_COLOR") is not None: + use_message_colors() def setUp(self): self._tempdir = tempfile.TemporaryDirectory() @@ -28,12 +35,21 @@ class AbstractUSDTest(unittest.TestCase): self.assertTrue(self.tempdir.exists(), 'Temp dir {0} should exist'.format(self.tempdir)) + print_message(self._testMethodName, 'SUCCESS', 'RUN') + # Make sure we always start with a known-empty file. bpy.ops.wm.open_mainfile(filepath=str(self.testdir / "empty.blend")) def tearDown(self): self._tempdir.cleanup() + result = self._outcome.result + ok = all(test != self for test, _ in result.errors + result.failures) + if not ok: + print_message(self._testMethodName, 'FAILURE', 'FAILED') + else: + print_message(self._testMethodName, 'SUCCESS', 'PASSED') + class USDImportTest(AbstractUSDTest): # Utility function to round each component of a vector to a few digits. The "+ 0" is to @@ -577,6 +593,7 @@ class USDImportTest(AbstractUSDTest): # Validate some simple aspects of the animated objects which prove that they're animating. ob_xform = bpy.data.objects["cube_anim_xform"] + ob_xform_child = bpy.data.objects["cube_anim_child_mesh"] ob_shapekeys = bpy.data.objects["cube_anim_keys"] ob_arm = bpy.data.objects["column_anim_armature"] ob_arm2_side_a = bpy.data.objects["side_a"] @@ -585,7 +602,10 @@ class USDImportTest(AbstractUSDTest): bpy.context.scene.frame_set(1) self.assertEqual(len(ob_xform.constraints), 1) + self.assertEqual(len(ob_xform_child.constraints), 1) self.assertEqual(self.round_vector(ob_xform.matrix_world.translation), [0.0, -2.0, 0.0]) + self.assertEqual(self.round_vector(ob_xform_child.matrix_world.translation), [0.0, -2.0, 1.0]) + self.assertEqual(self.round_vector(ob_xform_child.matrix_world.to_euler('XYZ')), [0.0, 0.0, 0.0]) self.assertEqual(self.round_vector(ob_shapekeys.dimensions), [1.0, 1.0, 1.0]) self.assertEqual(self.round_vector(ob_arm.dimensions), [0.4, 0.4, 3.0]) self.assertEqual(self.round_vector(ob_arm2_side_a.dimensions), [0.5, 0.0, 0.5]) @@ -595,7 +615,10 @@ class USDImportTest(AbstractUSDTest): bpy.context.scene.frame_set(5) self.assertEqual(len(ob_xform.constraints), 1) + self.assertEqual(len(ob_xform_child.constraints), 1) self.assertEqual(self.round_vector(ob_xform.matrix_world.translation), [3.0, -2.0, 0.0]) + self.assertEqual(self.round_vector(ob_xform_child.matrix_world.translation), [3.0, -2.0, 1.0]) + self.assertEqual(self.round_vector(ob_xform_child.matrix_world.to_euler('XYZ')), [0.0, 1.5708, 0.0]) self.assertEqual(self.round_vector(ob_shapekeys.dimensions), [0.1, 0.1, 0.1]) self.assertEqual(self.round_vector(ob_arm.dimensions), [1.65545, 0.4, 2.38953]) self.assertEqual(self.round_vector(ob_arm2_side_a.dimensions), [0.25, 0.0, 0.25]) @@ -1911,7 +1934,7 @@ def main(): parser.add_argument('--testdir', required=True, type=pathlib.Path) args, remaining = parser.parse_known_args(argv) - unittest.main(argv=remaining) + unittest.main(argv=remaining, verbosity=0) if __name__ == "__main__": diff --git a/tests/python/modules/colored_print.py b/tests/python/modules/colored_print.py index 09c1dafae45..bf5b1b09f8d 100644 --- a/tests/python/modules/colored_print.py +++ b/tests/python/modules/colored_print.py @@ -36,9 +36,9 @@ def print_message(message, type=None, status=''): elif status == 'OK': status_text = " OK " elif status == 'PASSED': - status_text = " PASSED " + status_text = " PASSED " elif status == 'FAILED': - status_text = " FAILED " + status_text = " FAILED " else: status_text = status if status_text: