Refactor Cutout and Image Editing Logic

- Renamed "Base Plane Depth" to "Reference Depth" across validate_cutout.py for consistency.
- Introduced a new specification for Cutout mesh sampling to ensure source pixel spacing is preserved and limits are applied correctly.
- Unified naming conventions for image editing results to maintain consistency across Remove Background, Upscale, and Crop operations.
- Updated the handling of Refine Selection to ensure it retains the original bounds and does not apply unnecessary cropping.
- Enhanced material generation logic to connect image color directly to IOR Level, improving the rendering of dark areas.
- Established clear requirements for geometry depth controls and image result materials to ensure consistent behavior across different components.
- Removed outdated logic and ensured all changes are documented and tested for regression.
This commit is contained in:
2026-09-03 01:02:10 +08:00
parent a6041cbe03
commit bdbde1a10d
47 changed files with 1120 additions and 257 deletions

View File

@@ -405,7 +405,7 @@ def load_normal_result_image(path, source_object):
return image
def create_pixel_result_image(source_image, pixels, output_size, suffix=""):
def create_image_edit_result(source_image, pixels, output_size):
"""Create a packed Image datablock from edited RGBA pixels."""
output_width, output_height = (int(value) for value in output_size)
if output_width <= 0 or output_height <= 0:
@@ -413,7 +413,7 @@ def create_pixel_result_image(source_image, pixels, output_size, suffix=""):
if len(pixels) != output_width * output_height * 4:
raise ValueError("The edited pixels do not match the image dimensions")
image = bpy.data.images.new(
f"{image_base_name(source_image)}{suffix}",
source_image.name,
width=output_width,
height=output_height,
alpha=True,
@@ -525,11 +525,12 @@ def place_empty_image_result(
def load_color_result_image(
def _load_packed_result_image(
source_object,
output_directory,
*,
frame_prefix="image.",
frame_prefix,
result_name,
):
output_directory = Path(output_directory)
color_paths = sorted_frame_paths(output_directory, frame_prefix)
@@ -555,7 +556,6 @@ def load_color_result_image(
raise RuntimeError("Unable to load the color result") from error
try:
result_name = color_data_name(source_object)
if animated:
pack_sequence_if_possible(result_image, len(color_paths))
else:
@@ -567,6 +567,36 @@ def load_color_result_image(
return result_image
def load_image_edit_result(
source_object,
output_directory,
*,
frame_prefix="image.",
):
"""Load one packed Job result that directly edits the source Image."""
return _load_packed_result_image(
source_object,
output_directory,
frame_prefix=frame_prefix,
result_name=source_object.data.name,
)
def load_color_result_image(
source_object,
output_directory,
*,
frame_prefix="image.",
):
"""Load one packed Color texture result for a generated material."""
return _load_packed_result_image(
source_object,
output_directory,
frame_prefix=frame_prefix,
result_name=color_data_name(source_object),
)
def image_empty_bounds(source_object):
image_width, image_height = source_object.data.size
if image_width <= 0 or image_height <= 0: