Refactor image handling and update foreground processing

- Changed the logic in `remove_background_faces` to keep only faces with all foreground vertices.
- Updated background job to save foreground images with a new naming convention (`color.0001.png`).
- Replaced `copy_frames` with `copy_color_images` in various jobs to ensure consistent image naming.
- Introduced a new function `copy_color_images` to handle the copying of images with a specific naming format.
- Updated the BEN2 model to save output images with a new prefix for better clarity.
- Modified tests to reflect changes in image naming and processing logic.
- Added a new shadeless node group for improved material handling in geometry nodes.
- Enhanced validation scripts to check for new image naming conventions and ensure proper functionality.
This commit is contained in:
2026-08-19 01:45:59 +08:00
parent 835225d264
commit 20b653bb30
28 changed files with 663 additions and 383 deletions

View File

@@ -7,6 +7,7 @@ GROUP_NAME = "O DA3 Surface"
MOGE_SURFACE_GROUP_NAME = "O MoGe2 Surface"
DEPTH_PLANE_GROUP_NAME = "O DA3 Depth Plane"
MOGE_DEPTH_PLANE_GROUP_NAME = "O MoGe2 Depth Plane"
SHADELESS_GROUP_NAME = "O Shadeless"
MATERIAL_DISPLACEMENT_ATTRIBUTE = "o_material_displacement"
BACKGROUND_DEPTH_ATTRIBUTE = "o_background_depth"
DEPTH_SCALE_ATTRIBUTE = "o_depth_scale"
@@ -800,9 +801,9 @@ def build_depth_plane_group():
"NodeSocketImage",
parent=data_panel,
)
foreground_image = new_socket(
color_image = new_socket(
interface,
"Foreground Image",
"Color Image",
"INPUT",
"NodeSocketImage",
parent=data_panel,
@@ -835,7 +836,7 @@ def build_depth_plane_group():
socket.min_value = 1
frame_data.append(socket)
depth_image.hide_in_modifier = True
foreground_image.hide_in_modifier = True
color_image.hide_in_modifier = True
material.hide_in_modifier = True
for socket in frame_data:
socket.hide_in_modifier = True
@@ -848,7 +849,7 @@ def build_depth_plane_group():
images_input = new_group_input(
nodes,
(100.0, 1250.0),
{"Depth Image", "Foreground Image"},
{"Depth Image", "Color Image"},
)
frames_input = new_group_input(
nodes,
@@ -973,7 +974,7 @@ def build_depth_plane_group():
foreground_texture.location = (350.0, 900.0)
links.new(images_input.outputs["Depth Image"], depth_texture.inputs["Image"])
links.new(
images_input.outputs["Foreground Image"],
images_input.outputs["Color Image"],
foreground_texture.inputs["Image"],
)
links.new(grid.outputs["UV Map"], depth_texture.inputs["Vector"])
@@ -1141,10 +1142,13 @@ def build_moge_depth_plane_group():
depth_image = new_socket(
interface, "Depth Image", "INPUT", "NodeSocketImage", data_panel
)
color_image = new_socket(
interface, "Color Image", "INPUT", "NodeSocketImage", data_panel
)
material = new_socket(
interface, "Material", "INPUT", "NodeSocketMaterial", data_panel
)
for socket in (depth_image, material):
for socket in (depth_image, color_image, material):
socket.hide_in_modifier = True
frame_sockets = []
for name, socket_type, default in (
@@ -1176,7 +1180,7 @@ def build_moge_depth_plane_group():
background_depth_value.inputs[0],
)
images = new_group_input(
nodes, (-500.0, 1100.0), {"Depth Image"}
nodes, (-500.0, 1100.0), {"Depth Image", "Color Image"}
)
frames = new_group_input(
nodes,
@@ -1241,18 +1245,42 @@ def build_moge_depth_plane_group():
depth_texture.interpolation = "Linear"
depth_texture.extension = "EXTEND"
depth_texture.location = (-250.0, 1100.0)
color_texture = nodes.new("GeometryNodeImageTexture")
color_texture.interpolation = "Closest"
color_texture.extension = "EXTEND"
color_texture.location = (-250.0, 850.0)
links.new(images.outputs["Depth Image"], depth_texture.inputs["Image"])
links.new(images.outputs["Color Image"], color_texture.inputs["Image"])
links.new(grid.outputs["UV Map"], depth_texture.inputs["Vector"])
links.new(grid.outputs["UV Map"], color_texture.inputs["Vector"])
frame = build_sequence_frame(
nodes, links, frames.outputs["Frame"], frames, 1800.0
)
links.new(frame, depth_texture.inputs["Frame"])
links.new(frame, color_texture.inputs["Frame"])
clamp_depth = nodes.new("ShaderNodeMath")
clamp_depth.operation = "MAXIMUM"
clamp_depth.location = (0.0, 750.0)
links.new(depth_texture.outputs["Color"], clamp_depth.inputs[0])
links.new(background_depth_value.outputs[0], clamp_depth.inputs[1])
color_mask = new_compare(
nodes,
"FLOAT",
"GREATER_THAN",
(0.0, 1000.0),
0.5,
)
links.new(
color_texture.outputs["Alpha"],
input_socket(color_mask, "A", 0),
)
masked_depth = nodes.new("ShaderNodeMix")
masked_depth.data_type = "FLOAT"
masked_depth.location = (200.0, 850.0)
links.new(color_mask.outputs["Result"], masked_depth.inputs[0])
links.new(background_depth_value.outputs[0], masked_depth.inputs[2])
links.new(clamp_depth.outputs[0], masked_depth.inputs[3])
displacement_menu = nodes.new("GeometryNodeMenuSwitch")
displacement_menu.data_type = "FLOAT"
displacement_menu.enum_items.clear()
@@ -1276,7 +1304,7 @@ def build_moge_depth_plane_group():
scaled_depth = nodes.new("ShaderNodeMath")
scaled_depth.operation = "MULTIPLY"
scaled_depth.location = (250.0, 750.0)
links.new(clamp_depth.outputs[0], scaled_depth.inputs[0])
links.new(masked_depth.outputs["Result"], scaled_depth.inputs[0])
links.new(geometry_strength.outputs[0], scaled_depth.inputs[1])
normal = nodes.new("GeometryNodeInputNormal")
normal.location = (0.0, 500.0)
@@ -1320,6 +1348,80 @@ def build_moge_depth_plane_group():
return group
def build_shadeless_group():
group = bpy.data.node_groups.new(SHADELESS_GROUP_NAME, "ShaderNodeTree")
interface = group.interface
new_socket(interface, "Shader", "OUTPUT", "NodeSocketShader")
new_socket(interface, "Color", "INPUT", "NodeSocketColor")
nodes = group.nodes
links = group.links
group_input = nodes.new("NodeGroupInput")
group_input.location = (-900.0, -350.0)
group_output = nodes.new("NodeGroupOutput")
group_output.location = (850.0, 100.0)
diffuse = nodes.new("ShaderNodeBsdfDiffuse")
diffuse.location = (250.0, -150.0)
emission = nodes.new("ShaderNodeEmission")
emission.location = (250.0, -400.0)
links.new(group_input.outputs["Color"], diffuse.inputs["Color"])
links.new(group_input.outputs["Color"], emission.inputs["Color"])
light_path = nodes.new("ShaderNodeLightPath")
light_path.location = (-900.0, 150.0)
bounce_count = nodes.new("ShaderNodeMath")
bounce_count.operation = "SUBTRACT"
bounce_count.label = "Bounce Count"
bounce_count.location = (-500.0, -50.0)
links.new(light_path.outputs["Ray Depth"], bounce_count.inputs[0])
links.new(light_path.outputs["Transmission Depth"], bounce_count.inputs[1])
refracted = nodes.new("ShaderNodeMath")
refracted.operation = "SUBTRACT"
refracted.label = "Camera or Refracted"
refracted.inputs[0].default_value = 1.0
refracted.location = (-250.0, -50.0)
links.new(bounce_count.outputs[0], refracted.inputs[1])
reflection_limit = nodes.new("ShaderNodeMath")
reflection_limit.operation = "SUBTRACT"
reflection_limit.label = "Limit Reflections"
reflection_limit.inputs[0].default_value = 2.0
reflection_limit.location = (-650.0, 450.0)
links.new(light_path.outputs["Ray Depth"], reflection_limit.inputs[1])
camera_reflected = nodes.new("ShaderNodeMath")
camera_reflected.operation = "MULTIPLY"
camera_reflected.label = "Camera Ray to Glossy"
camera_reflected.location = (-400.0, 400.0)
links.new(reflection_limit.outputs[0], camera_reflected.inputs[0])
links.new(light_path.outputs["Is Glossy Ray"], camera_reflected.inputs[1])
shadow_or_reflect = nodes.new("ShaderNodeMath")
shadow_or_reflect.operation = "MAXIMUM"
shadow_or_reflect.label = "Shadow or Reflection?"
shadow_or_reflect.location = (-100.0, 350.0)
links.new(camera_reflected.outputs[0], shadow_or_reflect.inputs[0])
links.new(light_path.outputs["Is Shadow Ray"], shadow_or_reflect.inputs[1])
shader_factor = nodes.new("ShaderNodeMath")
shader_factor.operation = "MAXIMUM"
shader_factor.label = "Shadow, Reflect or Refract?"
shader_factor.location = (150.0, 300.0)
links.new(shadow_or_reflect.outputs[0], shader_factor.inputs[0])
links.new(refracted.outputs[0], shader_factor.inputs[1])
mix = nodes.new("ShaderNodeMixShader")
mix.location = (550.0, 100.0)
links.new(shader_factor.outputs[0], mix.inputs["Fac"])
links.new(diffuse.outputs["BSDF"], mix.inputs[1])
links.new(emission.outputs["Emission"], mix.inputs[2])
links.new(mix.outputs["Shader"], group_output.inputs["Shader"])
group.color_tag = "SHADER"
group.description = (
"Display color without scene lighting while preserving shadows "
"and reflections."
)
group.use_fake_user = True
return group
def main():
bpy.ops.wm.read_factory_settings(use_empty=True)
bpy.context.preferences.filepaths.save_version = 0
@@ -1336,6 +1438,7 @@ def main():
configure_moge_surface_group(moge_surface_group)
build_depth_plane_group()
build_moge_depth_plane_group()
build_shadeless_group()
OUTPUT_PATH.parent.mkdir(parents=True, exist_ok=True)
bpy.ops.wm.save_as_mainfile(filepath=str(OUTPUT_PATH), check_existing=False)