Refactor depth surface handling and unify depth sampling rules
- Removed the `always_vertex` parameter from `build_surface_camera` to streamline depth sampling for cutouts and ensure consistent behavior across depth plane and panorama. - Updated depth sampling logic to ensure that all free boundary points, including the original frame of the depth plane, use neighboring face depth instead of their own texture sampling. - Adjusted the depth mask deletion process to operate on faces rather than points, eliminating the need for additional cleanup of dangling edges. - Ensured that the cutout rules are consistently applied across all relevant nodes, removing exceptions and simplifying the logic. - Updated tests to verify the new behavior, ensuring that cutout points follow the depth of adjacent faces and that the original frame maintains its depth sampling. - Refactored geometry handling in multiple depth-related nodes to improve clarity and maintainability.
This commit is contained in:
@@ -113,6 +113,7 @@ def test_symmetry_interface_and_cutout_defaults(symmetry):
|
||||
"Scale",
|
||||
"Fill Sides",
|
||||
"Fill Smooth",
|
||||
"Seam Smooth",
|
||||
]
|
||||
assert tuple(mirror_inputs[1].default_value) == (0, 0, 1)
|
||||
assert mirror_inputs[3].default_value == 1
|
||||
@@ -219,7 +220,7 @@ def test_disabled_fill_keeps_the_welded_seam(symmetry):
|
||||
assert not any(plane[edge[0]] and plane[edge[1]] for edge in open_edges)
|
||||
|
||||
|
||||
def test_fill_smooth_only_relaxes_the_seam(symmetry):
|
||||
def test_fill_smooth_relaxes_the_junction_band(symmetry):
|
||||
obj, _cutout, _mirror, _cutout_setter, mirror_setter = symmetry
|
||||
mirror_setter("Fill Sides", True)
|
||||
mirror_setter("Fill Smooth", 0)
|
||||
@@ -232,17 +233,67 @@ def test_fill_smooth_only_relaxes_the_seam(symmetry):
|
||||
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
|
||||
assert smooth_faces == plain_faces
|
||||
axis = np.abs(plain_points[:, 0]) <= tolerance
|
||||
moved = np.linalg.norm(smooth_points - plain_points, axis=1)
|
||||
# 衔接带同时覆盖对称轴上的点与外侧轮廓。
|
||||
assert moved[axis].max() > 1e-4
|
||||
plain_rim = _positions(_front_rim(plain_points, plain_faces, plain_marker, tolerance))
|
||||
smooth_rim = _positions(_front_rim(smooth_points, smooth_faces, smooth_marker, tolerance))
|
||||
assert plain_rim != smooth_rim
|
||||
|
||||
|
||||
def test_fill_smooth_band_reaches_beyond_two_rings():
|
||||
"""Fill Smooth 平滑的是衔接带,覆盖范围比原先的两圈更宽。"""
|
||||
from tools.nodes.common.depth_surface import _math
|
||||
from tools.nodes.groups.image_cutout_symmetry import FILL_SMOOTH_RINGS, _falloff
|
||||
|
||||
bpy.ops.wm.read_factory_settings(use_empty=True)
|
||||
size, rows = FILL_SMOOTH_RINGS + 4, 3
|
||||
points = [(x, 0.0, y) for y in range(rows) for x in range(size)]
|
||||
faces = [
|
||||
(
|
||||
y * size + x,
|
||||
y * size + x + 1,
|
||||
(y + 1) * size + x + 1,
|
||||
(y + 1) * size + x,
|
||||
)
|
||||
for y in range(rows - 1)
|
||||
for x in range(size - 1)
|
||||
]
|
||||
mesh = bpy.data.meshes.new("Fill band")
|
||||
mesh.from_pydata(points, [], faces)
|
||||
obj = bpy.data.objects.new("Fill band", mesh)
|
||||
bpy.context.collection.objects.link(obj)
|
||||
group = bpy.data.node_groups.new("Fill band", "GeometryNodeTree")
|
||||
for direction in ("INPUT", "OUTPUT"):
|
||||
group.interface.new_socket(
|
||||
name="Geometry", in_out=direction, socket_type="NodeSocketGeometry"
|
||||
)
|
||||
source = group.nodes.new("NodeGroupInput")
|
||||
position = group.nodes.new("GeometryNodeInputPosition")
|
||||
axes = group.nodes.new("ShaderNodeSeparateXYZ")
|
||||
group.links.new(position.outputs[0], axes.inputs[0])
|
||||
outline = _math(group, "COMPARE", axes.outputs["X"], 0)
|
||||
store = group.nodes.new("GeometryNodeStoreNamedAttribute")
|
||||
store.data_type, store.domain = "FLOAT", "POINT"
|
||||
store.inputs["Name"].default_value = "fill_band"
|
||||
group.links.new(source.outputs["Geometry"], store.inputs["Geometry"])
|
||||
group.links.new(_falloff(group, outline, FILL_SMOOTH_RINGS), store.inputs["Value"])
|
||||
group.links.new(
|
||||
store.outputs["Geometry"], group.nodes.new("NodeGroupOutput").inputs["Geometry"]
|
||||
)
|
||||
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))
|
||||
obj.modifiers.new("Fill band", "NODES").node_group = group
|
||||
result = obj.evaluated_get(bpy.context.evaluated_depsgraph_get())
|
||||
data = result.to_mesh()
|
||||
try:
|
||||
band = np.array(
|
||||
[item.value for item in data.attributes["fill_band"].data]
|
||||
).reshape(rows, size)
|
||||
finally:
|
||||
result.to_mesh_clear()
|
||||
assert (band[:, 3] > 0).all()
|
||||
assert (band[:, FILL_SMOOTH_RINGS + 1] == 0).all()
|
||||
|
||||
|
||||
def test_object_normal_attributes_follow_final_orientation(symmetry):
|
||||
|
||||
Reference in New Issue
Block a user