- Added a new cutout tool for selecting regions in images, allowing users to choose mesh shapes based on selected areas. - Introduced depth generation capabilities for rasterized images, including normal data extraction. - Created jobs for generating depth planes and region data, enhancing the AI data generation workflow. - Developed a selection refinement process for cutout regions, improving accuracy in generated outputs. - Established a new region module for handling rasterized image regions and their associated AI generation tasks. - Enhanced node graph builders for asset generation, facilitating smoother integration of new features.
182 lines
8.3 KiB
Python
182 lines
8.3 KiB
Python
"""Node graph builders used only while generating bundled assets."""
|
|
|
|
|
|
def group_input(nodes, location, visible_names):
|
|
node = nodes.new("NodeGroupInput")
|
|
node.location = location
|
|
visible = set(visible_names)
|
|
for output in node.outputs:
|
|
output.hide = output.name not in visible
|
|
return node
|
|
|
|
|
|
def edge_boundary_field(nodes, links, location):
|
|
x, y = location
|
|
vertex_neighbors = nodes.new("GeometryNodeInputMeshVertexNeighbors")
|
|
vertex_neighbors.location = (x, y + 150.0)
|
|
loose_vertex = nodes.new("FunctionNodeCompare")
|
|
loose_vertex.data_type = "INT"
|
|
loose_vertex.operation = "EQUAL"
|
|
loose_vertex_a = next(
|
|
socket for socket in loose_vertex.inputs if socket.identifier == "A_INT"
|
|
)
|
|
loose_vertex_b = next(
|
|
socket for socket in loose_vertex.inputs if socket.identifier == "B_INT"
|
|
)
|
|
loose_vertex_b.default_value = 1
|
|
loose_vertex.location = (x + 200.0, y + 150.0)
|
|
links.new(vertex_neighbors.outputs["Vertex Count"], loose_vertex_a)
|
|
|
|
edge_neighbors = nodes.new("GeometryNodeInputMeshEdgeNeighbors")
|
|
edge_neighbors.location = (x, y - 150.0)
|
|
boundary_edge = nodes.new("FunctionNodeCompare")
|
|
boundary_edge.data_type = "INT"
|
|
boundary_edge.operation = "EQUAL"
|
|
boundary_edge_a = next(
|
|
socket for socket in boundary_edge.inputs if socket.identifier == "A_INT"
|
|
)
|
|
boundary_edge_b = next(
|
|
socket for socket in boundary_edge.inputs if socket.identifier == "B_INT"
|
|
)
|
|
boundary_edge_b.default_value = 1
|
|
boundary_edge.location = (x + 200.0, y - 150.0)
|
|
links.new(edge_neighbors.outputs["Face Count"], boundary_edge_a)
|
|
edge_domain = nodes.new("GeometryNodeFieldOnDomain")
|
|
edge_domain.data_type = "BOOLEAN"
|
|
edge_domain.domain = "EDGE"
|
|
edge_domain.location = (x + 400.0, y - 150.0)
|
|
links.new(boundary_edge.outputs["Result"], edge_domain.inputs["Value"])
|
|
|
|
is_boundary = nodes.new("FunctionNodeBooleanMath")
|
|
is_boundary.operation = "OR"
|
|
is_boundary.location = (x + 600.0, y)
|
|
links.new(edge_domain.outputs["Value"], is_boundary.inputs[0])
|
|
links.new(loose_vertex.outputs["Result"], is_boundary.inputs[1])
|
|
return is_boundary.outputs["Boolean"]
|
|
|
|
|
|
def expand_smooth(
|
|
group, geometry, x_offset=0.0, iterations_name="Iterations"
|
|
):
|
|
nodes = group.nodes
|
|
links = group.links
|
|
existing_nodes = set(nodes)
|
|
iteration_controls = group_input(nodes, (550.0, 1150.0), {iterations_name})
|
|
weight_controls = group_input(nodes, (2300.0, 1450.0), {"Smooth"})
|
|
repeat_output = nodes.new("GeometryNodeRepeatOutput")
|
|
repeat_output.location = (3050.0, 550.0)
|
|
repeat_input = nodes.new("GeometryNodeRepeatInput")
|
|
repeat_input.pair_with_output(repeat_output)
|
|
repeat_output.repeat_items.new("GEOMETRY", "Geometry")
|
|
repeat_input.location = (550.0, 550.0)
|
|
links.new(
|
|
iteration_controls.outputs[iterations_name],
|
|
repeat_input.inputs["Iterations"],
|
|
)
|
|
links.new(geometry, repeat_input.inputs["Geometry"])
|
|
|
|
boundary_field = edge_boundary_field(nodes, links, (750.0, -350.0))
|
|
boundary_points = nodes.new("GeometryNodeFieldOnDomain")
|
|
boundary_points.data_type = "BOOLEAN"
|
|
boundary_points.domain = "POINT"
|
|
boundary_points.location = (1550.0, -350.0)
|
|
links.new(boundary_field, boundary_points.inputs["Value"])
|
|
|
|
boundary_geometry = nodes.new("GeometryNodeSeparateGeometry")
|
|
boundary_geometry.domain = "POINT"
|
|
boundary_geometry.location = (1750.0, -150.0)
|
|
links.new(repeat_input.outputs["Geometry"], boundary_geometry.inputs["Geometry"])
|
|
links.new(boundary_points.outputs["Value"], boundary_geometry.inputs["Selection"])
|
|
|
|
position = nodes.new("GeometryNodeInputPosition")
|
|
position.location = (750.0, 850.0)
|
|
smooth_all = nodes.new("GeometryNodeBlurAttribute")
|
|
smooth_all.data_type = "FLOAT_VECTOR"
|
|
smooth_all.inputs["Iterations"].default_value = 1
|
|
smooth_all.inputs["Weight"].default_value = 1.0
|
|
smooth_all.location = (950.0, 850.0)
|
|
links.new(position.outputs["Position"], smooth_all.inputs["Value"])
|
|
|
|
boundary_position = nodes.new("GeometryNodeInputPosition")
|
|
boundary_position.location = (1350.0, 250.0)
|
|
smooth_boundary = nodes.new("GeometryNodeBlurAttribute")
|
|
smooth_boundary.data_type = "FLOAT_VECTOR"
|
|
smooth_boundary.inputs["Iterations"].default_value = 1
|
|
smooth_boundary.inputs["Weight"].default_value = 0.5
|
|
smooth_boundary.location = (1550.0, 250.0)
|
|
links.new(boundary_position.outputs["Position"], smooth_boundary.inputs["Value"])
|
|
nearest_boundary = nodes.new("GeometryNodeSampleNearest")
|
|
nearest_boundary.domain = "POINT"
|
|
nearest_boundary.location = (1800.0, 150.0)
|
|
links.new(boundary_geometry.outputs["Selection"], nearest_boundary.inputs["Geometry"])
|
|
sample_boundary = nodes.new("GeometryNodeSampleIndex")
|
|
sample_boundary.data_type = "FLOAT_VECTOR"
|
|
sample_boundary.domain = "POINT"
|
|
sample_boundary.clamp = False
|
|
sample_boundary.location = (2050.0, 250.0)
|
|
links.new(boundary_geometry.outputs["Selection"], sample_boundary.inputs["Geometry"])
|
|
links.new(smooth_boundary.outputs["Value"], sample_boundary.inputs["Value"])
|
|
links.new(nearest_boundary.outputs["Index"], sample_boundary.inputs["Index"])
|
|
|
|
choose_boundary = nodes.new("GeometryNodeSwitch")
|
|
choose_boundary.input_type = "VECTOR"
|
|
choose_boundary.location = (2300.0, 350.0)
|
|
direct_boundary = edge_boundary_field(nodes, links, (750.0, 450.0))
|
|
links.new(direct_boundary, choose_boundary.inputs["Switch"])
|
|
links.new(smooth_all.outputs["Value"], choose_boundary.inputs["False"])
|
|
links.new(sample_boundary.outputs["Value"], choose_boundary.inputs["True"])
|
|
boundary_mix = nodes.new("ShaderNodeMix")
|
|
boundary_mix.data_type = "VECTOR"
|
|
boundary_mix.inputs[0].default_value = 1.0
|
|
boundary_mix.location = (2550.0, 400.0)
|
|
links.new(smooth_all.outputs["Value"], boundary_mix.inputs[4])
|
|
links.new(choose_boundary.outputs["Output"], boundary_mix.inputs[5])
|
|
|
|
normal = nodes.new("GeometryNodeInputNormal")
|
|
normal.location = (1350.0, 1050.0)
|
|
smooth_normal = nodes.new("GeometryNodeBlurAttribute")
|
|
smooth_normal.data_type = "FLOAT_VECTOR"
|
|
smooth_normal.inputs["Iterations"].default_value = 10
|
|
smooth_normal.inputs["Weight"].default_value = 1.0
|
|
smooth_normal.location = (1550.0, 1050.0)
|
|
links.new(normal.outputs["Normal"], smooth_normal.inputs["Value"])
|
|
normal_coherence = nodes.new("ShaderNodeVectorMath")
|
|
normal_coherence.operation = "LENGTH"
|
|
normal_coherence.location = (1800.0, 1050.0)
|
|
links.new(smooth_normal.outputs["Value"], normal_coherence.inputs[0])
|
|
sharp_switch = nodes.new("GeometryNodeSwitch")
|
|
sharp_switch.input_type = "FLOAT"
|
|
sharp_switch.inputs["Switch"].default_value = True
|
|
sharp_switch.inputs["False"].default_value = 1.0
|
|
sharp_switch.location = (2050.0, 1050.0)
|
|
links.new(normal_coherence.outputs["Value"], sharp_switch.inputs["True"])
|
|
smooth_weight = nodes.new("ShaderNodeMath")
|
|
smooth_weight.operation = "MULTIPLY"
|
|
smooth_weight.location = (2300.0, 1050.0)
|
|
links.new(weight_controls.outputs["Smooth"], smooth_weight.inputs[0])
|
|
links.new(sharp_switch.outputs["Output"], smooth_weight.inputs[1])
|
|
|
|
target_position = nodes.new("GeometryNodeSwitch")
|
|
target_position.input_type = "VECTOR"
|
|
target_position.inputs["Switch"].default_value = True
|
|
target_position.location = (2550.0, 700.0)
|
|
links.new(smooth_all.outputs["Value"], target_position.inputs["False"])
|
|
links.new(boundary_mix.outputs["Result"], target_position.inputs["True"])
|
|
current_position = nodes.new("GeometryNodeInputPosition")
|
|
current_position.location = (2300.0, 850.0)
|
|
mix_position = nodes.new("ShaderNodeMix")
|
|
mix_position.data_type = "VECTOR"
|
|
mix_position.location = (2800.0, 850.0)
|
|
links.new(smooth_weight.outputs[0], mix_position.inputs[0])
|
|
links.new(current_position.outputs["Position"], mix_position.inputs[4])
|
|
links.new(target_position.outputs["Output"], mix_position.inputs[5])
|
|
set_position = nodes.new("GeometryNodeSetPosition")
|
|
set_position.location = (2800.0, 550.0)
|
|
links.new(repeat_input.outputs["Geometry"], set_position.inputs["Geometry"])
|
|
links.new(mix_position.outputs["Result"], set_position.inputs["Position"])
|
|
links.new(set_position.outputs["Geometry"], repeat_output.inputs["Geometry"])
|
|
for node in set(nodes) - existing_nodes:
|
|
node.location.x += x_offset
|
|
return repeat_output.outputs["Geometry"]
|
|
|