chore: Bump version to 0.12.13 and update documentation for color space handling

This commit is contained in:
2026-08-19 13:42:29 +08:00
parent c115498b5e
commit 753f87da03
20 changed files with 189 additions and 37 deletions

View File

@@ -24,7 +24,13 @@ MOGE_SURFACE_MATERIAL_NODE_GROUP_NAME = "O MoGe2 Surface Layer"
DEPTH_PLANE_MATERIAL_NODE_GROUP_NAME = "O DA3 Depth Plane Layer"
MOGE_MATERIAL_NODE_GROUP_NAME = "O MoGe2 Depth Plane Layer"
SHADELESS_NODE_GROUP_NAME = "O Shadeless"
MATERIAL_COLOR_SPACE = "AgX Base sRGB"
VIEW_TRANSFORM_COLOR_SPACES = (
("ACES 1.3", "ACES 1.3 sRGB"),
("ACES 2.0", "ACES 2.0 sRGB"),
("AgX", "AgX Base sRGB"),
("Filmic", "Filmic sRGB"),
("Khronos PBR Neutral", "Khronos PBR Neutral sRGB"),
)
DA3_PATCH_SIZE = 14
DA3_MIN_PROCESS_RES = 252
DA3_MAX_PROCESS_RES = 1008
@@ -70,6 +76,36 @@ def is_image_empty(candidate):
)
def material_color_space_name(scene):
view_settings = getattr(scene, "view_settings", None)
view_transform = getattr(view_settings, "view_transform", "")
normalized = str(view_transform).strip().casefold()
for view_name, color_space in VIEW_TRANSFORM_COLOR_SPACES:
if normalized.startswith(view_name.casefold()):
return color_space
return "AgX Base sRGB"
def set_material_color_space(image, scene=None):
if scene is None:
scene = getattr(bpy.context, "scene", None)
settings = image.colorspace_settings
preferred = material_color_space_name(scene)
original = settings.name
for color_space in dict.fromkeys(
(preferred, "AgX Base sRGB", "sRGB", original)
):
if not color_space:
continue
try:
settings.name = color_space
except (TypeError, ValueError):
continue
if settings.name == color_space:
return color_space
return settings.name
def is_animated_image(image):
return getattr(image, "source", None) in {"MOVIE", "SEQUENCE"}
@@ -978,6 +1014,7 @@ def create_moge_material(
frame_count=1,
frame_start=1,
use_cyclic=False,
scene=None,
):
material = bpy.data.materials.new(name)
material.use_nodes = True
@@ -990,7 +1027,7 @@ def create_moge_material(
uv.uv_map = "UVMap"
uv.location = (-900.0, 200.0)
color = nodes.new("ShaderNodeTexImage")
color_image.colorspace_settings.name = MATERIAL_COLOR_SPACE
set_material_color_space(color_image, scene)
color.image = color_image
color.interpolation = "Linear"
color.extension = "EXTEND"
@@ -1303,6 +1340,7 @@ def create_material(
use_cyclic=None,
surface_group_name=None,
normal_image=None,
scene=None,
):
material = bpy.data.materials.new(name)
material.use_nodes = True
@@ -1318,7 +1356,7 @@ def create_material(
uv_map.uv_map = "UVMap"
uv_map.location = (-1250.0, 350.0)
material_image = color_image
material_image.colorspace_settings.name = MATERIAL_COLOR_SPACE
set_material_color_space(material_image, scene)
color_texture.image = material_image
color_texture.interpolation = "Linear"
color_texture.extension = "EXTEND"
@@ -1730,6 +1768,7 @@ def build_image_depth_plane(
depth_frame_offset=texture_frame_offset,
depth_frame_duration=texture_frame_count,
use_cyclic=source_use_cyclic,
scene=context.scene,
)
mesh.materials.append(material)
add_depth_plane_processing(
@@ -1834,6 +1873,7 @@ def build_depth_plane(
depth_frame_offset=0,
depth_frame_duration=frame_count,
use_cyclic=source_use_cyclic,
scene=context.scene,
)
mesh.materials.append(material)
add_depth_plane_processing(
@@ -1939,6 +1979,7 @@ def build_moge2_depth_plane(
frame_count=len(depth),
frame_start=source_frame_start,
use_cyclic=source_use_cyclic,
scene=context.scene,
)
mesh.materials.append(material)
modifier = add_moge_depth_plane_processing(

View File

@@ -456,6 +456,7 @@ def build_image_mesh(
MOGE_SURFACE_MATERIAL_NODE_GROUP_NAME if moge2 else None
),
normal_image=normal_image,
scene=context.scene,
)
mesh.materials.append(material)
mesh_object["snapform_reference_depth"] = reference_depth

View File

@@ -1,7 +1,7 @@
schema_version = "1.0.0"
id = "snapform"
version = "0.12.12"
version = "0.12.13"
name = "SnapForm"
tagline = "Build spatial structures from images, fast"
maintainer = "OmooLab"

View File

@@ -4,6 +4,12 @@ from contextlib import contextmanager
from ..media import prepare_input
def frame_progress_message(message, index, total):
if total > 1:
return f"{message} ({index + 1}/{total})"
return message
@contextmanager
def input_frames(context, parameters):
images, temporary_directory = prepare_input(

View File

@@ -1,7 +1,7 @@
from ..media import copy_color_images
from ..models import da3, geometry_adapter, moge2
from ..outputs.depth import write_da3_depth, write_moge_depth
from .common import input_frames
from .common import frame_progress_message, input_frames
from .foreground import write_optional
@@ -18,7 +18,7 @@ def run(context, parameters):
images,
progress_callback=lambda index, total: context.progress(
0.15 + 0.65 * index / total,
f"Estimating DA3 depth ({index + 1}/{total})",
frame_progress_message("Estimating DA3 depth", index, total),
),
cancel_check=context.check_cancelled,
)
@@ -31,7 +31,7 @@ def run(context, parameters):
include_points=False,
progress_callback=lambda index, total: context.progress(
0.15 + 0.65 * index / total,
f"Estimating MoGe-2 depth ({index + 1}/{total})",
frame_progress_message("Estimating MoGe-2 depth", index, total),
),
cancel_check=context.check_cancelled,
)

View File

@@ -2,17 +2,9 @@ from ..geometry import build_surface, foreground_mesh_mask
from ..media import copy_color_images
from ..models import geometry_adapter, moge2
from ..outputs.surface import write_normal_texture, write_surface_archive
from .common import input_frames
from .common import frame_progress_message, input_frames
from .foreground import write_optional
def inference_progress_message(model_name, index, total):
message = f"Estimating {model_name} geometry"
if total > 1:
message += f" ({index + 1}/{total})"
return message
def run(context, parameters):
context.progress(0.02, "Preparing surface input")
context.directory.mkdir(parents=True, exist_ok=True)
@@ -30,7 +22,7 @@ def run(context, parameters):
include_points=True,
progress_callback=lambda index, total: context.progress(
0.12 + 0.58 * index / total,
inference_progress_message("MoGe-2", index, total),
frame_progress_message("Estimating MoGe-2 geometry", index, total),
),
cancel_check=context.check_cancelled,
)
@@ -41,7 +33,7 @@ def run(context, parameters):
images,
progress_callback=lambda index, total: context.progress(
0.12 + 0.58 * index / total,
inference_progress_message("DA3", index, total),
frame_progress_message("Estimating DA3 geometry", index, total),
),
cancel_check=context.check_cancelled,
)

View File

@@ -1,5 +1,12 @@
"""Shared ONNX Runtime session helpers."""
COREML_PROVIDER_OPTIONS = {
"ModelFormat": "MLProgram",
"MLComputeUnits": "ALL",
"RequireStaticInputShapes": "0",
"EnableOnSubgraphs": "0",
}
def select_providers(requested, available):
available = set(available)
@@ -40,6 +47,12 @@ def create_session(path, requested_device="auto"):
requested_device,
onnxruntime.get_available_providers(),
)
providers = [
(provider, dict(COREML_PROVIDER_OPTIONS))
if provider == "CoreMLExecutionProvider"
else provider
for provider in providers
]
return onnxruntime.InferenceSession(str(path), providers=providers)