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

@@ -37,7 +37,7 @@ def test_boundary_triangle_cleanup_is_one_pass():
assert all(len(f) == 3 for f in faces)
@pytest.mark.parametrize("iterations", [0, 5, 12, 20])
@pytest.mark.parametrize("iterations", [0, 20])
def test_cleaned_sawtooth_smoothing_preserves_face_orientation(iterations):
obj, set_value = diagonal_surface(triangles=True)
original, faces = evaluated(obj)
@@ -50,8 +50,7 @@ def test_cleaned_sawtooth_smoothing_preserves_face_orientation(iterations):
assert np.all(np.sum(normals(original)*normals(points), axis=1) > 0)
@pytest.mark.parametrize("resolution", [12, 24])
@pytest.mark.parametrize("aspect", [.5, 2])
@pytest.mark.parametrize("resolution,aspect", [(12, .5), (24, 2)])
def test_split_profile_tapers_within_boundary_band(resolution, aspect):
obj, set_value = surface(step=6, resolution=resolution)
for vertex in obj.data.vertices:
@@ -65,7 +64,7 @@ def test_split_profile_tapers_within_boundary_band(resolution, aspect):
"value", np.full(len(obj.data.vertices), .3, dtype=np.float32))
set_value("Depth Scale", 0)
np.testing.assert_allclose(profile_values(obj), .3)
set_value("Split Threshold", .1)
set_value("Depth Split", .1)
points, faces = evaluated(obj)
boundary = boundary_neighbors(faces)
cut = [i for i in boundary if 0 < points[i,1] < 1 and .5*aspect < points[i,0] < 1.5*aspect]
@@ -78,7 +77,7 @@ def test_split_profile_tapers_within_boundary_band(resolution, aspect):
np.testing.assert_allclose(values[outside], .3)
assert np.isfinite(values).all()
assert values.max() == pytest.approx(.3)
set_value("Split Threshold", 0)
set_value("Depth Split", 0)
np.testing.assert_allclose(profile_values(obj), .3)
@@ -87,13 +86,13 @@ def test_split_profile_tapers_within_boundary_band(resolution, aspect):
def test_normal_blend_converges_to_raw_and_reaches_full_smoothing(mode, reference):
obj, set_value = surface(resolution=2)
group = obj.modifiers[0].node_group
# The production interface renames the uniform socket after building.
# The production interface renames the Shell thickness socket after building.
socket = next(s for s in group.interface.items_tree if s.item_type == "SOCKET" and s.in_out == "INPUT"
and s.name == "Thickness" and s.subtype == "DISTANCE")
socket.name = "Uniform Thickness"
uniform = group.nodes.new("FunctionNodeInputBool")
uniform.boolean = bool(mode)
weight = build_normal_weight(group, uniform.outputs[0])
socket.name = "Shell Thickness"
is_shell = group.nodes.new("FunctionNodeInputBool")
is_shell.boolean = bool(mode)
weight = build_normal_weight(group, is_shell.outputs[0])
raw = group.nodes.new("ShaderNodeCombineXYZ")
raw.inputs["Z"].default_value = 1
blurred = group.nodes.new("ShaderNodeCombineXYZ")