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

@@ -50,6 +50,43 @@ def test_normal_smooth_changes_thickness_direction_without_moving_zero_thickness
assert np.max(np.abs(raw - smooth)) > 1e-5
def test_thin_shell_normal_smoothing_is_independent_of_thickness_and_reference():
from tests.support.depth_surface import surface, evaluated
obj, set_value = surface(step=0, resolution=12)
image = bpy.data.images['Camera']
pixels = np.array(image.pixels[:], dtype=np.float32).reshape(32, 64, 4)
pixels[..., 2] = 1 + .15 * np.sin(pixels[..., 0] * 6) * np.cos(pixels[..., 1] * 5)
image.pixels.foreach_set(pixels.ravel())
image.update()
set_value('Reference Depth', 10.)
set_value('Thickness', 0.)
front, _ = evaluated(obj)
def offsets(thickness, smoothing, reference=10.):
set_value('Thickness', thickness)
set_value('Normal Smooth', smoothing)
set_value('Reference Depth', reference)
points, faces = evaluated(obj)
adjusted_front = front + (0, 0, reference - 10.)
from scipy.spatial import cKDTree
distances, indices = cKDTree(adjusted_front).query(points)
np.testing.assert_allclose(np.sort(distances)[:len(front)], 0, atol=2e-6)
rear = distances > thickness * .5
assert rear.sum() == len(front)
order = np.argsort(indices[rear])
return ((points[rear] - adjusted_front[indices[rear]]) / thickness)[order], faces
raw, _ = offsets(.02, 16)
smooth, faces = offsets(.02, 512)
assert np.max(np.linalg.norm(raw - smooth, axis=1)) > .05
thinner, thinner_faces = offsets(.01, 512)
distant, _ = offsets(.02, 512, 20.)
np.testing.assert_allclose(thinner, smooth, atol=2e-4)
np.testing.assert_allclose(distant, smooth, atol=2e-4)
assert thinner_faces == faces
def set_test_structure(monkeypatch, value):
"""Control structural amplitude without depending on storage nodes."""
from tools.nodes.groups import image_depth_cutout