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

@@ -64,19 +64,19 @@ Bump 合并;网格本身不写入 custom normal,因此重拓扑降低顶点
当前此功能仅支持单张图片。
MoGe-2 ViT-S、ViT-B、ViT-L、DA3 Small、DA3 Base 与 BEN2 全部使用 ONNX。模型执行、相机与深度恢复、
点云重投影和网格生成均不依赖 PyTorch。Windows 使用 DirectML 加速,provider 不可用时会回退到 ONNX Runtime CPU,
点云重投影和网格生成均不依赖 PyTorch。Windows 使用 DirectML 加速,macOS 使用 CoreML 的 `MLProgram` 模型格式;provider 不可用时会回退到 ONNX Runtime CPU,
并在任务状态中显示实际 provider。
转换对话框提供模型与 `Create Matching Camera`、`Remove Background`、`Shadeless`;DA3 显示
`Resolution Scale`,MoGe-2 显示 `Resolution Level`,
以及分割线下方的 `Keep Original`。
界面会显示计算所得的实际 Process Res。剔除和重拓扑参数直接在
Geometry Nodes 修改器中调整;`Shadeless` 与 Depth Plane 共用 `O Shadeless` 材质节点组。颜色贴图始终使用统一的 `.color` 转换产物;Remove Background 只决定是否由 BEN2 修改 Alpha,并使用 `AgX Base sRGB`。普通材质的
Geometry Nodes 修改器中调整;`Shadeless` 与 Depth Plane 共用 `O Shadeless` 材质节点组。颜色贴图始终使用统一的 `.color` 转换产物;Remove Background 只决定是否由 BEN2 修改 Alpha。颜色贴图会按当前场景的 View Transform 选择对应输入色彩空间:AgX、ACES 1.3、ACES 2.0、Filmic、Khronos PBR Neutral 分别使用 `AgX Base sRGB`、`ACES 1.3 sRGB`、`ACES 2.0 sRGB`、`Filmic sRGB`、`Khronos PBR Neutral sRGB`;无法匹配当前 View Transform 时回退 `AgX Base sRGB`;当前 Blender 连该选项也不支持时才安全回退 `sRGB`。普通材质的
Bump Scale 会在材质组内乘以 `0.001`,并按透视表面的深度空间缩放。Surface 与 Depth Plane 的
Layer Color 同时驱动 Principled BSDF 的 Base Color、Subsurface Radius 和 Emission Color,Layer Normal
同时驱动 Normal 与 Coat Normal;Subsurface、Emission、Coat 的其他设置保持默认。Surface attributes
统一使用 `o_` 前缀;Server 准备过程显示
`Preparing surface data n/6`,可看到当前阶段与总步骤;Surface 单帧模型推理不显示多余的 `1/1`。
`Preparing surface data n/6`,可看到当前阶段与总步骤;Surface 与 Depth 单帧模型推理都不显示多余的 `1/1`。
### 视频与序列帧

View File

@@ -19,7 +19,7 @@
`Keep Original` 默认关闭,并在分割线下方保持为最后一项。仅当开启 `Remove Background` 时才需要
`BEN2 Base`,并把 `.color` 的 Alpha 作为独立 Mask,不在 Server 中改写深度值。无论颜色层是直接
复制原图,还是由 BEN2 为单图或序列修改 Alpha,Server 都统一写为 `color.0001.*`;Blender 只导入
这一份 `.color`,不复用源 Empty 的 Image,Color Space 固定为 `AgX Base sRGB`。
这一份 `.color`,不复用源 Empty 的 Image。颜色贴图会按当前场景的 View Transform 选择对应输入色彩空间:AgX、ACES 1.3、ACES 2.0、Filmic、Khronos PBR Neutral 分别使用 `AgX Base sRGB`、`ACES 1.3 sRGB`、`ACES 2.0 sRGB`、`Filmic sRGB`、`Khronos PBR Neutral sRGB`;无法匹配当前 View Transform 时回退 `AgX Base sRGB`;当前 Blender 连该选项也不支持时才安全回退 `sRGB`。
Image Empty 引用视频或序列帧时,DA3 与 MoGe-2 会按 Empty 的 Image Frames 数值逐帧估计
深度(未设置时为完整帧数,显式设为 1 时只处理 1 帧),起始帧跟随 Empty 的 Offset,与背景蒙版范围一致;
DA3 会复用同一个 ONNX Session 对每帧独立推理,再合并为原有序列输出,避免多帧 Attention 的平方级显存占用。
@@ -30,7 +30,7 @@
一致;Original 模式的视频或序列帧使用 `color.0001.*` 颜色层同时作为颜色与深度输入;开启
Remove Background 时同名颜色层包含 BEN2 修改后的 Alpha。
DA3 的深度仍以 EXR 序列帧(`depth.0001.exr` 起)保存在 job 目录根下;MoGe-2 分别使用 `moge_depth`、`moge_mask` 与 `moge_normal` EXR 序列。
`Shadeless`、`Remove Background` 与 `Keep Original` 均默认关闭,因此默认删除原对象。`Shadeless` 会以 `O Shadeless` 节点组替代普通 Principled BSDF 路径,并继续通过 Alpha 与 Transparent BSDF 混合。
DA3 与 MoGe-2 的单帧推理进度只显示模型与阶段名称,不追加 `1/1`;多帧时继续显示当前帧与总数。`Shadeless`、`Remove Background` 与 `Keep Original` 均默认关闭,因此默认删除原对象。`Shadeless` 会以 `O Shadeless` 节点组替代普通 Principled BSDF 路径,并继续通过 Alpha 与 Transparent BSDF 混合。
3. DA3 或 MoGe-2 完成后会自动创建面片。DA3 面片几何先由 `mini_npz` 的相机内参与深度确定,再通过对象
Transform 匹配原 Image Empty 的可见尺寸、位置、旋转和 Offset。Original 模式直接使用源 Empty
的可见尺寸、Offset 与 Transform。DA3 会把用于匹配画面尺寸的缩放预乘到 `.depth` 数值,

View File

@@ -109,7 +109,7 @@ uv run pytest tests/test_addon.py tests/test_manifest.py tests/test_pack.py -v
uv run python pack.py
```
`pack.py` 根据 `blender_manifest.toml` 分别生成 Windows、macOS 和 Linux 扩展包,例如 `dist/SnapForm.v0.12.11.windows-x64.zip`。更换 `src/snapform/wheels/` 中随扩展分发的 wheel 后,先刷新锁文件再测试:
`pack.py` 根据 `blender_manifest.toml` 分别生成 Windows、macOS 和 Linux 扩展包,例如 `dist/SnapForm.v0.12.13.windows-x64.zip`。更换 `src/snapform/wheels/` 中随扩展分发的 wheel 后,先刷新锁文件再测试:
```bash
uv lock --refresh

View File

@@ -53,7 +53,7 @@
## 使用
1. 运行 `uv run python pack.py`,分别构建 `windows-x64`、`macos-arm64`、
`linux-x64` 三个平台的 Extension ZIP(如 `SnapForm.v0.12.11.macos-arm64.zip`)。
`linux-x64` 三个平台的 Extension ZIP(如 `SnapForm.v0.12.13.macos-arm64.zip`)。
安装包不携带 uv 或 AI 项目源码;首次安装 Environment 时下载固定版本 uv,并校验固定 SHA-256。官方安装按钮使用 GitHub、uv 默认 Python 下载源和 PyPI;镜像按钮使用 CNB uv Release、CNB Python 解释器镜像和清华 PyPI。
2. 在 Blender 的 `Preferences > Extensions` 中选择 `Install from Disk`。
3. 在 Extension Preferences 中确认 Storage Root 与 Device。Device 是正式功能

View File

@@ -63,7 +63,7 @@ ONNX 实现位于 `models/`;纯投影、网格与唯一 Surface Builder 位于
运行环境不安装 PyTorch、TorchVision、xFormers,也不安装 DA3、MoGe、BEN2 或 utils3d 的 Python 源码包。模型推理和 SnapForm 所需的相机、点云、网格后处理均由 ONNX Runtime、NumPy 与内部实现完成。
Windows 当前发行环境提供 DirectML 与 CPU;`Auto` 优先使用 `DmlExecutionProvider`。显式指定不可用设备时会安全回退到 CPU。其他平台安装标准 ONNX Runtime,并按可用 provider 选择 CoreML、OpenVINO 或 CPU。
Windows 当前发行环境提供 DirectML 与 CPU;`Auto` 优先使用 `DmlExecutionProvider`。显式指定不可用设备时会安全回退到 CPU。其他平台安装标准 ONNX Runtime,并按可用 provider 选择 CoreML、OpenVINO 或 CPU。macOS 的 CoreML Session 使用 `MLProgram` 模型格式与全部可用计算单元,允许动态输入 Shape;未被 CoreML 接管的节点继续由 CPU 执行。
`environment.json` 保存规范化后的声明,`manifest.json` 保存该声明与基础 Server packages 的 Hash。Python、packages、平台 packages、基础 Server packages 或 Environment Schema 改变后需要重新执行 `Install Environment`,不再维护手工 Manifest Revision。BlendJob 直接随 Extension 更新,不参与 Environment Hash。

View File

@@ -49,7 +49,7 @@
6. Server 在 job 根目录写出 `mesh.npz`。NPZ 保存 camera-space `vertices`、`faces`、`uv`、
`intrinsics`、`image_size` 与有效深度中位数 `reference_depth`。颜色层无论来自原图复制还是 BEN2,
Server 都统一写为 `color.0001.*`。Blender 读取网格数据后额外导入为 `.color`,材质不复用源
Empty 的 Image,Color Space 固定为 `AgX Base sRGB`。Server 不生成 `texture.png`,材质只在
Empty 的 Image。颜色贴图会按当前场景的 View Transform 选择对应输入色彩空间:AgX、ACES 1.3、ACES 2.0、Filmic、Khronos PBR Neutral 分别使用 `AgX Base sRGB`、`ACES 1.3 sRGB`、`ACES 2.0 sRGB`、`Filmic sRGB`、`Khronos PBR Neutral sRGB`;无法匹配当前 View Transform 时回退 `AgX Base sRGB`;当前 Blender 连该选项也不支持时才安全回退 `sRGB`。 Server 不生成 `texture.png`,材质只在
Blender 端创建。
DA3 Surface 只保留 Geometry Nodes 后处理实际使用的 attributes:点域 `o_depth`、面域
`o_confidence` 与面域 `o_depth_discontinuity`。Remove Background 已在 Server
@@ -67,7 +67,7 @@
`Remove Background`、`Shadeless`,以及分割线下方的 `Keep Original`。背景移除默认关闭;开启后 Server
使用 BEN2,并在写出 Surface 前直接删除背景三角面,不再由 Geometry Nodes 的 Background 开关处理。
该预删除同时适用于 DA3 与 MoGe-2;因此 MoGe-2 转换后即使关闭 `Mask`,BEN2 已删除的背景也不会恢复。
Surface 材质的 Color Image Texture 始终使用 `.color`;Remove Background 只决定该层是否带 BEN2 Alpha,原 Empty 始终保持原图。颜色层使用 `AgX Base sRGB`。
Surface 材质的 Color Image Texture 始终使用 `.color`;Remove Background 只决定该层是否带 BEN2 Alpha,原 Empty 始终保持原图。颜色贴图会按当前场景的 View Transform 选择对应输入色彩空间:AgX、ACES 1.3、ACES 2.0、Filmic、Khronos PBR Neutral 分别使用 `AgX Base sRGB`、`ACES 1.3 sRGB`、`ACES 2.0 sRGB`、`Filmic sRGB`、`Khronos PBR Neutral sRGB`;无法匹配当前 View Transform 时回退 `AgX Base sRGB`;当前 Blender 连该选项也不支持时才安全回退 `sRGB`。
`Shadeless` 使用与 Depth Plane 相同的 `O Shadeless` 节点组,并继续通过 Alpha 与 Transparent BSDF 混合;普通材质的
Bump Scale 按 `abs(object.scale.z) × camera scale_z` 设置,并在材质组内乘以固定基准 `0.001`,
与透视表面实际深度尺度一致;它允许负数以反转凹凸方向。

View File

@@ -1,6 +1,6 @@
[project]
name = "snapform"
version = "0.12.12"
version = "0.12.13"
description = "Fast image-guided structure building tools for Blender"
readme = "README.md"
requires-python = ">=3.11"

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)

View File

@@ -42,6 +42,52 @@ class ImageDepthTest(unittest.TestCase):
def setUpClass(cls):
cls.image_depth = load_image_depth()
def test_material_color_space_matches_scene_view_transform(self):
mappings = {
"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",
"Standard": "AgX Base sRGB",
}
for view_transform, expected in mappings.items():
with self.subTest(view_transform=view_transform):
scene = SimpleNamespace(
view_settings=SimpleNamespace(
view_transform=view_transform,
)
)
self.assertEqual(
self.image_depth.material_color_space_name(scene),
expected,
)
def test_material_color_space_falls_back_when_unsupported(self):
class ColorSpaceSettings:
def __init__(self):
self._name = "sRGB"
@property
def name(self):
return self._name
@name.setter
def name(self, value):
if value != "sRGB":
raise TypeError("unsupported color space")
self._name = value
image = SimpleNamespace(colorspace_settings=ColorSpaceSettings())
scene = SimpleNamespace(
view_settings=SimpleNamespace(view_transform="ACES 2.0")
)
result = self.image_depth.set_material_color_space(image, scene)
self.assertEqual(result, "sRGB")
self.assertEqual(image.colorspace_settings.name, "sRGB")
def test_extracts_depth_and_uses_first_view(self):
with tempfile.TemporaryDirectory() as directory:
npz_path = Path(directory) / "results.npz"

View File

@@ -76,6 +76,34 @@ class MogeOnnxTest(unittest.TestCase):
["DmlExecutionProvider", "CPUExecutionProvider"],
)
def test_coreml_session_uses_mlprogram(self):
calls = []
fake_runtime = ModuleType("onnxruntime")
fake_runtime.get_available_providers = lambda: [
"CoreMLExecutionProvider",
"CPUExecutionProvider",
]
fake_runtime.InferenceSession = lambda path, providers: calls.append(
(path, providers)
)
with patch.dict(sys.modules, {"onnxruntime": fake_runtime}):
self.moge.create_runtime_session("model.onnx")
self.assertEqual(calls[0][0], "model.onnx")
self.assertEqual(
calls[0][1][0],
(
"CoreMLExecutionProvider",
{
"ModelFormat": "MLProgram",
"MLComputeUnits": "ALL",
"RequireStaticInputShapes": "0",
"EnableOnSubgraphs": "0",
},
),
)
def test_explicit_unavailable_provider_falls_back_to_cpu(self):
providers = self.moge.select_providers(
"cuda",

View File

@@ -118,6 +118,7 @@ class WorkerTest(unittest.TestCase):
cls.surface_outputs = load_server_module("outputs.surface")
cls.debug_da3_outputs = load_server_module("outputs.debug_da3")
cls.debug_moge2_outputs = load_server_module("outputs.debug_moge2")
cls.common_job = load_server_module("jobs.common")
cls.depth_job = load_server_module("jobs.depth")
cls.surface_job = load_server_module("jobs.surface")
cls.debug_da3_job = load_server_module("jobs.debug_da3")
@@ -127,20 +128,39 @@ class WorkerTest(unittest.TestCase):
cls.foreground_job = load_server_module("jobs.foreground")
cls.download = load_server_module("model_download")
def test_surface_inference_progress_omits_single_frame_count(self):
def test_inference_progress_omits_single_frame_count(self):
self.assertEqual(
self.surface_job.inference_progress_message("MoGe-2", 0, 1),
self.common_job.frame_progress_message(
"Estimating MoGe-2 geometry", 0, 1
),
"Estimating MoGe-2 geometry",
)
self.assertEqual(
self.surface_job.inference_progress_message("DA3", 0, 1),
self.common_job.frame_progress_message(
"Estimating DA3 geometry", 0, 1
),
"Estimating DA3 geometry",
)
self.assertEqual(
self.surface_job.inference_progress_message("DA3", 1, 3),
self.common_job.frame_progress_message(
"Estimating DA3 geometry", 1, 3
),
"Estimating DA3 geometry (2/3)",
)
self.assertEqual(
self.common_job.frame_progress_message(
"Estimating MoGe-2 depth", 0, 1
),
"Estimating MoGe-2 depth",
)
self.assertEqual(
self.common_job.frame_progress_message(
"Estimating DA3 depth", 0, 1
),
"Estimating DA3 depth",
)
def test_surface_has_one_model_independent_builder(self):
self.assertTrue(callable(self.surface.build_surface))
self.assertTrue(callable(self.surface_outputs.write_surface_archive))

View File

@@ -13,7 +13,7 @@ sys.path.insert(
from snapform.blender.depth_plane import (
DEPTH_PLANE_MATERIAL_NODE_GROUP_NAME,
MATERIAL_COLOR_SPACE,
material_color_space_name,
SHADELESS_NODE_GROUP_NAME,
SURFACE_MATERIAL_NODE_GROUP_NAME,
add_depth_plane_processing,
@@ -273,7 +273,9 @@ def main():
"Shadow or Reflection?": "MAXIMUM",
"Shadow, Reflect or Refract?": "MAXIMUM",
}
assert foreground.colorspace_settings.name == MATERIAL_COLOR_SPACE
assert foreground.colorspace_settings.name == material_color_space_name(
bpy.context.scene
)
surface_material = create_material("Surface", foreground, 1.0)
surface_group = bpy.data.node_groups[SURFACE_MATERIAL_NODE_GROUP_NAME]
surface_group_nodes = [

View File

@@ -14,6 +14,7 @@ sys.path.insert(
)
from snapform.blender.depth_plane import MOGE_SURFACE_MATERIAL_NODE_GROUP_NAME
from snapform.blender.depth_plane import material_color_space_name
from snapform.blender.surface import (
MOGE_NODE_GROUP_NAME,
build_image_mesh,
@@ -198,7 +199,9 @@ def main():
if node.bl_idname == "ShaderNodeTexImage" and node.image == foreground
)
assert color_texture.image.name == "MoGe Surface Test.color"
assert color_texture.image.colorspace_settings.name == "AgX Base sRGB"
assert color_texture.image.colorspace_settings.name == material_color_space_name(
bpy.context.scene
)
normal_texture = next(
node for node in surface.data.materials[0].node_tree.nodes
if node.bl_idname == "ShaderNodeTexImage"

2
uv.lock generated
View File

@@ -305,7 +305,7 @@ wheels = [
[[package]]
name = "snapform"
version = "0.12.11"
version = "0.12.13"
source = { virtual = "." }
dependencies = [
{ name = "blendjob" },