feat: Implement cutout tool and depth generation features

- Added a new cutout tool for selecting regions in images, allowing users to choose mesh shapes based on selected areas.
- Introduced depth generation capabilities for rasterized images, including normal data extraction.
- Created jobs for generating depth planes and region data, enhancing the AI data generation workflow.
- Developed a selection refinement process for cutout regions, improving accuracy in generated outputs.
- Established a new region module for handling rasterized image regions and their associated AI generation tasks.
- Enhanced node graph builders for asset generation, facilitating smoother integration of new features.
This commit is contained in:
2026-08-30 23:09:13 +08:00
parent 32bcd45d7b
commit 08309f719d
88 changed files with 4145 additions and 5639 deletions

View File

@@ -2,8 +2,33 @@
import bpy
from ..common.node_asset import load_mesh_plane_node_group
from ..common.node_graph import group_input, interface_socket
from ..common.mesh_result import load_asset_node_group
MESH_PLANE_NODE_GROUP_NAME = "O Mesh Plane"
def mesh_plane_node_group():
return load_asset_node_group(MESH_PLANE_NODE_GROUP_NAME)
def _interface_socket(group, name, in_out, socket_type):
socket = group.interface.new_socket(
name=name,
in_out=in_out,
socket_type=socket_type,
)
if in_out == "INPUT" and hasattr(socket, "structure_type"):
socket.structure_type = "SINGLE"
return socket
def _group_input(nodes, location, visible_names):
node = nodes.new("NodeGroupInput")
node.location = location
visible = set(visible_names)
for output in node.outputs:
output.hide = output.name not in visible
return node
def depth_plane_node_group():
group_name = "O Image Depth Plane"
@@ -16,42 +41,42 @@ def depth_plane_node_group():
group.nodes.clear()
group.interface.clear()
group.is_modifier = True
interface_socket(group, "Geometry", "INPUT", "NodeSocketGeometry")
subdivide = interface_socket(group, "Subdivide", "INPUT", "NodeSocketInt")
_interface_socket(group, "Geometry", "INPUT", "NodeSocketGeometry")
subdivide = _interface_socket(group, "Subdivide", "INPUT", "NodeSocketInt")
subdivide.default_value = 7
subdivide.min_value = 0
subdivide.max_value = 10
thickness = interface_socket(group, "Thickness", "INPUT", "NodeSocketFloat")
thickness = _interface_socket(group, "Thickness", "INPUT", "NodeSocketFloat")
thickness.default_value = 0.1
thickness.min_value = 0.0
thickness.subtype = "DISTANCE"
depth_amount = interface_socket(group, "Depth Amount", "INPUT", "NodeSocketFloat")
depth_amount = _interface_socket(group, "Depth Amount", "INPUT", "NodeSocketFloat")
depth_amount.default_value = 1.0
depth_amount.min_value = 0.0
depth_image = interface_socket(group, "Depth Image", "INPUT", "NodeSocketImage")
depth_image = _interface_socket(group, "Depth Image", "INPUT", "NodeSocketImage")
depth_image.hide_in_modifier = True
material = interface_socket(group, "Material", "INPUT", "NodeSocketMaterial")
material = _interface_socket(group, "Material", "INPUT", "NodeSocketMaterial")
material.hide_in_modifier = True
interface_socket(group, "Geometry", "OUTPUT", "NodeSocketGeometry")
_interface_socket(group, "Geometry", "OUTPUT", "NodeSocketGeometry")
nodes = group.nodes
links = group.links
geometry_input = group_input(
geometry_input = _group_input(
nodes,
(-1850.0, 450.0),
{"Geometry", "Subdivide", "Material"},
)
shape_input = group_input(
shape_input = _group_input(
nodes,
(-1250.0, 850.0),
{"Thickness", "Depth Amount"},
)
image_input = group_input(nodes, (-1050.0, 50.0), {"Depth Image"})
cleanup_input = group_input(nodes, (650.0, -200.0), {"Thickness"})
image_input = _group_input(nodes, (-1050.0, 50.0), {"Depth Image"})
cleanup_input = _group_input(nodes, (650.0, -200.0), {"Thickness"})
group_output = nodes.new("NodeGroupOutput")
group_output.location = (1600.0, 450.0)
mesh_plane = nodes.new("GeometryNodeGroup")
mesh_plane.node_tree = load_mesh_plane_node_group()
mesh_plane.node_tree = mesh_plane_node_group()
mesh_plane.inputs["Thickness"].default_value = 0.0
mesh_plane.location = (-1550.0, 450.0)
links.new(geometry_input.outputs["Geometry"], mesh_plane.inputs["Geometry"])
@@ -150,7 +175,7 @@ def depth_plane_node_group():
def plane_node_group(shape):
if shape == "PLANE":
return load_mesh_plane_node_group()
return mesh_plane_node_group()
if shape == "DEPTH_PLANE":
return depth_plane_node_group()
raise ValueError(f"Unsupported Plane shape: {shape}")