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

@@ -22,7 +22,7 @@ def test_cutout_interfaces_and_thickness_modes(source):
assert len(set(groups.values())) == 3
for group in set(groups.values()):
validate_node_structure(group)
revision = 18 if group == groups["DEPTH_SOLID"] else 11
revision = 23 if group == groups["DEPTH_SOLID"] else 12 if group == groups["DEPTH_BALLOON"] else 11
assert group.is_modifier and group.get("anyimage_asset_revision") == revision
assert not any(node.bl_idname == "GeometryNodeGroup" for node in group.nodes)
inputs = {item.name: item for item in group.interface.items_tree if item.item_type == "SOCKET" and item.in_out == "INPUT"}
@@ -36,21 +36,25 @@ def test_cutout_interfaces_and_thickness_modes(source):
assert inputs["Double Sided"].default_value
if group == groups["DEPTH_SOLID"]:
assert np.isclose(inputs["Split Threshold"].default_value, 0.1)
assert np.isclose(inputs["Edge Round"].default_value, 0.2)
assert inputs["Edge Round"].parent.name == "Options"
assert list(inputs)[list(inputs).index("Front Inflation") - 1] == "Edge Round"
assert inputs["Normal Smooth"].default_value == 50
assert inputs["Front Inflation"].default_value == 1
assert not {"Edge Round", "Normal Smooth"} & inputs.keys()
normal_blurs = [n for n in group.nodes if n.bl_idname == "GeometryNodeBlurAttribute" and n.data_type == "FLOAT_VECTOR"
and not n.inputs["Iterations"].is_linked and n.inputs["Iterations"].default_value == 100]
assert len(normal_blurs) == 2
assert inputs["Front Inflation"].default_value == 0
assert inputs["Front Inflation"].subtype == "FACTOR"
assert (inputs["Front Inflation"].min_value, inputs["Front Inflation"].max_value) == (0, 1)
assert inputs["Front Inflation"].parent.name == "Options"
assert not set(inputs) & {"Edge Round Range", "Back Rim Range", "Normal Influence", "Edge Round Amount", "Back Rim Fullness"}
options = [s.name for s in inputs.values() if s.parent and s.parent.name == "Options"]
expected = ["Cleanup Threshold"]
if group == groups["DEPTH_SOLID"]:
expected.insert(0, "Boundary Smooth")
expected += ["Reference Depth", "Edge Round", "Front Inflation", "Normal Smooth"]
expected += ["Smooth Weight", "Reference Depth", "Boundary Smooth", "Outline Depth Fix", "Front Inflation"]
assert inputs["Outline Depth Fix"].default_value == 16
assert not set(inputs) & {"Ratio Lower", "Ratio Upper", "Weight Blur Iterations", "Weight Update Rounds", "Depth Steps Per Round"}
elif group == groups["DEPTH_BALLOON"]:
expected += ["Reference Depth"]
expected += ["Smooth Weight"]
expected += ["Smooth Weight", "Reference Depth"]
if group not in (groups["DEPTH_SOLID"], groups["DEPTH_BALLOON"]):
expected += ["Smooth Weight"]
if group == groups["DEPTH_BALLOON"]:
expected += ["Depth Direction"]
assert options == expected, (group.name, options)