fix(export_gltf): clear OCC custom_normal attribute before sharp edge processing
The geometry GLB from export_step_to_gltf.py contains a 'custom_normal' attribute (CORNER, INT16_2D) from OCC tessellation. If left in place, Blender's glTF exporter re-exports these pre-baked normals unchanged — ignoring shade_smooth_by_angle processing and our explicit sharp edge marks. Fix: remove the 'custom_normal' attribute from all imported mesh objects immediately after GLB import, before applying smooth shading. Also add orphans_purge() before export to remove palette materials (mat_0/1/2/3) that become users=0 after library material substitution. Same custom_normal clearing applied to blender_render.py for thumbnail renders. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -342,6 +342,16 @@ def _import_glb(glb_file):
|
||||
print(f"[blender_render] imported {len(parts)} part(s) from GLB: "
|
||||
f"{[p.name for p in parts[:5]]}")
|
||||
|
||||
# Remove OCC-baked custom normals so shade_smooth_by_angle can recompute
|
||||
# normals from scratch (respecting our sharp edge marks).
|
||||
cleared = 0
|
||||
for p in parts:
|
||||
if "custom_normal" in p.data.attributes:
|
||||
p.data.attributes.remove(p.data.attributes["custom_normal"])
|
||||
cleared += 1
|
||||
if cleared:
|
||||
print(f"[blender_render] cleared OCC custom_normal from {cleared} mesh objects")
|
||||
|
||||
# Centre combined bbox at world origin
|
||||
all_corners = []
|
||||
for p in parts:
|
||||
|
||||
@@ -116,6 +116,20 @@ def main() -> None:
|
||||
mesh_objects = [o for o in bpy.data.objects if o.type == "MESH"]
|
||||
print(f"Imported geometry GLB: {args.glb_path} ({len(mesh_objects)} mesh objects)")
|
||||
|
||||
# Remove OCC-baked custom normals from the geometry GLB.
|
||||
# RWGltf_CafWriter embeds per-corner normals from OCC tessellation as a
|
||||
# 'custom_normal' attribute (CORNER, INT16_2D). If left in place, Blender's
|
||||
# glTF exporter re-exports these pre-baked normals unchanged, ignoring our
|
||||
# shade_smooth_by_angle processing and sharp edge marks entirely.
|
||||
# Removing this attribute forces Blender to recompute normals from scratch.
|
||||
cleared_normals = 0
|
||||
for obj in mesh_objects:
|
||||
if "custom_normal" in obj.data.attributes:
|
||||
obj.data.attributes.remove(obj.data.attributes["custom_normal"])
|
||||
cleared_normals += 1
|
||||
if cleared_normals:
|
||||
print(f"Cleared OCC custom_normal attribute from {cleared_normals} mesh objects")
|
||||
|
||||
# Apply smooth shading using the configured angle threshold
|
||||
smooth_rad = _math.radians(args.smooth_angle)
|
||||
print(f"Applying smooth shading at {args.smooth_angle}° ({smooth_rad:.3f} rad)")
|
||||
@@ -235,6 +249,14 @@ def main() -> None:
|
||||
if fallback:
|
||||
print(f"Single-material fallback: applied '{default_mat_name}' to {fallback} unmatched objects")
|
||||
|
||||
# Purge orphan data-blocks (palette materials mat_0/mat_1/... from the geometry
|
||||
# GLB that now have users=0 after library material substitution).
|
||||
# This prevents stale materials from appearing as duplicates in the export.
|
||||
try:
|
||||
bpy.ops.outliner.orphans_purge(do_recursive=True)
|
||||
except Exception:
|
||||
pass # non-critical; export proceeds regardless
|
||||
|
||||
# Export production GLB with full PBR material data
|
||||
try:
|
||||
bpy.ops.export_scene.gltf(
|
||||
|
||||
Reference in New Issue
Block a user