- Introduced tests for boundary smoothing in `test_boundary_smoothing.py`, verifying that smoothing reduces stair-step artifacts while preserving boundary integrity. - Added tests for cutout boundary behavior in `test_cutout_boundary.py`, ensuring proper handling of boundary triangles and normal blending. - Created `test_temporary_attributes.py` to check the cleanup of temporary attributes across depth modifier branches, ensuring no warnings are raised. - Implemented point culling functionality in `test_validity.py`, confirming that invalid points are removed without affecting adjacent geometry. - Developed boundary smoothing logic in `boundary_smoothing.py`, allowing for depth smoothing while maintaining edge integrity. - Added cutout boundary management in `cutout_boundary.py`, including functions for removing boundary triangles and tapering thickness profiles. - Implemented validity checks in `validity.py` to ensure proper deletion of invalid vertices and associated wire edges.
72 lines
3.3 KiB
Python
72 lines
3.3 KiB
Python
"""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", asset_revision=14)
|
|
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
|