Add new functionality for image rectification and depth metadata handling

- Implemented a preview tool for rectifying images with interactive aspect controls in `preview.py`.
- Added tests for depth metadata loading to ensure consistent schema usage in `test_depth_metadata.py`.
- Developed comprehensive tests for cutout calibration processes in `test_cutout_calibration.py`, including stability checks and depth calibration.
- Created tests for frame compositing operations in `test_frame_compositing.py`, ensuring correct handling of depth and transparency.
- Introduced material slot inheritance functionality in `material_slots.py` to manage geometry material assignments.
- Built shared shader nodes for material processing in `shader.py`, including roughness and bump mapping setups.
This commit is contained in:
2026-09-12 19:20:06 +08:00
parent e8268504c2
commit 938d95db0f
175 changed files with 3812 additions and 6864 deletions

View File

@@ -46,7 +46,7 @@ class MaskToolTest(BlenderTestCase):
def test_mask_freezes_scene_settings_on_invoke(self):
settings = SimpleNamespace(
mask_gesture="BRUSH",
mask_mode="ADD",
mask_mode="EXTEND",
mask_radius=64,
)
context = SimpleNamespace(scene=SimpleNamespace(anyimage_settings=settings))
@@ -55,52 +55,22 @@ class MaskToolTest(BlenderTestCase):
self.edit_mask.EditImageAlpha._read_gesture_settings(operator, context)
self.assertEqual(operator.gesture, "BRUSH")
self.assertEqual(operator.mode, "ADD")
self.assertEqual(operator.mode, "EXTEND")
self.assertEqual(operator.radius, 64)
def test_mask_has_no_letter_option_shortcut(self):
operator = SimpleNamespace(
gesture="LASSO",
mode="SUBTRACT",
radius=25,
active_tool_id="anyimage.mask",
)
context = SimpleNamespace(
workspace=SimpleNamespace(status_text_set=Mock())
)
event = SimpleNamespace(type="F", value="PRESS")
with patch.object(
self.image_interaction,
"active_view3d_tool_id",
return_value=None,
):
result = self.image_interaction.ImageGesture.modal(
operator,
context,
event,
)
self.edit_mask.EditImageAlpha._set_status(operator, context)
self.assertEqual(result, {"PASS_THROUGH"})
status = context.workspace.status_text_set.call_args.args[0]
self.assertIn("Subtract", status)
self.assertNotIn("F", status)
def test_mask_polyline_status_explains_point_controls(self):
context = SimpleNamespace(
workspace=SimpleNamespace(status_text_set=Mock())
)
operator = SimpleNamespace(gesture="POLYLINE", mode="ADD", radius=25)
operator = SimpleNamespace(gesture="POLYLINE", mode="EXTEND", radius=25)
self.edit_mask.EditImageAlpha._set_status(operator, context)
status = context.workspace.status_text_set.call_args.args[0]
self.assertIn("click start, double-click, or Enter", status)
self.assertIn("Backspace removes", status)
self.assertIn("Add", status)
self.assertIn("Extend", status)
def test_mask_and_rectify_start_after_an_empty_pick(self):
@@ -147,8 +117,8 @@ class MaskToolTest(BlenderTestCase):
),
patch.object(
self.image_interaction,
"video_total_frames",
return_value=1,
"is_animated_image",
return_value=False,
),
patch.object(
self.image_interaction,
@@ -169,8 +139,8 @@ class MaskToolTest(BlenderTestCase):
),
patch.object(
self.rectify,
"video_total_frames",
return_value=1,
"is_animated_image",
return_value=False,
),
patch.object(
self.rectify,
@@ -325,7 +295,7 @@ class MaskToolTest(BlenderTestCase):
full_mask = mask.full_values((3, 2))
expected_alpha = {
"SET": source[:, :, 3] * full_mask,
"ADD": np.maximum(source[:, :, 3], full_mask),
"EXTEND": np.maximum(source[:, :, 3], full_mask),
"SUBTRACT": source[:, :, 3] * (1.0 - full_mask),
}
@@ -349,7 +319,7 @@ class MaskToolTest(BlenderTestCase):
transparent = np.flipud(removed.reshape(source.shape))
self.assertFalse(np.any(transparent[:, :, 3]))
added = self.edit_mask.apply_alpha_mask(transparent, mask, "ADD")
added = self.edit_mask.apply_alpha_mask(transparent, mask, "EXTEND")
restored = np.flipud(added.reshape(source.shape))
np.testing.assert_array_equal(restored[:, :, 3], 1.0)
@@ -1014,7 +984,7 @@ class MaskToolTest(BlenderTestCase):
def test_mask_brush_overlay_matches_lasso_fill_and_outline(self):
for mode, color in (
("SUBTRACT", (1.0, 0.25, 0.2, 0.16)),
("ADD", (1.0, 1.0, 1.0, 0.16)),
("EXTEND", (1.0, 1.0, 1.0, 0.16)),
):
cache = Mock()
operator = SimpleNamespace(