Refactor depth node groups and simplify options

- 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.
This commit is contained in:
2026-09-16 13:12:12 +08:00
parent 6ca084ee4a
commit 7f69630371
26 changed files with 741 additions and 178 deletions

View File

@@ -92,12 +92,9 @@ def cut_boundary_influence(group, split_boundary, protected=False, *, outline_sc
def smooth_cut_boundary(group, geometry, split_boundary=False, *, protected=False, outline_scale=0.1, boundary=None):
"""Blend O Smooth through split and outline masks with configurable weights."""
"""Move boundary vertices toward the smoothed position through split and outline influence."""
influence = cut_boundary_influence(
group, split_boundary, protected, outline_scale=outline_scale, boundary=boundary,
)
# The support band depends on topology, which stays unchanged in the loop.
return expand_smooth(
group, geometry, iterations_name="Boundary Smooth", weight_name="Smooth Weight",
influence=influence, pin_sharp=False,
)
return expand_smooth(group, geometry, "Boundary Smooth", influence)

View File

@@ -40,14 +40,10 @@ def edge_boundary_field(nodes, links):
return is_boundary.outputs["Boolean"]
def expand_smooth(
group, geometry, iterations_name, weight_name, *,
influence=None, pin_sharp=True,
):
def expand_smooth(group, geometry, iterations_name, influence):
nodes = group.nodes
links = group.links
iteration_controls = group_input(nodes, {iterations_name})
weight_controls = group_input(nodes, {weight_name})
repeat_output = nodes.new("GeometryNodeRepeatOutput")
repeat_input = nodes.new("GeometryNodeRepeatInput")
repeat_input.pair_with_output(repeat_output)
@@ -69,18 +65,15 @@ def expand_smooth(
links.new(geometry, repeat_input.inputs["Geometry"])
nearest_boundary = nodes.new("GeometryNodeSampleNearest")
nearest_boundary.domain = "POINT"
if influence is not None:
# 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"])
else:
links.new(boundary_geometry.outputs["Selection"], nearest_boundary.inputs["Geometry"])
# 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")
@@ -109,44 +102,19 @@ def expand_smooth(
links.new(smooth_all.outputs["Value"], choose_boundary.inputs["False"])
links.new(sample_boundary.outputs["Value"], choose_boundary.inputs["True"])
weight = weight_controls.outputs[weight_name]
if pin_sharp:
normal = nodes.new("GeometryNodeInputNormal")
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
links.new(normal.outputs["Normal"], smooth_normal.inputs["Value"])
normal_coherence = nodes.new("ShaderNodeVectorMath")
normal_coherence.operation = "LENGTH"
links.new(smooth_normal.outputs["Value"], normal_coherence.inputs[0])
smooth_weight = nodes.new("ShaderNodeMath")
smooth_weight.operation = "MULTIPLY"
links.new(weight_controls.outputs[weight_name], smooth_weight.inputs[0])
links.new(normal_coherence.outputs["Value"], smooth_weight.inputs[1])
weight = smooth_weight.outputs[0]
if influence is not None:
masked_weight = nodes.new("ShaderNodeMath")
masked_weight.operation = "MULTIPLY"
links.new(weight, masked_weight.inputs[0])
links.new(influence, masked_weight.inputs[1])
weight = masked_weight.outputs[0]
current_position = nodes.new("GeometryNodeInputPosition")
mix_position = nodes.new("ShaderNodeMix")
mix_position.data_type = "VECTOR"
links.new(weight, mix_position.inputs[0])
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"])
if influence is not None:
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"]
return repeat_output.outputs["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"]