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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user