Refactor and enhance SnapForm functionality

- Introduced MODEL_NUMBERS for better model indexing.
- Improved enum_items function to cache results and handle download status.
- Updated ActiveJob class to manage temporary input paths and added displacement_via property.
- Changed IMAGE_DEPTH_PROCESS_RES_METHOD from "lower_bound_resize" to "upper_bound_resize".
- Enhanced RunJob operator to include new properties and improved error messages.
- Modified panel layout for better user experience and added runtime installation checks.
- Updated SnapFormSettings to reflect new model properties and defaults.
- Added temporary input path management in runtime.
- Refined worker functions to improve error handling and messaging.
- Expanded tests to cover new functionality and ensure backward compatibility.
- Fixed packaging script to align with versioning conventions.
This commit is contained in:
2026-08-03 13:47:15 +08:00
parent b02372c457
commit a503786c62
14 changed files with 827 additions and 174 deletions

View File

@@ -11,7 +11,7 @@ from .models import get_model, selected_model_key
RECONSTRUCTION_JOB = "RECONSTRUCT"
IMAGE_DEPTH_JOB = "IMAGE_DEPTH"
IMAGE_DEPTH_DEFAULT_PROCESS_RES = 1024
IMAGE_DEPTH_PROCESS_RES_METHOD = "lower_bound_resize"
IMAGE_DEPTH_PROCESS_RES_METHOD = "upper_bound_resize"
def open_job_directory(result_directory):
@@ -36,6 +36,8 @@ class ActiveJob:
process_res: int = IMAGE_DEPTH_DEFAULT_PROCESS_RES
subdivision_level: int = 5
delete_source: bool = True
displacement_via: str = "MODIFIER"
temporary_input_path: Path | None = None
cancelled: bool = False
@@ -62,6 +64,11 @@ def close_active_job():
if _active_job is None:
return
_active_job.log_file.close()
if _active_job.temporary_input_path is not None:
try:
_active_job.temporary_input_path.unlink(missing_ok=True)
except OSError:
pass
_active_job = None
@@ -98,20 +105,32 @@ class RunJob(bpy.types.Operator):
)
snapform_process_res: bpy.props.IntProperty(
default=IMAGE_DEPTH_DEFAULT_PROCESS_RES,
min=14,
max=2016,
min=1,
max=65_536,
options={"HIDDEN", "SKIP_SAVE"},
)
snapform_delete_source: bpy.props.BoolProperty(
default=True,
options={"HIDDEN", "SKIP_SAVE"},
)
snapform_delete_input: bpy.props.BoolProperty(
default=False,
options={"HIDDEN", "SKIP_SAVE"},
)
snapform_subdivision_level: bpy.props.IntProperty(
default=5,
min=0,
max=10,
options={"HIDDEN", "SKIP_SAVE"},
)
snapform_displacement_via: bpy.props.EnumProperty(
items=(
("MODIFIER", "Modifier", ""),
("MATERIAL", "Material", ""),
),
default="MODIFIER",
options={"HIDDEN", "SKIP_SAVE"},
)
def execute(self, context):
global _active_job
@@ -138,7 +157,7 @@ class RunJob(bpy.types.Operator):
)
except OSError as error:
log_file.close()
self.report({"ERROR"}, f"Unable to start DA3 task: {error}")
self.report({"ERROR"}, f"Unable to start task: {error}")
return {"CANCELLED"}
_active_job = ActiveJob(
@@ -157,6 +176,13 @@ class RunJob(bpy.types.Operator):
process_res=self.snapform_process_res,
subdivision_level=self.snapform_subdivision_level,
delete_source=self.snapform_delete_source,
displacement_via=self.snapform_displacement_via,
temporary_input_path=(
Path(self.snapform_input_path)
if self.job_type == IMAGE_DEPTH_JOB
and self.snapform_delete_input
else None
),
)
settings.status = self._starting_message(settings)
settings.progress = 0.0
@@ -245,9 +271,9 @@ class RunJob(bpy.types.Operator):
"DOWNLOAD_MODEL": "Starting model download",
}
if self.job_type == RECONSTRUCTION_JOB:
return f"Starting DA3 {settings.export_format} export"
return f"Starting {settings.export_format} export"
if self.job_type == IMAGE_DEPTH_JOB:
return "Starting DA3 image depth conversion"
return "Starting depth estimation"
if self.job_type == "DOWNLOAD_MODEL":
return f"Starting {get_model(self.model_key).label} download"
return labels[self.job_type]
@@ -298,7 +324,7 @@ class RunJob(bpy.types.Operator):
settings.progress = 0.0
self.report(
{"ERROR"},
f"{error or 'DA3 subprocess failed'}; log: {job.log_path}",
f"{error or 'Task subprocess failed'}; log: {job.log_path}",
)
close_active_job()
self._redraw_ui(context, force=True)
@@ -326,7 +352,7 @@ class RunJob(bpy.types.Operator):
close_active_job()
self._redraw_ui(context, force=True)
return {"CANCELLED"}
status["message"] = "DA3 depth plane is ready"
status["message"] = "Depth plane is ready"
settings.status = status.get("message", "Task complete")
settings.progress = 1.0
@@ -346,6 +372,7 @@ class RunJob(bpy.types.Operator):
snapform_npz_path=str(npz_path),
snapform_subdivision_level=job.subdivision_level,
snapform_delete_source=job.delete_source,
snapform_displacement_via=job.displacement_via,
)
if "FINISHED" not in result:
raise RuntimeError("Unable to build the depth plane")