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:
@@ -64,23 +64,8 @@ def test_quad_strips_and_corners_are_classified_once(cells, expected, offset, re
|
||||
assert cleaned_faces(vertices, faces) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize("count", [3, 5, 6])
|
||||
def test_non_quad_faces_are_preserved(count):
|
||||
angles = np.linspace(0, 2 * np.pi, count, endpoint=False)
|
||||
vertices = [(np.cos(a), np.sin(a), 0) for a in angles]
|
||||
assert cleaned_faces(vertices, [tuple(range(count))]) == {0}
|
||||
|
||||
|
||||
def test_nonmanifold_edge_is_not_a_boundary():
|
||||
vertices = [(0, 0, 0), (1, 0, 0), (1, 1, 0), (0, 1, 0),
|
||||
(2, 0, 0), (1, 2, 0), (0, 2, 1), (-1, 0, 0)]
|
||||
faces = [(0, 1, 2, 3), (2, 1, 4), (3, 2, 5), (2, 3, 6), (0, 3, 7)]
|
||||
assert cleaned_faces(vertices, faces) == set(range(5))
|
||||
|
||||
|
||||
@pytest.mark.parametrize("width, height, expected", [(1, 1, 0), (5, 1, 0), (2, 2, 8), (3, 3, 18)])
|
||||
@pytest.mark.parametrize("reverse", [False, True])
|
||||
def test_triangle_pairs_remove_strips_and_preserve_surface_corners(width, height, expected, reverse):
|
||||
@pytest.mark.parametrize("width,height,expected", [(2, 2, 8), (3, 3, 18)])
|
||||
def test_triangle_pairs_remove_strips_and_preserve_surface_corners(width, height, expected):
|
||||
vertices = [(x, y, 0) for y in range(height + 1) for x in range(width + 1)]
|
||||
faces = []
|
||||
for y in range(height):
|
||||
@@ -89,36 +74,11 @@ def test_triangle_pairs_remove_strips_and_preserve_surface_corners(width, height
|
||||
b, c, d = a + 1, a + width + 2, a + width + 1
|
||||
faces.extend([(a, b, c), (a, c, d)])
|
||||
# Reverse alternate faces to test matching by vertex identity, not winding.
|
||||
if reverse:
|
||||
faces = [face[::-1] if i % 2 else face[1:] + face[:1] for i, face in enumerate(faces)]
|
||||
faces = [face[::-1] if i % 2 else face[1:] + face[:1] for i, face in enumerate(faces)]
|
||||
result = cleaned_faces(vertices, faces, triangles=True)
|
||||
assert len(result) == expected
|
||||
|
||||
|
||||
def test_isolated_triangle_is_removed_only_for_cutout():
|
||||
vertices = [(0, 0, 0), (1, 0, 0), (0, 1, 0)]
|
||||
assert cleaned_faces(vertices, [(0, 1, 2)], triangles=True) == set()
|
||||
assert cleaned_faces(vertices, [(0, 1, 2)]) == {0}
|
||||
|
||||
|
||||
def test_triangle_pair_requires_a_manifold_shared_edge():
|
||||
vertices = [(0, 0, 0), (1, 0, 0), (.5, 1, 0), (.5, -1, 0), (.5, 0, 1)]
|
||||
faces = [(0, 1, 2), (1, 0, 3), (0, 1, 4)]
|
||||
assert cleaned_faces(vertices, faces, triangles=True) == {0, 1, 2}
|
||||
|
||||
|
||||
def test_triangle_pair_requires_four_distinct_vertices():
|
||||
vertices = [(0, 0, 0), (1, 0, 0), (0, 1, 0)]
|
||||
assert cleaned_faces(vertices, [(0, 1, 2), (2, 1, 0)], triangles=True) == {0, 1}
|
||||
|
||||
|
||||
def test_triangle_cleanup_marks_both_faces_without_recursive_peeling():
|
||||
vertices = [(0, 0, 0), (2, 0, 0), (1, 2, 0), (1, -2, 0),
|
||||
(3, 2, 0), (-1, 2, 0), (-1, -1, 0)]
|
||||
faces = [(0, 1, 2), (1, 0, 3), (2, 1, 4), (0, 2, 5), (3, 0, 6)]
|
||||
assert cleaned_faces(vertices, faces, triangles=True) == {0, 2, 3}
|
||||
|
||||
|
||||
@pytest.mark.parametrize("kind", ["plane", "cutout"])
|
||||
def test_strips_are_removed_before_projection_and_closed_thickness(kind):
|
||||
from tests.support.depth_surface import surface, evaluated, assert_closed, component_count
|
||||
@@ -144,15 +104,11 @@ def test_strips_are_removed_before_projection_and_closed_thickness(kind):
|
||||
assert len(faces) == 4 and len(vertices) == 9
|
||||
assert component_count(faces) == 1
|
||||
set_value("Thickness", 0.2)
|
||||
before_smooth, shell = evaluated(obj)
|
||||
vertices, shell = evaluated(obj)
|
||||
assert len(shell) == 16
|
||||
assert_closed(shell)
|
||||
set_value("Smooth", 2)
|
||||
after_smooth, smooth_shell = evaluated(obj)
|
||||
assert smooth_shell == shell
|
||||
assert np.isfinite(after_smooth).all()
|
||||
assert_closed(smooth_shell)
|
||||
assert component_count(smooth_shell) == 1
|
||||
assert np.isfinite(vertices).all()
|
||||
assert component_count(shell) == 1
|
||||
set_value("Thickness", 0.0)
|
||||
assert len(evaluated(obj)[1]) == 4
|
||||
|
||||
|
||||
Reference in New Issue
Block a user