Refactor depth node groups and simplify options
- Removed `Smooth Weight` input from `O Image Depth Plane`, `O Image Depth Cutout`, and `O Image Depth Panorama` to streamline the interface and maintain consistent boundary smoothing behavior. - Adjusted the `Reference Depth` input to appear last in the options panel for better organization, reflecting its role as a calibration value. - Consolidated the `expand_smooth()` function to only accept necessary parameters, eliminating unused branches related to `Smooth Weight` and `pin_sharp`. - Updated related tests and node assets to ensure functionality remains intact and consistent with the new structure. - Introduced new specifications to document the changes and ensure compliance with the updated requirements.
This commit is contained in:
@@ -9,7 +9,7 @@ from scipy.spatial import cKDTree
|
||||
|
||||
from anyimage.common.object import modifier_input_identifier, set_modifier_input
|
||||
from anyimage.operators.cutout_tool.object import load_cutout_node_group
|
||||
from tests.support.depth_surface import assert_closed, evaluated
|
||||
from tests.support.depth_surface import assert_closed, assert_single_vertex_fans, evaluated
|
||||
from tools.nodes.common.normal_map import AXIS_ATTRIBUTE, FACE_ATTRIBUTE, ROTATION_ATTRIBUTE
|
||||
from tools.nodes.groups.image_depth_cutout import build_image_depth_cutout_group
|
||||
from tools.nodes.groups.image_cutout_symmetry import build_image_cutout_symmetry_group
|
||||
@@ -100,6 +100,7 @@ def symmetry(request):
|
||||
|
||||
def test_symmetry_interface_and_cutout_defaults(symmetry):
|
||||
_obj, cutout, mirror, _cutout_setter, _mirror_setter = symmetry
|
||||
assert not any(node.bl_idname == "GeometryNodeMeshBoolean" for node in mirror.node_group.nodes)
|
||||
mirror_inputs = [
|
||||
item
|
||||
for item in mirror.node_group.interface.items_tree
|
||||
@@ -146,6 +147,102 @@ def test_final_symmetry_axis_is_x_and_z_is_up(symmetry):
|
||||
assert cKDTree(points).query(points * (-1, 1, 1))[0].max() < 1e-5
|
||||
assert np.ptp(points[:, 2]) > 1.0
|
||||
assert_closed(faces)
|
||||
assert_single_vertex_fans(faces)
|
||||
|
||||
|
||||
def _tolerance(points):
|
||||
size = float(np.linalg.norm(points.max(axis=0) - points.min(axis=0)))
|
||||
return max(size, 1e-8) * 1e-7
|
||||
|
||||
|
||||
def _evaluated(obj):
|
||||
result = obj.evaluated_get(bpy.context.evaluated_depsgraph_get())
|
||||
mesh = result.to_mesh()
|
||||
try:
|
||||
points = np.array([vertex.co[:] for vertex in mesh.vertices])
|
||||
faces = [tuple(polygon.vertices) for polygon in mesh.polygons]
|
||||
marker = np.array([item.value for item in mesh.attributes[FACE_ATTRIBUTE].data])
|
||||
finally:
|
||||
result.to_mesh_clear()
|
||||
return points, faces, marker
|
||||
|
||||
|
||||
def _open_edges(faces):
|
||||
counts = Counter(
|
||||
tuple(sorted((a, b))) for f in faces for a, b in zip(f, (*f[1:], f[0]))
|
||||
)
|
||||
return [edge for edge, count in counts.items() if count == 1]
|
||||
|
||||
|
||||
def _marked_vertices(points, faces, marker, value):
|
||||
indices = {index for face, item in zip(faces, marker) if item == value for index in face}
|
||||
return points[sorted(indices)]
|
||||
|
||||
|
||||
def _front_vertices(points, faces, marker, predicate):
|
||||
return np.array(
|
||||
[point for point in _marked_vertices(points, faces, marker, 1) if predicate(point)]
|
||||
)
|
||||
|
||||
|
||||
def _positions(points):
|
||||
return {tuple(np.round(point, 6)) for point in points}
|
||||
|
||||
|
||||
def _front_rim(points, faces, marker, tolerance):
|
||||
return _front_vertices(points, faces, marker, lambda point: abs(point[0]) <= tolerance)
|
||||
|
||||
|
||||
def test_seam_clamps_geometry_onto_the_symmetry_plane(symmetry):
|
||||
obj, _cutout, _mirror, _cutout_setter, _mirror_setter = symmetry
|
||||
points, faces, marker = _evaluated(obj)
|
||||
tolerance = _tolerance(points)
|
||||
plane = np.abs(points[:, 0]) <= tolerance
|
||||
|
||||
assert _marked_vertices(points, faces, marker, 1)[:, 0].min() >= -tolerance
|
||||
assert _marked_vertices(points, faces, marker, 2)[:, 0].max() <= tolerance
|
||||
assert plane.any()
|
||||
assert not any(all(plane[index] for index in face) for face in faces)
|
||||
# Kept straddling faces fold onto the plane instead of being discarded.
|
||||
assert any(plane[list(face)].any() and not plane[list(face)].all() for face in faces)
|
||||
|
||||
|
||||
def test_disabled_fill_keeps_the_welded_seam(symmetry):
|
||||
obj, _cutout, _mirror, _cutout_setter, mirror_setter = symmetry
|
||||
mirror_setter("Fill Sides", False)
|
||||
points, faces = evaluated(obj)
|
||||
tolerance = _tolerance(points)
|
||||
plane = np.abs(points[:, 0]) <= tolerance
|
||||
open_edges = _open_edges(faces)
|
||||
|
||||
assert open_edges
|
||||
assert not any(plane[edge[0]] and plane[edge[1]] for edge in open_edges)
|
||||
|
||||
|
||||
def test_fill_smooth_only_relaxes_the_seam(symmetry):
|
||||
obj, _cutout, _mirror, _cutout_setter, mirror_setter = symmetry
|
||||
mirror_setter("Fill Sides", True)
|
||||
mirror_setter("Fill Smooth", 0)
|
||||
plain_points, plain_faces, plain_marker = _evaluated(obj)
|
||||
mirror_setter("Fill Smooth", 4)
|
||||
smooth_points, smooth_faces, smooth_marker = _evaluated(obj)
|
||||
tolerance = _tolerance(plain_points)
|
||||
|
||||
for points, faces in ((plain_points, plain_faces), (smooth_points, smooth_faces)):
|
||||
plane = np.abs(points[:, 0]) <= tolerance
|
||||
assert plane.any()
|
||||
assert not any(all(plane[index] for index in face) for face in faces)
|
||||
plain_interior = _front_vertices(
|
||||
plain_points, plain_faces, plain_marker, lambda point: point[0] > tolerance
|
||||
)
|
||||
smooth_interior = _front_vertices(
|
||||
smooth_points, smooth_faces, smooth_marker, lambda point: point[0] > tolerance
|
||||
)
|
||||
assert _positions(plain_interior) == _positions(smooth_interior)
|
||||
plain_rim = _front_rim(plain_points, plain_faces, plain_marker, tolerance)
|
||||
smooth_rim = _front_rim(smooth_points, smooth_faces, smooth_marker, tolerance)
|
||||
assert plain_rim.shape == smooth_rim.shape
|
||||
assert not np.allclose(np.sort(plain_rim[:, 1:], axis=0), np.sort(smooth_rim[:, 1:], axis=0))
|
||||
|
||||
|
||||
def test_object_normal_attributes_follow_final_orientation(symmetry):
|
||||
|
||||
Reference in New Issue
Block a user