- Removed `Smooth Weight` input from `O Image Depth Plane`, `O Image Depth Cutout`, and `O Image Depth Panorama` to streamline the interface and maintain consistent boundary smoothing behavior. - Adjusted the `Reference Depth` input to appear last in the options panel for better organization, reflecting its role as a calibration value. - Consolidated the `expand_smooth()` function to only accept necessary parameters, eliminating unused branches related to `Smooth Weight` and `pin_sharp`. - Updated related tests and node assets to ensure functionality remains intact and consistent with the new structure. - Introduced new specifications to document the changes and ensure compliance with the updated requirements.
121 lines
5.8 KiB
Python
121 lines
5.8 KiB
Python
"""Build shared boundary fields and iterative smoothing."""
|
|
from .nodes import group_input, sample_field
|
|
|
|
|
|
def edge_boundary_field(nodes, links):
|
|
vertex_neighbors = nodes.new("GeometryNodeInputMeshVertexNeighbors")
|
|
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
|
|
links.new(vertex_neighbors.outputs["Vertex Count"], loose_vertex_a)
|
|
|
|
edge_neighbors = nodes.new("GeometryNodeInputMeshEdgeNeighbors")
|
|
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
|
|
links.new(edge_neighbors.outputs["Face Count"], boundary_edge_a)
|
|
edge_domain = nodes.new("GeometryNodeFieldOnDomain")
|
|
edge_domain.data_type = "BOOLEAN"
|
|
edge_domain.domain = "EDGE"
|
|
links.new(boundary_edge.outputs["Result"], edge_domain.inputs["Value"])
|
|
|
|
is_boundary = nodes.new("FunctionNodeBooleanMath")
|
|
is_boundary.operation = "OR"
|
|
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, iterations_name, influence):
|
|
nodes = group.nodes
|
|
links = group.links
|
|
iteration_controls = group_input(nodes, {iterations_name})
|
|
repeat_output = nodes.new("GeometryNodeRepeatOutput")
|
|
repeat_input = nodes.new("GeometryNodeRepeatInput")
|
|
repeat_input.pair_with_output(repeat_output)
|
|
links.new(
|
|
iteration_controls.outputs[iterations_name],
|
|
repeat_input.inputs["Iterations"],
|
|
)
|
|
|
|
boundary_field = edge_boundary_field(nodes, links)
|
|
boundary_points = nodes.new("GeometryNodeFieldOnDomain")
|
|
boundary_points.data_type = "BOOLEAN"
|
|
boundary_points.domain = "POINT"
|
|
links.new(boundary_field, boundary_points.inputs["Value"])
|
|
|
|
boundary_geometry = nodes.new("GeometryNodeSeparateGeometry")
|
|
boundary_geometry.domain = "POINT"
|
|
links.new(repeat_input.outputs["Geometry"], boundary_geometry.inputs["Geometry"])
|
|
links.new(boundary_points.outputs["Value"], boundary_geometry.inputs["Selection"])
|
|
links.new(geometry, repeat_input.inputs["Geometry"])
|
|
nearest_boundary = nodes.new("GeometryNodeSampleNearest")
|
|
nearest_boundary.domain = "POINT"
|
|
# Both boundary meshes keep the same compact index order: only positions change.
|
|
source_boundary = nodes.new("GeometryNodeSeparateGeometry")
|
|
source_boundary.domain = "POINT"
|
|
links.new(geometry, source_boundary.inputs["Geometry"])
|
|
links.new(boundary_points.outputs["Value"], source_boundary.inputs["Selection"])
|
|
links.new(source_boundary.outputs["Selection"], nearest_boundary.inputs["Geometry"])
|
|
source_position = nodes.new("GeometryNodeInputPosition").outputs["Position"]
|
|
fixed_position = sample_field(group, geometry, source_position, "FLOAT_VECTOR")
|
|
links.new(fixed_position, nearest_boundary.inputs["Sample Position"])
|
|
|
|
position = nodes.new("GeometryNodeInputPosition")
|
|
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
|
|
links.new(position.outputs["Position"], smooth_all.inputs["Value"])
|
|
|
|
boundary_position = nodes.new("GeometryNodeInputPosition")
|
|
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
|
|
links.new(boundary_position.outputs["Position"], smooth_boundary.inputs["Value"])
|
|
sample_boundary = nodes.new("GeometryNodeSampleIndex")
|
|
sample_boundary.data_type = "FLOAT_VECTOR"
|
|
sample_boundary.domain = "POINT"
|
|
sample_boundary.clamp = False
|
|
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"
|
|
links.new(boundary_points.outputs["Value"], choose_boundary.inputs["Switch"])
|
|
links.new(smooth_all.outputs["Value"], choose_boundary.inputs["False"])
|
|
links.new(sample_boundary.outputs["Value"], choose_boundary.inputs["True"])
|
|
|
|
current_position = nodes.new("GeometryNodeInputPosition")
|
|
mix_position = nodes.new("ShaderNodeMix")
|
|
mix_position.data_type = "VECTOR"
|
|
links.new(influence, mix_position.inputs[0])
|
|
links.new(current_position.outputs["Position"], mix_position.inputs[4])
|
|
links.new(choose_boundary.outputs["Output"], mix_position.inputs[5])
|
|
set_position = nodes.new("GeometryNodeSetPosition")
|
|
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"])
|
|
enabled = nodes.new("GeometryNodeSwitch")
|
|
enabled.input_type = "GEOMETRY"
|
|
links.new(iteration_controls.outputs[iterations_name], enabled.inputs["Switch"])
|
|
links.new(geometry, enabled.inputs["False"])
|
|
links.new(repeat_output.outputs["Geometry"], enabled.inputs["True"])
|
|
return enabled.outputs["Output"]
|