Add cutout shell and volume node assets for depth volume processing
- Implemented `cutout_shell.py` to build front normals and shell positions for balloon geometry. - Created `cutout_volume.py` to establish smooth center fields and manage balloon surface attributes. - Introduced `pisa_sr_export.py` for exporting PiSA-SR components with dependencies and asset finalization.
This commit is contained in:
53
tools/node_assets/cutout_layout.py
Normal file
53
tools/node_assets/cutout_layout.py
Normal file
@@ -0,0 +1,53 @@
|
||||
"""Place independent Cutout stages using authored local layouts."""
|
||||
from collections import Counter
|
||||
|
||||
|
||||
def route_geometry(group, source, positions):
|
||||
"""Guide a shared forward geometry reference through authored waypoints."""
|
||||
for position in positions:
|
||||
reroute = group.nodes.new("NodeReroute")
|
||||
reroute.location = position
|
||||
group.links.new(source, reroute.inputs[0])
|
||||
source = reroute.outputs[0]
|
||||
return source
|
||||
|
||||
|
||||
def layout_stage(group, previous, positions, input_regions, offset=(0, 0)):
|
||||
"""Map stage-local default names without renaming Blender nodes."""
|
||||
counts, stage = Counter(), {}
|
||||
for node in group.nodes:
|
||||
if node in previous or node.bl_idname == "NodeGroupInput":
|
||||
continue
|
||||
base, dot, suffix = node.name.rpartition(".")
|
||||
base = base if dot and suffix.isdigit() else node.name
|
||||
index = counts[base]
|
||||
counts[base] += 1
|
||||
stage[base if index == 0 else f"{base}.{index:03d}"] = node
|
||||
assert set(stage) == set(positions) - {"Set Shade Smooth", "Group Output"}, (group.name, set(stage) ^ set(positions))
|
||||
for name, node in stage.items():
|
||||
x, y = positions[name]
|
||||
node.location = (x + offset[0], y + offset[1])
|
||||
inputs = [(link.to_socket, link.from_socket.name) for link in group.links if link.to_node in stage.values() and link.from_node.bl_idname == "NodeGroupInput"]
|
||||
for targets, (x, y) in input_regions:
|
||||
sockets = [(socket, name) for socket, name in inputs if socket.node in [stage[key] for key in targets if key in stage]]
|
||||
if not sockets:
|
||||
continue
|
||||
control = group.nodes.new("NodeGroupInput")
|
||||
control.location = (x + offset[0], y + offset[1])
|
||||
for socket, name in sockets:
|
||||
group.links.new(control.outputs[name], socket)
|
||||
return stage
|
||||
|
||||
|
||||
def finish_layout(group):
|
||||
"""Expose linked fields and retain readable constants."""
|
||||
for node in group.nodes:
|
||||
node.select = False
|
||||
node.width = 200 if "Attribute" in node.bl_idname else 160
|
||||
if node.bl_idname in {"ShaderNodeMath", "ShaderNodeVectorMath"}:
|
||||
node.hide = all(socket.is_linked for socket in node.inputs if socket.enabled and not socket.hide)
|
||||
for socket in node.outputs:
|
||||
socket.hide = not socket.is_linked
|
||||
for node in list(group.nodes):
|
||||
if node.bl_idname == "NodeGroupInput" and not any(socket.is_linked for socket in node.outputs):
|
||||
group.nodes.remove(node)
|
||||
Reference in New Issue
Block a user