"""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"]