feat: GPU rendering + material matching + perf improvements

- GPU: fix Cycles device activation order — set compute_device_type
  BEFORE engine init, re-set AFTER open_mainfile wipes preferences
- GPU: remove _mark_sharp_and_seams edit-mode loop (redundant with
  Blender 5.0 shade_smooth_by_angle), saves ~200s/render on 175 parts
- Material: fix _AFN suffix mismatch — build AF-stripped mat_map keys
  and add prefix fallback in _apply_material_library (blender_render.py)
- Material: production GLB now uses get_material_library_path() which
  checks active AssetLibrary instead of empty legacy system setting
- Admin: RenderTemplateTable multi-select output types (M2M frontend)
- Admin: MaterialLibraryPanel replaced with link to Asset Libraries
- UX: move Toaster to top-left to avoid dispatch button overlap
- SQLAlchemy: add .unique() to all RenderTemplate M2M collection queries
- Logging: flush=True on all Blender progress prints, stdout reconfigure

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-08 19:05:03 +01:00
parent 934728da77
commit ee6eb34b4c
34 changed files with 1274 additions and 511 deletions
+6
View File
@@ -97,3 +97,9 @@ export async function generateGltfProduction(cadFileId: string): Promise<Generat
const res = await api.post<GenerateGltfResponse>(`/cad/${cadFileId}/generate-gltf-production`)
return res.data
}
/** Force-reset a CAD file stuck in 'processing' to 'failed'. */
export async function resetStuckProcessing(cadFileId: string): Promise<{ status: string; message: string }> {
const res = await api.post(`/cad/${cadFileId}/reset-stuck`)
return res.data
}
+3 -1
View File
@@ -6,6 +6,8 @@ export interface RenderTemplate {
category_key: string | null;
output_type_id: string | null;
output_type_name: string | null;
output_type_ids: string[];
output_type_names: string[];
blend_file_path: string;
original_filename: string;
target_collection: string;
@@ -39,7 +41,7 @@ export async function createRenderTemplate(formData: FormData): Promise<RenderTe
export async function updateRenderTemplate(
id: string,
updates: Partial<Pick<RenderTemplate, 'name' | 'category_key' | 'output_type_id' | 'target_collection' | 'material_replace_enabled' | 'lighting_only' | 'shadow_catcher_enabled' | 'camera_orbit' | 'is_active'>>,
updates: Partial<Pick<RenderTemplate, 'name' | 'category_key' | 'output_type_ids' | 'target_collection' | 'material_replace_enabled' | 'lighting_only' | 'shadow_catcher_enabled' | 'camera_orbit' | 'is_active'>>,
): Promise<RenderTemplate> {
const { data } = await api.patch(`/render-templates/${id}`, updates);
return data;
+1 -1
View File
@@ -10,7 +10,7 @@ export interface WorkflowDefinition {
}
export interface WorkflowConfig {
type: 'still' | 'turntable' | 'multi_angle' | 'custom'
type: 'still' | 'turntable' | 'multi_angle' | 'still_with_exports' | 'custom'
params: WorkflowParams
nodes?: WorkflowNode[]
}