- Implemented `cutout_depth_surface.py` for face separation and connected thickness calculations for depth surface assets. - Created `cutout_depth_surface_layout.py` to arrange nodes for staggered calculation branches in depth surface processing. - Authored `geometry_layouts.py` to define layouts for various geometry assets, including image cutouts and depth planes. - Introduced `node_layout.py` for shared presentation rules, facilitating node arrangement and validation in geometry-node layouts.
157 lines
4.8 KiB
Python
157 lines
4.8 KiB
Python
import sys
|
|
from pathlib import Path
|
|
|
|
import bpy
|
|
|
|
PROJECT_ROOT = Path(__file__).parents[2]
|
|
sys.path.insert(0, str(Path(__file__).parent))
|
|
sys.path.insert(0, str(PROJECT_ROOT / "src"))
|
|
sys.path.insert(
|
|
0,
|
|
str(next((PROJECT_ROOT / "src" / "anyimage" / "wheels").glob("blendjob-*.whl"))),
|
|
)
|
|
|
|
from node_layout import validate_node_layout
|
|
from anyimage.common.material import (
|
|
DEPTH_MATERIAL_NODE_GROUP_NAME,
|
|
IMAGE_MATERIAL_NODE_GROUP_NAME,
|
|
)
|
|
from anyimage.common.node import load_node_group, node_asset_path
|
|
from anyimage.operators.cutout_tool.shape import (
|
|
CUTOUT_NODE_GROUP_NAME,
|
|
CUTOUT_NODE_GROUP_NAMES,
|
|
)
|
|
|
|
|
|
DEPTH_PLANE_NODE_GROUP_NAME = "O Image Depth Plane"
|
|
|
|
|
|
def input_names(group):
|
|
return [
|
|
item.name
|
|
for item in group.interface.items_tree
|
|
if item.item_type == "SOCKET" and item.in_out == "INPUT"
|
|
]
|
|
|
|
|
|
def main():
|
|
bpy.ops.wm.read_factory_settings(use_empty=True)
|
|
mesh_plane = load_node_group("O Mesh Plane")
|
|
depth_plane = load_node_group(DEPTH_PLANE_NODE_GROUP_NAME)
|
|
image_layer = load_node_group(IMAGE_MATERIAL_NODE_GROUP_NAME)
|
|
depth_layer = load_node_group(DEPTH_MATERIAL_NODE_GROUP_NAME)
|
|
shadeless = load_node_group("O Shadeless")
|
|
cutout = load_node_group(CUTOUT_NODE_GROUP_NAME)
|
|
cutout_groups = {
|
|
name: bpy.data.node_groups[name] for name in CUTOUT_NODE_GROUP_NAMES.values()
|
|
}
|
|
expected_names = {
|
|
"O Mesh Plane",
|
|
DEPTH_PLANE_NODE_GROUP_NAME,
|
|
IMAGE_MATERIAL_NODE_GROUP_NAME,
|
|
DEPTH_MATERIAL_NODE_GROUP_NAME,
|
|
"O Shadeless",
|
|
CUTOUT_NODE_GROUP_NAME,
|
|
*CUTOUT_NODE_GROUP_NAMES.values(),
|
|
}
|
|
with bpy.data.libraries.load(str(node_asset_path()), link=False) as (source, _):
|
|
assert set(source.node_groups) == expected_names
|
|
|
|
assert mesh_plane.name == "O Mesh Plane"
|
|
assert mesh_plane.bl_idname == "GeometryNodeTree"
|
|
assert mesh_plane.is_modifier
|
|
assert input_names(mesh_plane) == [
|
|
"Geometry",
|
|
"Subdivide",
|
|
"Thickness",
|
|
]
|
|
assert depth_plane.bl_idname == "GeometryNodeTree"
|
|
assert depth_plane.is_modifier
|
|
assert input_names(depth_plane) == [
|
|
"Geometry",
|
|
"Subdivide",
|
|
"Thickness",
|
|
"Depth Scale",
|
|
"Reference Depth",
|
|
"Uniform Scale",
|
|
"Depth Image",
|
|
]
|
|
depth_panels = [
|
|
item for item in depth_plane.interface.items_tree if item.item_type == "PANEL"
|
|
]
|
|
assert [panel.name for panel in depth_panels] == ["Options", "Data"]
|
|
assert [item.name for item in depth_panels[0].interface_items] == [
|
|
"Reference Depth"
|
|
]
|
|
assert [item.name for item in depth_panels[1].interface_items] == [
|
|
"Uniform Scale",
|
|
"Depth Image",
|
|
]
|
|
assert all(panel.default_closed for panel in depth_panels)
|
|
assert all(item.hide_in_modifier for item in depth_panels[1].interface_items)
|
|
depth_subdivide = next(
|
|
item
|
|
for item in depth_plane.interface.items_tree
|
|
if item.item_type == "SOCKET" and item.name == "Subdivide"
|
|
)
|
|
assert depth_subdivide.default_value == 6
|
|
assert image_layer.bl_idname == "ShaderNodeTree"
|
|
assert input_names(image_layer) == [
|
|
"Color",
|
|
"Alpha",
|
|
"Normal",
|
|
"Normal Scale",
|
|
"Object Space",
|
|
"Bump Scale",
|
|
]
|
|
assert depth_layer.bl_idname == "ShaderNodeTree"
|
|
assert input_names(depth_layer) == [
|
|
"Color",
|
|
"Alpha",
|
|
"Depth",
|
|
"Bump Scale",
|
|
]
|
|
assert shadeless.name == "O Shadeless"
|
|
assert shadeless.bl_idname == "ShaderNodeTree"
|
|
assert input_names(shadeless) == ["Color"]
|
|
|
|
assert cutout.name == CUTOUT_NODE_GROUP_NAME
|
|
assert cutout.bl_idname == "GeometryNodeTree"
|
|
assert cutout.is_modifier
|
|
assert input_names(cutout)[:4] == [
|
|
"Geometry",
|
|
"Shape",
|
|
"Inward Axis",
|
|
"Thickness",
|
|
]
|
|
assert set(cutout_groups) == set(CUTOUT_NODE_GROUP_NAMES.values())
|
|
for group in cutout_groups.values():
|
|
assert group.bl_idname == "GeometryNodeTree"
|
|
assert not group.is_modifier
|
|
assert input_names(group)[0] == "Geometry"
|
|
|
|
public_groups = {
|
|
mesh_plane,
|
|
depth_plane,
|
|
image_layer,
|
|
depth_layer,
|
|
shadeless,
|
|
cutout,
|
|
}
|
|
loaded = {*public_groups, *cutout_groups.values()}
|
|
for group in loaded:
|
|
if group.bl_idname == "GeometryNodeTree":
|
|
validate_node_layout(group)
|
|
assert all(group.use_fake_user for group in public_groups)
|
|
assert all(group.users > 0 for group in cutout_groups.values())
|
|
if bpy.app.version >= (5, 0, 0):
|
|
assert all(group.library is not None for group in loaded)
|
|
print(
|
|
f"Validated Blender {bpy.app.version_string}: "
|
|
+ ", ".join(sorted(group.name for group in loaded))
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|