feat(D): OCC mesh attribute extraction + Blender smooth shading integration

Migration 039: cad_files.mesh_attributes JSONB column.
domains/products/tasks.py: extract_mesh_attributes Celery task using pythonOCC.
still_render.py + turntable_render.py: _apply_mesh_attributes() sets auto-smooth
based on curved_ratio and topology threshold from OCC analysis.
render_blender.py: passes --mesh-attributes JSON arg to Blender subprocess.
render_still_task: loads mesh_attributes from DB and passes to renderer.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-06 17:07:55 +01:00
parent 7e47e4aca7
commit 716451ff76
8 changed files with 207 additions and 1 deletions
+35
View File
@@ -157,6 +157,28 @@ def _scale_mm_to_m(parts):
print(f"[turntable_render] scaled {len(parts)} parts mm→m (×0.001)")
def _apply_mesh_attributes(objects: list, mesh_attributes: dict) -> None:
"""Apply topology-based shading settings from OCC analysis."""
import math
if not mesh_attributes or mesh_attributes.get("error"):
return
curved_ratio = mesh_attributes.get("curved_ratio", 0.0)
threshold_deg = mesh_attributes.get("sharp_angle_threshold_deg", 30.0)
threshold_rad = threshold_deg * math.pi / 180.0
for obj in objects:
if obj.type != 'MESH':
continue
# Enable smooth shading for predominantly curved parts (bearings etc.)
if curved_ratio > 0.3:
for poly in obj.data.polygons:
poly.use_smooth = True
# Auto-smooth at topology threshold
obj.data.use_auto_smooth = True
obj.data.auto_smooth_angle = threshold_rad
def _import_stl(stl_file):
"""Import STL into Blender, using per-part STLs if available.
@@ -351,6 +373,15 @@ def main():
bg_color = args[21] if len(args) > 21 else ""
transparent_bg = args[22] == "1" if len(args) > 22 else False
# Named argument: --mesh-attributes <json>
_mesh_attrs: dict = {}
if "--mesh-attributes" in argv:
_idx = argv.index("--mesh-attributes")
try:
_mesh_attrs = json.loads(argv[_idx + 1])
except Exception:
pass
os.makedirs(frames_dir, exist_ok=True)
try:
@@ -402,6 +433,8 @@ def main():
_scale_mm_to_m(parts)
# Apply render position rotation before material/camera setup
_apply_rotation(parts, rotation_x, rotation_y, rotation_z)
# Apply OCC topology-based shading overrides
_apply_mesh_attributes(parts, _mesh_attrs)
# Move imported parts into target collection
for part in parts:
@@ -480,6 +513,8 @@ def main():
_scale_mm_to_m(parts)
# Apply render position rotation before material/camera setup
_apply_rotation(parts, rotation_x, rotation_y, rotation_z)
# Apply OCC topology-based shading overrides
_apply_mesh_attributes(parts, _mesh_attrs)
for i, part in enumerate(parts):
_apply_smooth(part, SMOOTH_ANGLE)