90 lines
3.2 KiB
Python
90 lines
3.2 KiB
Python
import sys
|
|
import types
|
|
|
|
import numpy as np
|
|
import trimesh
|
|
from PIL import Image
|
|
|
|
|
|
def _export_textured_glb(path):
|
|
mesh = trimesh.creation.box()
|
|
img = Image.new("RGB", (8, 8), (10, 20, 30))
|
|
uv = np.zeros((len(mesh.vertices), 2), dtype=np.float64)
|
|
mesh.visual = trimesh.visual.TextureVisuals(uv=uv, image=img)
|
|
trimesh.Scene(mesh).export(str(path), file_type="glb")
|
|
|
|
|
|
def test_loadglb_node_end_to_end(tmp_path, monkeypatch):
|
|
input_dir = tmp_path / "input"
|
|
(input_dir / "3d").mkdir(parents=True)
|
|
glb = input_dir / "3d" / "shoe.glb"
|
|
_export_textured_glb(glb)
|
|
|
|
fake = types.ModuleType("folder_paths")
|
|
fake.get_input_directory = lambda: str(input_dir)
|
|
fake.get_annotated_filepath = lambda rel: str(input_dir / rel)
|
|
monkeypatch.setitem(sys.modules, "folder_paths", fake)
|
|
|
|
# Evict any previously cached import so the stub is picked up at import time.
|
|
monkeypatch.delitem(sys.modules, "cxn.load_glb", raising=False)
|
|
|
|
from cxn.load_glb import LoadGLB
|
|
from cxn.types import Model3D
|
|
|
|
(model,) = LoadGLB().load(model_file="3d/shoe.glb", toe_axis="+X", up_axis="+Z")
|
|
|
|
assert isinstance(model, Model3D)
|
|
assert len(model.scene.geometry) >= 1
|
|
assert model.source_path.endswith("shoe.glb")
|
|
assert len(model.textures) >= 1
|
|
assert all(isinstance(t, Image.Image) for t in model.textures)
|
|
|
|
|
|
def test_loadglb_node_sentinel_raises(tmp_path, monkeypatch):
|
|
import pytest
|
|
|
|
input_dir = tmp_path / "input"
|
|
(input_dir / "3d").mkdir(parents=True)
|
|
fake = types.ModuleType("folder_paths")
|
|
fake.get_input_directory = lambda: str(input_dir)
|
|
fake.get_annotated_filepath = lambda rel: str(input_dir / rel)
|
|
monkeypatch.setitem(sys.modules, "folder_paths", fake)
|
|
|
|
# Evict any previously cached import so the stub is picked up at import time.
|
|
monkeypatch.delitem(sys.modules, "cxn.load_glb", raising=False)
|
|
|
|
from cxn.load_glb import LoadGLB, _NO_FILES_SENTINEL
|
|
|
|
with pytest.raises(RuntimeError, match="No .glb"):
|
|
LoadGLB().load(model_file=_NO_FILES_SENTINEL)
|
|
|
|
|
|
def test_loadglb_node_applies_axis_remap(tmp_path, monkeypatch):
|
|
input_dir = tmp_path / "input"
|
|
(input_dir / "3d").mkdir(parents=True)
|
|
glb = input_dir / "3d" / "shoe.glb"
|
|
_export_textured_glb(glb)
|
|
|
|
fake = types.ModuleType("folder_paths")
|
|
fake.get_input_directory = lambda: str(input_dir)
|
|
fake.get_annotated_filepath = lambda rel: str(input_dir / rel)
|
|
monkeypatch.setitem(sys.modules, "folder_paths", fake)
|
|
monkeypatch.delitem(sys.modules, "cxn.load_glb", raising=False)
|
|
|
|
from cxn.glb_loader import load_glb_as_scene
|
|
from cxn.load_glb import LoadGLB
|
|
from cxn.loader_common import apply_axis_remap, build_axis_remap
|
|
|
|
# Vertices as the node will load them (pre-remap), for the same file.
|
|
raw_scene = load_glb_as_scene(str(glb))
|
|
raw_geom = list(raw_scene.geometry.values())[0]
|
|
expected = (
|
|
np.asarray(raw_geom.vertices, dtype=np.float64)
|
|
@ build_axis_remap("+Y", "+Z").T
|
|
)
|
|
|
|
(model,) = LoadGLB().load(model_file="3d/shoe.glb", toe_axis="+Y", up_axis="+Z")
|
|
out_geom = list(model.scene.geometry.values())[0]
|
|
|
|
assert np.allclose(np.asarray(out_geom.vertices, dtype=np.float64), expected)
|