Files
AnyImage/tools/node_assets/cutout_volume.py
nan 196b964efc 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.
2026-09-08 17:18:03 +08:00

89 lines
4.4 KiB
Python

"""Build the smooth center field for depth volume."""
from node_graph import edge_boundary_field
def node(group, kind, location):
result = group.nodes.new(kind)
result.location = location
return result
def shift_stage(group, previous, offset):
for item in group.nodes:
if item not in previous:
item.location.x += offset[0]
item.location.y += offset[1]
def build_volume_fields(group, geometry, offset=(0, 0)):
previous = set(group.nodes)
boundary = edge_boundary_field(group.nodes, group.links, (0, -400))
store = node(group, "GeometryNodeStoreNamedAttribute", (860, 0))
store.domain, store.data_type = "POINT", "FLOAT"
store.inputs["Name"].default_value = "o_balloon_surface_rim"
group.links.new(geometry, store.inputs["Geometry"])
group.links.new(boundary, store.inputs["Value"])
profile = node(group, "GeometryNodeInputNamedAttribute", (860, 700))
profile.data_type = "FLOAT"
profile.inputs["Name"].default_value = "o_balloon"
links = group.links
def math(operation, a, b, location):
result = node(group, "ShaderNodeMath", location)
result.operation = operation
for index, value in enumerate((a, b)):
if isinstance(value, (int, float)):
result.inputs[index].default_value = value
else:
links.new(value, result.inputs[index])
return result.outputs[0]
position = node(group, "GeometryNodeInputPosition", (860, 1100))
axes = node(group, "ShaderNodeSeparateXYZ", (1100, 1100))
links.new(position.outputs[0], axes.inputs[0])
seed = math("SUBTRACT", axes.outputs["Z"], profile.outputs["Attribute"], (1340, 900))
center = node(group, "GeometryNodeStoreNamedAttribute", (1340, 0))
center.domain, center.data_type = "POINT", "FLOAT"
center.inputs["Name"].default_value = "o_balloon_surface_center"
links.new(store.outputs["Geometry"], center.inputs["Geometry"])
links.new(seed, center.inputs["Value"])
current = node(group, "GeometryNodeInputNamedAttribute", (1660, -330))
current.data_type = "FLOAT"
current.inputs["Name"].default_value = "o_balloon_surface_center"
rim = node(group, "GeometryNodeInputNamedAttribute", (1660, -660))
rim.data_type = "FLOAT"
rim.inputs["Name"].default_value = "o_balloon_surface_rim"
interior = math("SUBTRACT", 1, rim.outputs["Attribute"], (1890, -660))
blur = node(group, "GeometryNodeBlurAttribute", (2120, -330))
blur.data_type = "FLOAT"
blur.inputs["Iterations"].default_value = 256
links.new(current.outputs["Attribute"], blur.inputs["Value"])
links.new(interior, blur.inputs["Weight"])
update = node(group, "GeometryNodeStoreNamedAttribute", (2370, 0))
update.domain, update.data_type = "POINT", "FLOAT"
update.inputs["Name"].default_value = "o_balloon_surface_center"
links.new(center.outputs["Geometry"], update.inputs["Geometry"])
links.new(blur.outputs[0], update.inputs["Value"])
baseline = node(group, "GeometryNodeInputNamedAttribute", (2940, 1000))
baseline.data_type = "FLOAT"
baseline.inputs["Name"].default_value = "o_balloon_surface_center"
profile_end = node(group, "GeometryNodeInputNamedAttribute", (2940, 700))
profile_end.data_type = "FLOAT"
profile_end.inputs["Name"].default_value = "o_balloon"
position_end = node(group, "GeometryNodeInputPosition", (2940, 1360))
axes_end = node(group, "ShaderNodeSeparateXYZ", (3180, 1360))
links.new(position_end.outputs[0], axes_end.inputs[0])
residual = math("SUBTRACT", axes_end.outputs["Z"], baseline.outputs["Attribute"], (3420, 1000))
full = math("ADD", residual, profile_end.outputs["Attribute"], (3660, 1000))
minimum = math("MULTIPLY", profile_end.outputs["Attribute"], 0.05, (3420, 700))
positive = math("MAXIMUM", full, minimum, (3900, 1000))
control = node(group, "NodeGroupInput", (3900, 700))
scaled = math("MULTIPLY", positive, control.outputs["Thickness"], (4140, 1000))
thickness = node(group, "GeometryNodeStoreNamedAttribute", (4140, 0))
thickness.domain, thickness.data_type = "POINT", "FLOAT"
thickness.inputs["Name"].default_value = "o_balloon_surface_thickness"
group.links.new(update.outputs["Geometry"], thickness.inputs["Geometry"])
group.links.new(scaled, thickness.inputs["Value"])
shift_stage(group, previous, offset)
return thickness.outputs["Geometry"]