Add new tests and functionality for image processing and geometry handling

- Introduced color_image.py for preparing standalone color images for tests.
- Added hdr_image.py to create HDR textures for testing.
- Implemented test_image_depth_panorama.py to evaluate panorama topology, UVs, and depth discontinuities.
- Created test_shadeless.py to validate the opacity and HDR color endpoints of the Shadeless group.
- Developed moge3_export.py for exporting dynamic MoGe-3 backbone and ONNX graphs.
- Added material.py to inherit material slots onto generated geometry.
- Built image_depth_panorama.py to construct a quad panorama with depth separation and sampling.
This commit is contained in:
2026-09-10 14:42:17 +08:00
parent 27ca25224a
commit 489003c2cc
136 changed files with 5758 additions and 1083 deletions

View File

@@ -197,7 +197,7 @@ def test_surface_interface_and_node_structure(surface):
assert inputs["Split Threshold"].subtype == "FACTOR"
assert inputs["Split Threshold"].parent == inputs["Smooth"].parent
assert inputs["Split Threshold"].parent.name != "Options"
assert inputs["Validity Threshold"].default_value == pytest.approx(0.9)
assert inputs["Validity Threshold"].default_value == pytest.approx(0.1)
assert inputs["Validity Threshold"].parent.name == "Options"
assert inputs["Validity Threshold"].subtype == "FACTOR"
assert inputs["Valid Only"].default_value is True
@@ -234,7 +234,7 @@ def test_relief_interface_and_node_structure(relief):
@pytest.mark.parametrize("threshold", [0.0, 0.4, 0.9, 1.0])
@pytest.mark.parametrize("pattern", ["valid", "invalid", "partial", "half", "stripe"])
def test_valid_only_recomputes_per_point_and_preserves_boundary_faces(surface, pattern, threshold):
def test_valid_only_samples_face_centers(surface, pattern, threshold):
obj, set_value, _, inputs, _ = surface
set_value("Validity Threshold", threshold)
depth_image = obj.modifiers[0][inputs["Depth Image"].identifier]
@@ -256,17 +256,15 @@ def test_valid_only_recomputes_per_point_and_preserves_boundary_faces(surface, p
set_value("Subdivide", subdivisions)
set_value("Valid Only", False)
base = evaluated(obj)
u = (base[0][:, 0] + 2) / 4
u = np.array([(base[0][list(face), 0].mean() + 2) / 4 for face in base[1]])
sampled = np.interp(u * 16 - 0.5, np.arange(16), alpha)
expected = [face for face in base[1] if any(sampled[index] >= threshold for index in face)]
expected = [face for face, alpha_value in zip(base[1], sampled) if alpha_value >= threshold]
set_value("Valid Only", True)
culled = evaluated(obj)
assert len(culled[1]) == len(expected)
expected_points = {tuple(base[0][index]) for face in expected for index in face}
assert {tuple(point) for point in culled[0]} == expected_points
assert np.isfinite(culled[2]).all()
if pattern == "half" and subdivisions >= 2 and threshold == 1.0:
assert 0 <= min(point[0] for point in culled[0]) < 0.125
set_value("Valid Only", False)
np.testing.assert_allclose(evaluated(obj)[0], base[0])
@@ -293,9 +291,7 @@ def test_validity_graph_matches_reference_domains_and_connections(surface):
group = obj.modifiers[0].node_group
delete = next(node for node in group.nodes if node.bl_idname == "GeometryNodeDeleteGeometry")
assert (delete.domain, delete.mode) == ("FACE", "ALL")
points = origin_socket(delete.inputs["Selection"].links[0].from_socket).node
assert (points.bl_idname, points.data_type, points.domain) == ("GeometryNodeFieldOnDomain", "BOOLEAN", "POINT")
compare = origin_socket(points.inputs["Value"].links[0].from_socket).node
compare = origin_socket(delete.inputs["Selection"].links[0].from_socket).node
assert (compare.bl_idname, compare.data_type, compare.operation) == ("FunctionNodeCompare", "FLOAT", "LESS_THAN")
assert origin_socket(compare.inputs["B"].links[0].from_socket).name == "Validity Threshold"
alpha = origin_socket(compare.inputs["A"].links[0].from_socket)