Implement arrangement framework for node groups

- Introduced `frames.py` to manage field complex calculations and their arrangement within node groups.
- Added functionality to create and remove field frames based on node arrangements.
- Developed `passages.py` to find unobstructed paths for connections around calculation frames.
- Implemented `references.py` to route shared results on peripheral tracks, ensuring efficient distribution of outputs.
- Created `sections.py` to reserve space for field calculations adjacent to geometry consumers.
- Added `sources.py` to position shared calculation sources effectively beside their distribution channels.
- Enhanced outline smoothing with `outline_smoothing.py` to adapt camera depth along original outlines.
This commit is contained in:
2026-09-12 12:19:07 +08:00
parent dd32ccdc44
commit 5b2dc59f79
57 changed files with 2253 additions and 700 deletions

View File

@@ -70,7 +70,7 @@ def artifacts(tmp_path, source):
rgba = np.ones((16, 32, 4), np.float32)
rgba[..., :3] = 3
write_float_exr(rgba, tmp_path / "depth.exr")
(tmp_path / "depth.json").write_text(json.dumps({"projection": "equirectangular", "image_size": [32, 16], "reference_distance": 3}))
(tmp_path / "depth.json").write_text(json.dumps({"projection": "equirectangular", "image_size": [32, 16]}))
result = SimpleNamespace(directory=tmp_path, file=lambda key: tmp_path / {"depth": "depth.exr", "depth_metadata": "depth.json"}[key])
operator = SimpleNamespace(source_object_name=source.name, source_identity=str(source.as_pointer()),
image_identity=str(source.data.as_pointer()), mesh_detail=2,
@@ -90,7 +90,7 @@ def test_result_replaces_source_with_zero_rotation_and_shadeless_material(source
monkeypatch.setattr(conversion, "bpy", SimpleNamespace(data=bpy.data, ops=SimpleNamespace(ed=SimpleNamespace(undo_push=undo))))
obj = conversion.create_panorama_from_result(bpy.context, result, operator)
assert obj.modifiers[0].node_group != saved
assert obj.modifiers[0].node_group["anyimage_asset_revision"] == 14
assert obj.modifiers[0].node_group["anyimage_asset_revision"] == 15
assert saved in bpy.data.node_groups.values() and saved["anyimage_asset_revision"] == 11
assert obj.name == operator.source_object_name and obj.type == "MESH"
np.testing.assert_allclose(obj.location, matrix.translation, atol=1e-6)
@@ -162,7 +162,7 @@ def test_failed_response_keeps_source_and_cleans_owned_data(source, artifacts, m
elif failure == "replaced_image":
operator.image_identity = "replaced"
else:
(result.directory / "depth.json").write_text(json.dumps({"projection": "equirectangular", "image_size": [16, 8], "reference_distance": 3}))
(result.directory / "depth.json").write_text(json.dumps({"projection": "equirectangular", "image_size": [16, 8]}))
with pytest.raises((RuntimeError, ValueError)):
conversion.create_panorama_from_result(bpy.context, result, operator)
for name, values in before.items():