feat: Implement depth cutout symmetry and associated functionalities

- Introduced a new proposal for depth cutout symmetry, allowing for the reuse of depth replacement and geometry operations.
- Added requirements for maintaining default thickness values for cutout nodes and ensuring proper initialization during object creation.
- Enhanced symmetry node to handle existing geometry, including alignment, mirroring, and boundary filling.
- Implemented fill smoothing to control the geometry of generated walls while preserving original surfaces.
- Created tests to validate the functionality of the new symmetry features against baseline geometry.
- Updated existing assets and node groups to support the new symmetry capabilities without introducing additional dependencies.
This commit is contained in:
2026-09-14 14:58:48 +08:00
parent dc000e50b1
commit ab282e4fdf
28 changed files with 716 additions and 689 deletions

View File

@@ -90,7 +90,7 @@ def create_shape_object(
):
import numpy as np
normal_mode = NormalMode(normal_mode)
normal_mode = NormalMode.OBJECT if shape in DEPTH_CUTOUT_SHAPES else NormalMode(normal_mode)
bounds = crop_plane_bounds(
source_object,
content_bounds,
@@ -180,7 +180,7 @@ def create_shape_object(
crop_center,
)
mesh_object["anyimage_mesh_shape"] = shape
node_group = load_cutout_node_group(shape)
node_group = load_cutout_node_group("DEPTH_SOLID" if shape == "DEPTH_SYMMETRY" else shape)
modifier = mesh_object.modifiers.new(name=node_group.name, type="NODES")
modifier.node_group = node_group
modifier.show_group_selector = False
@@ -188,18 +188,26 @@ def create_shape_object(
("Cleanup Threshold", cleanup_value),
(
"Thickness",
0.0 if shape == "FLAT" else 1.0,
0.0 if shape in {"FLAT", "DEPTH_SYMMETRY"} else 1.0,
),
):
if name == "Thickness" and shape == "DEPTH_SYMMETRY":
continue
set_modifier_input(
modifier,
modifier_input_identifier(
node_group, name,
subtype="NONE" if name == "Thickness" and shape == "DEPTH_SOLID" else None,
subtype="NONE" if name == "Thickness" and shape in DEPTH_CUTOUT_SHAPES else None,
),
value,
)
if gesture == "POLYLINE" and shape != "DEPTH_SYMMETRY":
if shape == "DEPTH_SOLID":
set_modifier_input(
modifier,
modifier_input_identifier(node_group, "Thickness", subtype="DISTANCE"),
0.2,
)
if gesture == "POLYLINE":
set_modifier_input(
modifier,
modifier_input_identifier(node_group, "Mode"),
@@ -224,9 +232,13 @@ def create_shape_object(
value,
)
if shape == "DEPTH_SYMMETRY":
symmetry_group = load_cutout_node_group("DEPTH_SYMMETRY")
symmetry = mesh_object.modifiers.new(name=symmetry_group.name, type="NODES")
symmetry.node_group = symmetry_group
symmetry.show_group_selector = False
set_modifier_input(
modifier,
modifier_input_identifier(node_group, "Depth Direction"),
symmetry,
modifier_input_identifier(symmetry_group, "Symmetry Direction"),
depth_direction,
)
return finalize_object_result(

View File

@@ -72,10 +72,8 @@ _HIDDEN = {"HIDDEN", "SKIP_SAVE"}
def normal_mode_for_shape(shape, generate_normal):
if shape == "DEPTH_SOLID":
if shape in DEPTH_CUTOUT_SHAPES:
return NormalMode.OBJECT
if shape == "DEPTH_SYMMETRY":
return NormalMode.TANGENT
if not generate_normal:
return NormalMode.NONE
return NormalMode.TANGENT

View File

@@ -11,7 +11,7 @@ CUTOUT_Z_TO_X = (
CUTOUT_NODE_GROUP_NAMES = {
"FLAT": "O Image Cutout",
"SOLID": "O Image Cutout",
"DEPTH_SYMMETRY": "O Image Depth Symmetry",
"DEPTH_SYMMETRY": "O Image Cutout Symmetry",
"DEPTH_SOLID": "O Image Depth Cutout",
}
CUTOUT_SHAPE_LABELS = {