Add tests for foreground preservation and refactor geometry node asset
- Implement test to ensure foreground preserves source RGB and Ben2 alpha in WorkerTest. - Remove outdated tests related to background distance and original background depth. - Update geometry node asset to reflect new naming conventions and structure. - Introduce validation for depth plane asset, ensuring correct input/output configurations and attribute handling. - Adjust confidence and edge parameters in geometry node asset to support a wider range of values.
This commit is contained in:
249
tools/validate_depth_plane_asset.py
Normal file
249
tools/validate_depth_plane_asset.py
Normal file
@@ -0,0 +1,249 @@
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
import bpy
|
||||
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parents[1] / "src"))
|
||||
|
||||
from snapform.image_depth import (
|
||||
DEPTH_PLANE_MATERIAL_NODE_GROUP_NAME,
|
||||
SURFACE_MATERIAL_NODE_GROUP_NAME,
|
||||
add_depth_plane_processing,
|
||||
create_material,
|
||||
load_depth_plane_node_group,
|
||||
modifier_input_identifier,
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
bpy.ops.wm.read_factory_settings(use_empty=True)
|
||||
group = load_depth_plane_node_group()
|
||||
background_depth = next(
|
||||
item
|
||||
for item in group.interface.items_tree
|
||||
if item.item_type == "SOCKET"
|
||||
and item.in_out == "INPUT"
|
||||
and item.name == "Background Depth"
|
||||
)
|
||||
assert background_depth.subtype == "DISTANCE"
|
||||
geometry_input = next(
|
||||
item
|
||||
for item in group.interface.items_tree
|
||||
if item.item_type == "SOCKET"
|
||||
and item.in_out == "INPUT"
|
||||
and item.name == "Geometry"
|
||||
)
|
||||
assert geometry_input.structure_type == "SINGLE"
|
||||
all_inputs = [
|
||||
(item.name, getattr(item.parent, "name", None), item.hide_in_modifier)
|
||||
for item in group.interface.items_tree
|
||||
if item.item_type == "SOCKET"
|
||||
and item.in_out == "INPUT"
|
||||
]
|
||||
visible_inputs = [name for name, parent, hidden in all_inputs if not hidden]
|
||||
assert visible_inputs[:6] == [
|
||||
"Geometry",
|
||||
"Displacement",
|
||||
"Depth Scale",
|
||||
"Subdivision",
|
||||
"Remove Background",
|
||||
"Background Depth",
|
||||
]
|
||||
remove_background = next(
|
||||
item
|
||||
for item in group.interface.items_tree
|
||||
if item.item_type == "SOCKET"
|
||||
and item.in_out == "INPUT"
|
||||
and item.name == "Remove Background"
|
||||
)
|
||||
assert remove_background.socket_type == "NodeSocketBool"
|
||||
assert remove_background.is_panel_toggle
|
||||
assert remove_background.parent.name == "Remove Background"
|
||||
assert background_depth.parent == remove_background.parent
|
||||
depth_scale = next(
|
||||
item
|
||||
for item in group.interface.items_tree
|
||||
if item.item_type == "SOCKET"
|
||||
and item.in_out == "INPUT"
|
||||
and item.name == "Depth Scale"
|
||||
)
|
||||
assert depth_scale.default_value == 1.0
|
||||
assert depth_scale.min_value < 0.0
|
||||
assert depth_scale.structure_type == "SINGLE"
|
||||
stores = {
|
||||
node.inputs["Name"].default_value: node
|
||||
for node in group.nodes
|
||||
if node.bl_idname == "GeometryNodeStoreNamedAttribute"
|
||||
}
|
||||
attribute_names = (
|
||||
"o_remove_background",
|
||||
"o_material_displacement",
|
||||
"o_background_depth",
|
||||
"o_depth_scale",
|
||||
)
|
||||
for name in attribute_names:
|
||||
assert stores[name].domain == "POINT"
|
||||
assert not any(
|
||||
node.bl_idname == "GeometryNodeGeometryToInstance"
|
||||
for node in group.nodes
|
||||
)
|
||||
|
||||
mesh = bpy.data.meshes.new("Depth Plane")
|
||||
mesh.from_pydata(
|
||||
[(-1, -1, 0), (1, -1, 0), (-1, 1, 0), (1, 1, 0)],
|
||||
[],
|
||||
[(0, 1, 3, 2)],
|
||||
)
|
||||
obj = bpy.data.objects.new("Depth Plane", mesh)
|
||||
bpy.context.scene.collection.objects.link(obj)
|
||||
depth = bpy.data.images.new("Depth", width=2, height=2, float_buffer=True)
|
||||
depth.pixels[:] = [0.25, 0.25, 0.25, 1.0] * 4
|
||||
foreground = bpy.data.images.new("Foreground", width=2, height=2)
|
||||
foreground.pixels[:] = [0.8, 0.2, 0.1, 1.0] * 4
|
||||
foreground.alpha_mode = "CHANNEL_PACKED"
|
||||
material = create_material(
|
||||
"Depth Plane",
|
||||
foreground,
|
||||
1.0,
|
||||
displacement_image=depth,
|
||||
foreground_image=foreground,
|
||||
)
|
||||
mesh.materials.append(material)
|
||||
material_group = bpy.data.node_groups[DEPTH_PLANE_MATERIAL_NODE_GROUP_NAME]
|
||||
interface_inputs = [
|
||||
item.name
|
||||
for item in material_group.interface.items_tree
|
||||
if item.item_type == "SOCKET"
|
||||
and item.in_out == "INPUT"
|
||||
]
|
||||
interface_outputs = [
|
||||
item.name
|
||||
for item in material_group.interface.items_tree
|
||||
if item.item_type == "SOCKET"
|
||||
and item.in_out == "OUTPUT"
|
||||
]
|
||||
assert interface_inputs == [
|
||||
"Color",
|
||||
"Alpha",
|
||||
"Depth",
|
||||
"Bump Scale",
|
||||
]
|
||||
assert interface_outputs == [
|
||||
"Color",
|
||||
"Roughness",
|
||||
"Alpha",
|
||||
"Normal",
|
||||
"Displacement",
|
||||
]
|
||||
depth_input = next(
|
||||
item
|
||||
for item in material_group.interface.items_tree
|
||||
if item.item_type == "SOCKET"
|
||||
and item.in_out == "INPUT"
|
||||
and item.name == "Depth"
|
||||
)
|
||||
assert depth_input.socket_type == "NodeSocketFloat"
|
||||
bump_scale = next(
|
||||
item
|
||||
for item in material_group.interface.items_tree
|
||||
if item.item_type == "SOCKET"
|
||||
and item.in_out == "INPUT"
|
||||
and item.name == "Bump Scale"
|
||||
)
|
||||
assert bump_scale.default_value == 1.0
|
||||
assert bump_scale.min_value < 0.0
|
||||
material_group_nodes = [
|
||||
node
|
||||
for node in material.node_tree.nodes
|
||||
if node.bl_idname == "ShaderNodeGroup"
|
||||
and node.node_tree == material_group
|
||||
]
|
||||
assert len(material_group_nodes) == 1
|
||||
assert material_group_nodes[0].name == "O DA3 Depth Plane"
|
||||
attributes = [
|
||||
node
|
||||
for node in material_group.nodes
|
||||
if node.bl_idname == "ShaderNodeAttribute"
|
||||
]
|
||||
assert len(attributes) == 4
|
||||
assert all(node.attribute_type == "GEOMETRY" for node in attributes)
|
||||
assert not any(
|
||||
node.bl_idname == "ShaderNodeAttribute"
|
||||
for node in material.node_tree.nodes
|
||||
)
|
||||
forbidden_outer_nodes = {
|
||||
"ShaderNodeAttribute",
|
||||
"ShaderNodeBump",
|
||||
"ShaderNodeDisplacement",
|
||||
"ShaderNodeFloatCurve",
|
||||
"ShaderNodeMath",
|
||||
"ShaderNodeMix",
|
||||
}
|
||||
assert not any(
|
||||
node.bl_idname in forbidden_outer_nodes
|
||||
for node in material.node_tree.nodes
|
||||
)
|
||||
surface_material = create_material("Surface", foreground, 1.0)
|
||||
surface_group = bpy.data.node_groups[SURFACE_MATERIAL_NODE_GROUP_NAME]
|
||||
surface_group_nodes = [
|
||||
node
|
||||
for node in surface_material.node_tree.nodes
|
||||
if node.bl_idname == "ShaderNodeGroup"
|
||||
and node.node_tree == surface_group
|
||||
]
|
||||
assert len(surface_group_nodes) == 1
|
||||
assert surface_group_nodes[0].name == "O DA3 Surface"
|
||||
surface_depth_input = next(
|
||||
item
|
||||
for item in surface_group.interface.items_tree
|
||||
if item.item_type == "SOCKET"
|
||||
and item.in_out == "INPUT"
|
||||
and item.name == "Depth"
|
||||
)
|
||||
assert surface_depth_input.socket_type == "NodeSocketFloat"
|
||||
assert not any(
|
||||
node.bl_idname in forbidden_outer_nodes
|
||||
for node in surface_material.node_tree.nodes
|
||||
)
|
||||
modifier = add_depth_plane_processing(obj, depth, foreground, material)
|
||||
modifier[modifier_input_identifier(group, "Depth Scale")] = -2.0
|
||||
for name, expected in (
|
||||
("Frame Start", 1),
|
||||
("Frames", 1),
|
||||
("Cyclic", False),
|
||||
):
|
||||
assert modifier[modifier_input_identifier(group, name)] == expected
|
||||
image_textures = [
|
||||
node
|
||||
for node in group.nodes
|
||||
if node.bl_idname == "GeometryNodeImageTexture"
|
||||
]
|
||||
assert len(image_textures) == 2
|
||||
assert all(node.inputs["Frame"].is_linked for node in image_textures)
|
||||
assert image_textures[0].inputs["Frame"].links[0].from_socket == (
|
||||
image_textures[1].inputs["Frame"].links[0].from_socket
|
||||
)
|
||||
floored_modulo = [
|
||||
node
|
||||
for node in group.nodes
|
||||
if node.bl_idname == "ShaderNodeMath"
|
||||
and node.operation == "FLOORED_MODULO"
|
||||
]
|
||||
assert len(floored_modulo) == 1
|
||||
bpy.context.view_layer.objects.active = obj
|
||||
obj.select_set(True)
|
||||
result = bpy.ops.object.modifier_apply(modifier=modifier.name)
|
||||
assert result == {"FINISHED"}
|
||||
assert not obj.modifiers
|
||||
assert obj.type == "MESH"
|
||||
assert len(obj.data.vertices) > 4
|
||||
for name in attribute_names:
|
||||
assert obj.data.attributes[name].domain == "POINT"
|
||||
assert all(polygon.use_smooth for polygon in obj.data.polygons)
|
||||
assert material in obj.data.materials[:]
|
||||
print("Depth plane asset validation passed")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user