feat(cutout): implement boundary padding for cutout textures

- Introduced a new `Boundary Padding` preference in the Cutout Tool with a default of 2 px and a configurable range of 1-4 px.
- Updated the Cutout client to establish inward mapping from the final Mask, sampling in a fixed direction and processing independent material RGBA and Depth.
- Enhanced the handling of RGBA and Depth during cutout operations, ensuring proper mapping and preservation of source data.
- Added tests to validate the new boundary padding functionality and its integration with existing cutout processes.

feat(geometry): remove overall mesh smoothing from geometry nodes

- Removed the `Smooth` input from several geometry node groups to eliminate unnecessary overall mesh smoothing.
- Retained `Smooth Weight` for depth nodes while removing it from Cutout and Relief Plane nodes.
- Ensured that boundary, normal, and fill smoothing behaviors remain intact and consistent.
- Updated tests and documentation to reflect the changes in node interfaces and behaviors.

feat(normals): scale tangent normals with depth

- Reused the existing `o_normal_reduction` attribute to adjust Tangent Normal strength based on the geometry's `Depth Scale`.
- Ensured that Tangent Normal strength is consistent with the geometry depth, preserving full strength for materials that do not provide the attribute.
- Updated tests to verify the correct behavior of normal strength adjustments in both Tangent and Object Space.
This commit is contained in:
2026-09-15 00:40:24 +08:00
parent ab282e4fdf
commit 591e62085a
93 changed files with 1915 additions and 2851 deletions

View File

@@ -11,7 +11,6 @@ from ..common.depth_surface import (
)
from ..common.nodes import float_input, group_input, interface_socket, prepare_node_group, evaluate_field, remove_attributes
from ..common.material_slots import inherit_material_slots
from ..common.smoothing import expand_smooth
from ..common.boundary_smoothing import smooth_boundary_depth, smooth_cut_boundary
@@ -45,18 +44,14 @@ def build_image_depth_panorama_group():
subdivide.default_value, subdivide.min_value, subdivide.max_value = 8, 0, 8
float_input(group, "Depth Scale", 1, maximum=1, subtype="FACTOR").description = "Blend between a sphere at zero and the estimated depth surface at one."
float_input(group, "Depth Split", 0.1, maximum=1, subtype="FACTOR").description = "Split the mesh where depth changes abruptly. Higher values detect smaller depth jumps. Zero disables splitting."
smooth = interface_socket(group, "Smooth", "INPUT", "NodeSocketInt")
smooth.description = "Set the number of mesh smoothing passes. Higher values smooth the surface more but may soften details. Zero disables smoothing."
smooth.default_value, smooth.min_value, smooth.max_value = 0, 0, 20
valid_only = interface_socket(group, "Depth Mask", "INPUT", "NodeSocketBool")
valid_only.default_value = True
valid_only.description = "Remove mesh areas marked invalid by the depth mask."
group.interface.move(valid_only, smooth.position)
options = group.interface.new_panel("Options", default_closed=True)
boundary_smooth = interface_socket(group, "Boundary Smooth", "INPUT", "NodeSocketInt", options)
boundary_smooth.default_value, boundary_smooth.min_value, boundary_smooth.max_value = 2, 0, 20
boundary_smooth.default_value, boundary_smooth.min_value, boundary_smooth.max_value = 2, 0, 16
boundary_smooth.description = "Smooth depth and geometry near cut edges on the panorama surface. Zero disables boundary smoothing."
float_input(group, "Smooth Weight", 1, maximum=1, subtype="FACTOR", parent=options).description = "Control the strength of each mesh smoothing pass. Higher values move vertices more."
float_input(group, "Smooth Weight", 1, maximum=1, subtype="FACTOR", parent=options).description = "Control the strength of boundary smoothing. Higher values move boundary vertices more."
float_input(group, "Mask Threshold", 0.9, maximum=1, subtype="FACTOR", parent=options).description = "Set the minimum depth mask value treated as valid. Higher values exclude more partially valid boundary areas."
float_input(group, "Invalid Distance", 100, minimum=1e-5, subtype="DISTANCE", parent=options).description = "Set the fallback distance from the panorama center for invalid depth areas kept when Depth Mask is disabled."
data = group.interface.new_panel("Data", default_closed=True)
@@ -184,8 +179,7 @@ def build_image_depth_panorama_group():
group, deform.outputs[0], CUT_ATTRIBUTE,
enabled=_math(group, "GREATER_THAN", strength, 0.0),
)
geometry = smooth_cut_boundary(group, geometry)
geometry = expand_smooth(group, geometry, iterations_name="Smooth", weight_name="Smooth Weight")
geometry = smooth_cut_boundary(group, geometry, cut_vertex, outline_scale=1.0)
flip = nodes.new("GeometryNodeFlipFaces")
links.new(geometry, flip.inputs["Mesh"])
smooth = nodes.new("GeometryNodeSetShadeSmooth")