- Introduced a new design for selection rasterization that decouples the selection geometry from the image content, ensuring that the SelectionMask is independent of the source image's alpha and color. - Updated the `rasterize_selection_path` function to only accept selection paths and image dimensions, removing parameters related to source alpha and alpha thresholds. - Implemented a new approach for handling selection paths using non-zero winding fill, ensuring overlapping areas are preserved. - Enhanced performance by utilizing a scanline algorithm for rasterization, significantly reducing processing time for high-resolution images. - Updated internal documentation and added comprehensive tests to validate the new behavior and performance improvements. - Ensured backward compatibility by maintaining existing interfaces where necessary while introducing breaking changes in the selection processing logic.
121 lines
4.0 KiB
Python
121 lines
4.0 KiB
Python
from pathlib import Path
|
|
import sys
|
|
|
|
import bpy
|
|
|
|
|
|
PROJECT_ROOT = Path(__file__).parents[2]
|
|
sys.path.insert(0, str(PROJECT_ROOT / "src"))
|
|
sys.path.insert(
|
|
0,
|
|
str(next((PROJECT_ROOT / "src" / "anyimage" / "wheels").glob("blendjob-*.whl"))),
|
|
)
|
|
|
|
from anyimage.common.object import (
|
|
modifier_input_identifier,
|
|
set_modifier_input,
|
|
)
|
|
from anyimage.operators.convert_to_plane.mesh_plane import (
|
|
add_mesh_plane_processing,
|
|
create_mesh_plane_mesh,
|
|
)
|
|
|
|
|
|
def evaluated_mesh(obj):
|
|
bpy.context.view_layer.update()
|
|
evaluated = obj.evaluated_get(bpy.context.evaluated_depsgraph_get())
|
|
return evaluated, evaluated.to_mesh()
|
|
|
|
|
|
def main():
|
|
bpy.ops.wm.read_factory_settings(use_empty=True)
|
|
mesh = create_mesh_plane_mesh("Mesh Plane", (-1.0, 1.0, -0.5, 0.5))
|
|
assert len(mesh.polygons) == 1
|
|
material = bpy.data.materials.new("Mesh Plane Material")
|
|
mesh.materials.append(material)
|
|
obj = bpy.data.objects.new("Mesh Plane", mesh)
|
|
bpy.context.scene.collection.objects.link(obj)
|
|
modifier = add_mesh_plane_processing(obj)
|
|
group = modifier.node_group
|
|
assert group.name == "O Mesh Plane"
|
|
assert group.is_modifier
|
|
inputs = {
|
|
item.name: item
|
|
for item in group.interface.items_tree
|
|
if item.item_type == "SOCKET" and item.in_out == "INPUT"
|
|
}
|
|
assert list(inputs) == ["Geometry", "Subdivide", "Thickness"]
|
|
assert inputs["Subdivide"].default_value == 0
|
|
assert inputs["Subdivide"].max_value == 10
|
|
assert inputs["Thickness"].default_value == 0.0
|
|
assert obj.data.materials[0] == material
|
|
|
|
evaluated, result = evaluated_mesh(obj)
|
|
try:
|
|
assert result.materials[0].original == material
|
|
assert len(result.polygons) == 2
|
|
assert len(result.vertices) == 6
|
|
assert "UVMap" in result.attributes
|
|
uv_values = {
|
|
tuple(round(value, 6) for value in loop.uv)
|
|
for loop in result.uv_layers["UVMap"].data
|
|
}
|
|
assert uv_values == {
|
|
(0.0, 0.0),
|
|
(0.5, 0.0),
|
|
(1.0, 0.0),
|
|
(0.0, 1.0),
|
|
(0.5, 1.0),
|
|
(1.0, 1.0),
|
|
}
|
|
assert all(abs(vertex.co.z) < 1e-6 for vertex in result.vertices)
|
|
assert all(polygon.material_index == 0 for polygon in result.polygons)
|
|
finally:
|
|
evaluated.to_mesh_clear()
|
|
|
|
set_modifier_input(modifier, modifier_input_identifier(group, "Subdivide"), 3)
|
|
obj.update_tag(refresh={"DATA"})
|
|
evaluated, result = evaluated_mesh(obj)
|
|
try:
|
|
assert len(result.polygons) == 128
|
|
assert len(result.vertices) == 153
|
|
finally:
|
|
evaluated.to_mesh_clear()
|
|
|
|
set_modifier_input(modifier, modifier_input_identifier(group, "Subdivide"), 2)
|
|
set_modifier_input(modifier, modifier_input_identifier(group, "Thickness"), 1.2)
|
|
obj.update_tag(refresh={"DATA"})
|
|
evaluated, result = evaluated_mesh(obj)
|
|
try:
|
|
assert result.materials[0].original == material
|
|
assert len(result.polygons) == 184
|
|
z_values = [vertex.co.z for vertex in result.vertices]
|
|
assert abs(min(z_values) + 0.6) < 1e-6
|
|
assert abs(max(z_values) - 0.6) < 1e-6
|
|
assert len({round(value, 6) for value in z_values}) == 6
|
|
edge_users = {edge.key: 0 for edge in result.edges}
|
|
for polygon in result.polygons:
|
|
for edge_key in polygon.edge_keys:
|
|
edge_users[edge_key] += 1
|
|
assert all(users == 2 for users in edge_users.values())
|
|
assert all(polygon.material_index == 0 for polygon in result.polygons)
|
|
finally:
|
|
evaluated.to_mesh_clear()
|
|
|
|
set_modifier_input(modifier, modifier_input_identifier(group, "Subdivide"), 0)
|
|
set_modifier_input(modifier, modifier_input_identifier(group, "Thickness"), 0.01)
|
|
obj.update_tag(refresh={"DATA"})
|
|
evaluated, result = evaluated_mesh(obj)
|
|
try:
|
|
z_values = {round(vertex.co.z, 6) for vertex in result.vertices}
|
|
assert len(z_values) >= 4
|
|
finally:
|
|
evaluated.to_mesh_clear()
|
|
|
|
if bpy.app.version >= (5, 0, 0):
|
|
assert group.library is not None
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|