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

@@ -6,7 +6,6 @@ from ..common.validity import delete_invalid_points
from ..common.nodes import group_input as _group_input, interface_socket as _interface_socket
from ..common.nodes import prepare_node_group, float_input, evaluate_field
from ..common.smoothing import expand_smooth
from ..common.boundary_smoothing import smooth_boundary_camera, smooth_cut_boundary
from ..common.depth_surface import (
_math, project_depth_surface, thicken_depth_surface,
@@ -40,17 +39,13 @@ def build_image_depth_plane_group(image_plane_group):
depth_scale = _interface_socket(group, "Depth Scale", "INPUT", "NodeSocketFloat")
depth_scale.default_value = 1.0
depth_scale.min_value = 0.0
depth_scale.max_value = 2.0
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."
iterations = _interface_socket(group, "Smooth", "INPUT", "NodeSocketInt")
iterations.description = "Set the number of mesh smoothing passes. Higher values smooth the surface more but may soften details. Zero disables smoothing."
iterations.default_value = 0
iterations.min_value, iterations.max_value = 0, 20
valid_only = _interface_socket(group, "Depth Mask", "INPUT", "NodeSocketBool")
valid_only.description = "Remove mesh areas marked invalid by the depth mask."
valid_only.default_value = True
group.interface.move(valid_only, iterations.position)
options = group.interface.new_panel(name="Options", default_closed=True)
float_input(group, "Smooth Weight", 1.0, 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.0, maximum=1, subtype="FACTOR", parent=options).description = "Control the strength of boundary smoothing. Higher values move boundary vertices more."
float_input(group, "Reference Depth", 1.0, subtype="DISTANCE", parent=options)
boundary_smooth = _interface_socket(group, "Boundary Smooth", "INPUT", "NodeSocketInt", parent=options)
boundary_smooth.default_value, boundary_smooth.min_value, boundary_smooth.max_value = 4, 0, 16
@@ -137,7 +132,9 @@ def build_image_depth_plane_group(image_plane_group):
scale_input.outputs["Uniform Scale"], depth_input.outputs["Reference Depth"],
depth_input.outputs["Depth Scale"], split_input.outputs["Depth Split"],
)
surface = smooth_cut_boundary(group, surface, original_boundary)
surface = smooth_cut_boundary(
group, surface, cut_vertex, protected=original_boundary, outline_scale=1.0,
)
shell_input = _group_input(nodes, {"Thickness"})
shell = thicken_depth_surface(
group, surface, shell_input.outputs["Thickness"],
@@ -152,12 +149,9 @@ def build_image_depth_plane_group(image_plane_group):
links.new(positive.outputs[0], choose.inputs["Switch"])
links.new(surface, choose.inputs["False"])
links.new(shell["geometry"], choose.inputs["True"])
geometry = expand_smooth(
group, choose.outputs["Output"], iterations_name="Smooth", weight_name="Smooth Weight",
)
smooth = nodes.new("GeometryNodeSetShadeSmooth")
smooth.domain = "FACE"
links.new(geometry, smooth.inputs["Geometry"])
links.new(choose.outputs["Output"], smooth.inputs["Geometry"])
output = nodes.new("NodeGroupOutput")
links.new(smooth.outputs["Geometry"], output.inputs["Geometry"])
group.color_tag = "GEOMETRY"