fix(export_gltf): use edit-mode mark_sharp+mark_seam for proper GLB sharp edges
Replace shade_smooth_by_angle with explicit edit-mode operators: - edges_select_sharp(angle) → mark_sharp() + mark_seam() - Produces vertex splits at sharp edges (6027 split positions verified) - Remove OCC custom_normal attribute before processing to prevent pre-baked normals overriding Blender's sharp edge processing - Update comment: calc_normals_split() removed in Blender 5.0 Verified: production GLB has 812 extra vertices vs geometry GLB, 6027 positions with multiple normals = sharp edges correctly encoded. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -130,21 +130,45 @@ def main() -> None:
|
||||
if cleared_normals:
|
||||
print(f"Cleared OCC custom_normal attribute from {cleared_normals} mesh objects")
|
||||
|
||||
# Apply smooth shading using the configured angle threshold
|
||||
# Mark sharp edges and seams using the configured angle threshold.
|
||||
# We use Blender's edit-mode operators (mark_sharp + mark_seam) rather than
|
||||
# shade_smooth_by_angle alone, because:
|
||||
# 1. mark_sharp() sets the sharp_edge boolean attribute on edges — the glTF
|
||||
# exporter creates vertex splits (duplicate vertices with different normals)
|
||||
# at sharp edges, which is how glTF encodes hard edges.
|
||||
# 2. mark_seam() ensures UV splits at the same edges (stepper-addon behaviour).
|
||||
# Note: calc_normals_split() was removed in Blender 5.0 — not needed here
|
||||
# because export_apply=True triggers vertex splitting automatically.
|
||||
smooth_rad = _math.radians(args.smooth_angle)
|
||||
print(f"Applying smooth shading at {args.smooth_angle}° ({smooth_rad:.3f} rad)")
|
||||
print(f"Marking sharp edges + seams at {args.smooth_angle}° ({smooth_rad:.3f} rad)")
|
||||
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
total_sharp = 0
|
||||
for obj in mesh_objects:
|
||||
bpy.context.view_layer.objects.active = obj
|
||||
obj.select_set(True)
|
||||
try:
|
||||
bpy.ops.object.shade_smooth_by_angle(angle=smooth_rad)
|
||||
except Exception:
|
||||
bpy.ops.object.shade_smooth()
|
||||
if hasattr(obj.data, 'use_auto_smooth'):
|
||||
obj.data.use_auto_smooth = True
|
||||
obj.data.auto_smooth_angle = smooth_rad
|
||||
|
||||
# Apply OCC sharp edges if available (overrides pure dihedral-angle shading)
|
||||
# Set all faces smooth
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
for poly in obj.data.polygons:
|
||||
poly.use_smooth = True
|
||||
|
||||
# Enter edit mode, deselect, select sharp edges by angle, mark sharp+seam
|
||||
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')
|
||||
|
||||
# Count how many edges were marked
|
||||
n_sharp = sum(1 for e in obj.data.edges if e.use_edge_sharp)
|
||||
total_sharp += n_sharp
|
||||
obj.select_set(False)
|
||||
|
||||
print(f"Marked {total_sharp} sharp/seam edges across {len(mesh_objects)} objects")
|
||||
|
||||
# Apply OCC sharp edges if available (additional explicit sharp edges from CAD data)
|
||||
sharp_pairs = mesh_attributes.get("sharp_edge_pairs") or []
|
||||
if sharp_pairs:
|
||||
_apply_sharp_edges_from_occ(mesh_objects, sharp_pairs)
|
||||
|
||||
Reference in New Issue
Block a user