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

@@ -0,0 +1,71 @@
"""Apply packed panorama artifacts around the source Empty's camera origin."""
import json
import math
from pathlib import Path
import bpy
from ...common.depth import load_depth_result_image
from ...common.image import require_conversion_source
from ...common.color_image import material_color_image
from ...common.material import create_image_material
from ...common.node import load_node_group
from ...common.object import finalize_object_result, modifier_input_identifier, set_modifier_input
def load_panorama_metadata(path):
metadata = json.loads(Path(path).read_text(encoding="utf-8"))
try:
size = tuple(int(value) for value in metadata["image_size"])
distance = float(metadata["reference_distance"])
valid = (metadata["projection"] == "equirectangular" and len(size) == 2
and size[1] > 0 and size[0] == 2 * size[1]
and math.isfinite(distance) and distance > 0)
except (KeyError, TypeError, ValueError) as error:
raise ValueError("Panorama metadata is invalid") from error
if not valid:
raise ValueError("Panorama metadata is invalid")
return {"image_size": size, "reference_distance": distance}
def create_panorama_from_result(context, result, operator):
source = require_conversion_source(operator)
depth = material = mesh = obj = None
try:
with material_color_image(input_path=operator.color_path) as color:
metadata = load_panorama_metadata(result.file("depth_metadata"))
group = load_node_group("O Image Depth Panorama")
depth = load_depth_result_image(result.file("depth"), source, metadata)
material = create_image_material(source.data, color, shadeless=True, scene=context.scene,
texture_extension="REPEAT")
mesh = bpy.data.meshes.new(source.name)
mesh.from_pydata([(0, 0, 0)], [], [])
mesh.materials.append(material)
obj = bpy.data.objects.new(source.name, mesh)
context.collection.objects.link(obj)
obj.location = source.matrix_world.translation
obj.scale = source.matrix_world.to_scale()
obj["anyimage_mesh_shape"] = "PANORAMA"
modifier = obj.modifiers.new(group.name, "NODES")
modifier.node_group = group
modifier.show_group_selector = False
for name, value in (
("Subdivide", operator.mesh_detail), ("Depth Image", depth),
("Reference Distance", metadata["reference_distance"]),
):
set_modifier_input(modifier, modifier_input_identifier(group, name), value)
finalize_object_result(context, source, obj)
except Exception:
if obj is not None:
bpy.data.objects.remove(obj, do_unlink=True)
if mesh is not None and mesh.users == 0:
bpy.data.meshes.remove(mesh)
if material is not None and material.users == 0:
bpy.data.materials.remove(material, do_unlink=True)
if depth is not None and depth.users == 0:
bpy.data.images.remove(depth, do_unlink=True)
raise
if "FINISHED" not in bpy.ops.ed.undo_push(message="Convert to Panorama"):
raise RuntimeError("Unable to create the Convert to Panorama Undo step")
return obj