From 202b06a0268abad38e2ab7cd6aee49bdf90420c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hartmut=20N=C3=B6renberg?= Date: Wed, 11 Mar 2026 11:38:47 +0100 Subject: [PATCH] feat(export_gltf): embed sharp angle in GLB extras + restore script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add export_extras=True to bpy.ops.export_scene.gltf() call - Store schaeffler_sharp_angle_deg in scene custom props before export → value is embedded in scenes[0].extras in the GLB JSON chunk → survives import/export round-trip intact (verified: 30.0 restored) - Add tools/restore_sharp_marks.py: companion Blender script that reads the angle from scene.get("schaeffler_sharp_angle_deg") and re-applies mark_sharp() + mark_seam() on all mesh objects after GLB import GLB format cannot store per-edge sharp/seam flags natively; the visual shading is correct via vertex splits. The extras + restore script give users the ability to reconstruct Edit Mode markers without a second format. Co-Authored-By: Claude Sonnet 4.6 --- render-worker/scripts/export_gltf.py | 10 +++++- tools/restore_sharp_marks.py | 46 ++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 tools/restore_sharp_marks.py diff --git a/render-worker/scripts/export_gltf.py b/render-worker/scripts/export_gltf.py index c2457eb..33ab485 100644 --- a/render-worker/scripts/export_gltf.py +++ b/render-worker/scripts/export_gltf.py @@ -281,7 +281,14 @@ def main() -> None: except Exception: pass # non-critical; export proceeds regardless - # Export production GLB with full PBR material data + # Store the sharp angle in the scene so it is embedded in the GLB extras. + # After importing the production GLB in Blender, running restore_sharp_marks.py + # reads this value and re-applies mark_sharp()+mark_seam() on all mesh objects. + bpy.context.scene["schaeffler_sharp_angle_deg"] = args.smooth_angle + + # Export production GLB with full PBR material data. + # export_extras=True embeds scene custom properties (incl. schaeffler_sharp_angle_deg) + # in the glTF scenes[0].extras JSON field, surviving the round-trip intact. try: bpy.ops.export_scene.gltf( filepath=args.output_path, @@ -290,6 +297,7 @@ def main() -> None: use_selection=False, export_materials="EXPORT", export_image_format="AUTO", + export_extras=True, ) except Exception as exc: print(f"GLB export failed: {exc}", file=sys.stderr) diff --git a/tools/restore_sharp_marks.py b/tools/restore_sharp_marks.py new file mode 100644 index 0000000..635daf2 --- /dev/null +++ b/tools/restore_sharp_marks.py @@ -0,0 +1,46 @@ +"""Blender companion script: restore sharp + seam edge marks after importing a production GLB. + +After importing a Schaeffler production GLB in Blender, run this script once via +the Scripting workspace (Text Editor → Run Script). It reads the sharp angle that +was baked into the GLB at export time and re-applies mark_sharp() + mark_seam() on +every mesh object. + +The GLB visual shading already encodes the sharp edges via vertex splits (normals). +This script restores the blue sharp-crease and red seam markers in Edit Mode for +further editing in Blender. + +Usage: + 1. File → Import → glTF 2.0 (.glb) — open your production GLB + 2. Open the Scripting workspace + 3. Open this file (Text Editor → Open → restore_sharp_marks.py) + 4. Click Run Script +""" + +import bpy +import math + +angle_deg = bpy.context.scene.get("schaeffler_sharp_angle_deg", 30.0) +smooth_rad = math.radians(float(angle_deg)) + +mesh_objects = [o for o in bpy.data.objects if o.type == "MESH"] +if not mesh_objects: + print("No mesh objects found in scene.") +else: + total_sharp = 0 + bpy.ops.object.select_all(action="DESELECT") + for obj in mesh_objects: + bpy.context.view_layer.objects.active = obj + obj.select_set(True) + bpy.ops.object.mode_set(mode="OBJECT") + for poly in obj.data.polygons: + poly.use_smooth = True + bpy.ops.object.mode_set(mode="EDIT") + bpy.ops.mesh.select_all(action="DESELECT") + bpy.ops.mesh.edges_select_sharp(sharpness=smooth_rad) + bpy.ops.mesh.mark_sharp() + bpy.ops.mesh.mark_seam() + bpy.ops.object.mode_set(mode="OBJECT") + total_sharp += sum(1 for e in obj.data.edges if e.use_edge_sharp) + obj.select_set(False) + print(f"Restored sharp/seam marks at {angle_deg}°: " + f"{total_sharp} edges across {len(mesh_objects)} objects.")