Bug 1 — Missing parts (mirror/repeated instances):
- id(solid.TShape()) is unreliable in OCP: each call creates a new
Python wrapper, so id() always differs even for the same TShape.
Replaced with IsSame() for correct TShape-pointer deduplication.
- TopExp_Explorer(SOLID) misses free shells/faces in assemblies.
Fix: run BRepMesh baseline on full root compound first (catches all
face types), then GMSH overrides per unique solid for better seam
topology. REVERSED solids keep BRepMesh to avoid inverted Jacobians.
Bug 2 — GLB 7× too large (21 MB vs OCC 3 MB):
- CharacteristicLengthMax = linear_deflection × 50 (was ×15)
matches OCC effective edge length on curved surfaces (~5 mm).
- MinimumCirclePoints = min(12, ...) (was min(20, ...))
- Result: GMSH 91% of OCC file size (target ≤120% ✓)
Verified on rolling bearing STEP: same 4 skipped nodes as OCC,
25 unique GMSH tessellations (IsSame deduplication), no OOM.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Introduces GMSH as an alternative to OCC BRepMesh for STEP→GLB tessellation.
GMSH produces conforming meshes that eliminate fan triangles at cylinder seam
edges — a structural limitation of OCC BRepMesh that cannot be fixed via
deflection parameters.
Changes:
- render-worker/Dockerfile: install gmsh>=4.15.0 + libglu1-mesa + libxft2
- export_step_to_gltf.py: --tessellation_engine occ|gmsh CLI arg +
_tessellate_with_gmsh() using BRep→GMSH→Poly_Triangulation write-back
- admin.py: tessellation_engine setting (SETTINGS_DEFAULTS, SettingsOut,
SettingsUpdate, validation)
- export_glb.py: pass tessellation_engine to export_step_to_gltf.py CLI in
both geometry and production GLB tasks
- Admin.tsx: radio button UI for OCC vs GMSH selection
Tested: 121 faces meshed, 0 BRepMesh fallback, 649K triangles on sample part.
Clean seam edges for UV unwrap — GMSH respects B-rep periodic face boundaries.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 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>
4 root causes fixed:
1. export_colors=False was removed in Blender 4.x — caused every Blender
export to fail (exit 1) and always fall back to trimesh. Remove it.
Blender now runs the full pipeline: materials + sharp edges.
2. GlbModel cloned ref never reset on url change — key={glbBlobUrl} forces
React to remount GlbModel on each new blob URL, resetting the ref so
fresh geometry is always loaded.
3. glbBlobUrl not cleared before re-fetch — setGlbBlobUrl(null) added at
start of downloadUrl effect so spinner shows instead of stale mesh.
4. staleTime: 30_000 delayed picking up new MediaAsset after generation.
Changed to staleTime: 0 so invalidation always triggers immediate refetch.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Bug A: Media Library thumbnails were gray because <img src> cannot send
JWT auth headers. Added useAuthBlob() hook (fetch + createObjectURL) in
MediaBrowser.tsx. Also fixed publish_asset Celery task to populate
product_id + cad_file_id on MediaAsset for thumbnail fallback resolution.
Bug B: Product dimensions now shown in Product Details card with Ruler
icon and "from CAD" label when cad_mesh_attributes.dimensions_mm exists.
Bug C: Replaced 128×128 CAD thumbnail with InlineCadViewer component.
Queries gltf_geometry MediaAssets, fetches GLB via auth fetch → blob URL
→ Three.js Canvas with OrbitControls. Falls back to thumbnail + "Load 3D
Model" button. Polling when GLB generation is in progress.
Bug D: trimesh was in [cad] optional extra but Dockerfile only installed
[dev]. Changed to pip install -e ".[dev,cad]" — trimesh now available in
backend container, GLB + Colors export works.
Also added bbox extraction (STL-first numpy parsing) in render_step_thumbnail
and admin "Re-extract CAD Metadata" bulk endpoint.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>