feat(node_assets): add image plane geometry nodes and validation scripts

- Implemented `image_plane.py` to build the Image Plane Geometry Nodes group with customizable parameters for geometry, subdivide, and thickness.
- Created `image_plane_validation.py` to validate the functionality of the image plane, ensuring correct geometry generation and material assignment.
- Developed `material_layers.py` to construct shader node groups for image materials, including depth and normal handling.
- Authored `plane_layouts.py` to define node arrangements for image geometry assets.
- Introduced `shadeless.py` to create a shadeless shader node group that displays color without scene lighting while preserving shadows and reflections.
This commit is contained in:
2026-09-08 23:24:27 +08:00
parent 196b964efc
commit 4c902ed7db
155 changed files with 9700 additions and 10393 deletions

View File

@@ -2,7 +2,6 @@ import sys
from pathlib import Path
from types import SimpleNamespace
from unittest.mock import patch
import numpy as np
import pytest
from PIL import Image
@@ -160,21 +159,18 @@ def test_alpha_resize_retains_threshold_values(tmp_path):
@pytest.mark.parametrize(
"depth_mode,normal_mode,correct",
"generate_depth,normal_mode,correct",
[
("VECTOR", "OBJECT", True),
("VECTOR", "TANGENT", True),
("Z", "TANGENT", True),
("Z", "TANGENT", False),
("NONE", "OBJECT", True),
(True, "OBJECT", True),
(True, "TANGENT", True),
(True, "TANGENT", False),
(False, "OBJECT", True),
],
)
def test_artifacts_use_corrected_depth_and_original_normals(
tmp_path, depth_mode, normal_mode, correct
tmp_path, generate_depth, normal_mode, correct
):
frame, alpha = silhouette()
if depth_mode == "Z":
frame.points = None
rgba = np.full((*alpha.shape, 4), 255, np.uint8)
rgba[..., 3] = np.round(alpha * 255).astype(np.uint8)
path = tmp_path / "source.png"
@@ -188,12 +184,9 @@ def test_artifacts_use_corrected_depth_and_original_normals(
with (
patch.object(artifacts.moge2, "infer", return_value=[frame]),
patch.object(
artifacts, "write_vector_depth_texture",
return_value=tmp_path / "vector.exr",
) as vector,
patch.object(
artifacts, "write_z_depth_texture", return_value=tmp_path / "z.exr"
) as z,
artifacts, "write_depth_texture",
return_value=tmp_path / "depth.exr",
) as depth,
patch.object(
artifacts, "write_depth_metadata", return_value=tmp_path / "depth.json"
) as metadata,
@@ -203,13 +196,13 @@ def test_artifacts_use_corrected_depth_and_original_normals(
patch.object(artifacts, "extend_edge_depth", wraps=extend_edge_depth) as repair,
):
artifacts.generate_moge2_artifacts(
context, {}, path, depth_mode=depth_mode, normal_mode=normal_mode,
context, {}, path, generate_depth=generate_depth, normal_mode=normal_mode,
correct_edge_depth=correct,
)
assert normal.call_args.args[0] is frame
assert repair.call_count == int(correct and depth_mode != "NONE")
if depth_mode != "NONE":
written_frame = (vector if depth_mode == "VECTOR" else z).call_args.args[0]
assert repair.call_count == int(correct and generate_depth)
if generate_depth:
written_frame = depth.call_args.args[0]
assert metadata.call_args.args[0] is written_frame
if correct:
assert written_frame.depth[12, 24] == 2
@@ -217,5 +210,4 @@ def test_artifacts_use_corrected_depth_and_original_normals(
assert written_frame is frame
else:
metadata.assert_not_called()
vector.assert_not_called()
z.assert_not_called()
depth.assert_not_called()