- 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.
102 lines
5.1 KiB
Python
102 lines
5.1 KiB
Python
"""Round depth volume around the smoothed center-surface normals."""
|
|
from cutout_volume import node, shift_stage
|
|
|
|
|
|
def build_volume_rounding(group, volume, offset):
|
|
previous = set(group.nodes)
|
|
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]
|
|
|
|
def read(name, location, kind="FLOAT"):
|
|
result = node(group, "GeometryNodeInputNamedAttribute", location)
|
|
result.data_type = kind
|
|
result.inputs["Name"].default_value = "o_balloon_surface_" + name
|
|
return result.outputs["Attribute"]
|
|
|
|
def store(geometry, name, value, location, kind="FLOAT"):
|
|
result = node(group, "GeometryNodeStoreNamedAttribute", location)
|
|
result.data_type, result.domain = kind, "POINT"
|
|
result.inputs["Name"].default_value = "o_balloon_surface_" + name
|
|
links.new(geometry, result.inputs["Geometry"])
|
|
links.new(value, result.inputs["Value"])
|
|
return result.outputs["Geometry"]
|
|
|
|
control = node(group, "NodeGroupInput", (0, 1250))
|
|
profile = node(group, "GeometryNodeInputNamedAttribute", (0, 850))
|
|
profile.data_type = "FLOAT"
|
|
profile.inputs["Name"].default_value = "o_balloon"
|
|
balloon = profile.outputs["Attribute"]
|
|
maximum = node(group, "GeometryNodeAttributeStatistic", (240, 850))
|
|
maximum.data_type, maximum.domain = "FLOAT", "POINT"
|
|
links.new(volume, maximum.inputs["Geometry"])
|
|
links.new(balloon, maximum.inputs["Attribute"])
|
|
limit = math("MAXIMUM", maximum.outputs["Max"], 1e-8, (480, 850))
|
|
falloff = node(group, "ShaderNodeMapRange", (720, 850))
|
|
falloff.interpolation_type = "SMOOTHERSTEP"
|
|
falloff.inputs["To Min"].default_value = 1
|
|
falloff.inputs["To Max"].default_value = 0
|
|
links.new(balloon, falloff.inputs["Value"])
|
|
links.new(limit, falloff.inputs["From Max"])
|
|
weight = math("MULTIPLY", falloff.outputs[0], control.outputs["Edge Round"], (960, 850))
|
|
center = read("center", (0, 1900))
|
|
position = node(group, "GeometryNodeInputPosition", (0, 2250))
|
|
axes = node(group, "ShaderNodeSeparateXYZ", (240, 2250))
|
|
links.new(position.outputs[0], axes.inputs[0])
|
|
target = math("ADD", center, balloon, (480, 1900))
|
|
delta = math("SUBTRACT", target, axes.outputs["Z"], (720, 1900))
|
|
delta = math("MULTIPLY", delta, weight, (960, 1900))
|
|
enabled = math("MINIMUM", control.outputs["Thickness"], 1, (480, 1300))
|
|
enabled = math("MAXIMUM", enabled, 0, (720, 1300))
|
|
delta = math("MULTIPLY", delta, enabled, (1200, 1900))
|
|
carrier = store(volume, "edge_weight", weight, (1200, 0))
|
|
carrier = store(carrier, "front_delta", delta, (1440, 0))
|
|
rear = math("MULTIPLY", balloon, weight, (1200, 850))
|
|
rear = math("MULTIPLY", rear, control.outputs["Thickness"], (1440, 850))
|
|
thickness = read("thickness", (1440, 1250))
|
|
total = math("ADD", thickness, delta, (1680, 1250))
|
|
total = math("ADD", total, rear, (1920, 1250))
|
|
carrier = store(carrier, "thickness", total, (1920, 0))
|
|
|
|
# Evaluate normals on a separate center surface with identical point indices.
|
|
center_position = node(group, "ShaderNodeCombineXYZ", (480, -550))
|
|
for axis in ("X", "Y"):
|
|
links.new(axes.outputs[axis], center_position.inputs[axis])
|
|
links.new(center, center_position.inputs["Z"])
|
|
surface = node(group, "GeometryNodeSetPosition", (720, -550))
|
|
links.new(volume, surface.inputs["Geometry"])
|
|
links.new(center_position.outputs[0], surface.inputs["Position"])
|
|
normal = node(group, "GeometryNodeInputNormal", (720, -1000))
|
|
blur = node(group, "GeometryNodeBlurAttribute", (960, -1000))
|
|
blur.data_type = "FLOAT_VECTOR"
|
|
links.new(normal.outputs[0], blur.inputs["Value"])
|
|
local = node(group, "NodeGroupInput", (720, -1300))
|
|
links.new(local.outputs["Normal Smooth"], blur.inputs["Iterations"])
|
|
normalize = node(group, "ShaderNodeVectorMath", (1200, -1000))
|
|
normalize.operation = "NORMALIZE"
|
|
links.new(blur.outputs[0], normalize.inputs[0])
|
|
index = node(group, "GeometryNodeInputIndex", (1200, -1350))
|
|
sample = node(group, "GeometryNodeSampleIndex", (1440, -550))
|
|
sample.data_type, sample.domain = "FLOAT_VECTOR", "POINT"
|
|
links.new(surface.outputs[0], sample.inputs["Geometry"])
|
|
links.new(normalize.outputs[0], sample.inputs["Value"])
|
|
links.new(index.outputs[0], sample.inputs["Index"])
|
|
carrier = store(carrier, "normal", sample.outputs[0], (2160, 0), "FLOAT_VECTOR")
|
|
captured = read("front_delta", (2160, 850))
|
|
displacement = node(group, "ShaderNodeCombineXYZ", (2400, 850))
|
|
links.new(captured, displacement.inputs["Z"])
|
|
front = node(group, "GeometryNodeSetPosition", (2640, 0))
|
|
links.new(carrier, front.inputs["Geometry"])
|
|
links.new(displacement.outputs[0], front.inputs["Offset"])
|
|
shift_stage(group, previous, offset)
|
|
return front.outputs[0]
|
|
|