fix(gltf): append materials (link=False) for proper PBR export to GLB
Linked materials are external references — Blender's GLTF exporter cannot traverse their node trees to extract Principled BSDF PBR values (metallic, roughness, base color, normal maps). Appended materials are local copies that the exporter can fully traverse. Changes: - asset_library.py: add link=True parameter (default unchanged for renders) - export_gltf.py: call apply_asset_library_materials with link=False - export_gltf.py: add export_materials='EXPORT' + export_image_format='AUTO' to embed textures and ensure full PBR data in the GLB Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -13,13 +13,16 @@ import logging
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def apply_asset_library_materials(blend_path: str, material_map: dict) -> None:
|
def apply_asset_library_materials(blend_path: str, material_map: dict, link: bool = True) -> None:
|
||||||
"""Link materials from an asset library .blend and apply them to mesh slots.
|
"""Load materials from an asset library .blend and apply them to mesh slots.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
blend_path: Absolute path to the .blend library file.
|
blend_path: Absolute path to the .blend library file.
|
||||||
material_map: Mapping of current slot material name -> library material name.
|
material_map: Mapping of current slot material name -> library material name.
|
||||||
E.g. {"Steel--Stahl": "SCHAEFFLER_010101_Steel-Bare"}
|
E.g. {"Steel--Stahl": "SCHAEFFLER_010101_Steel-Bare"}
|
||||||
|
link: If True (default), link materials (external reference, good for rendering).
|
||||||
|
If False, append materials (local copy — required for GLB/GLTF export so
|
||||||
|
that the exporter can traverse Principled BSDF node trees for PBR values).
|
||||||
"""
|
"""
|
||||||
import bpy # type: ignore[import]
|
import bpy # type: ignore[import]
|
||||||
|
|
||||||
@@ -28,12 +31,12 @@ def apply_asset_library_materials(blend_path: str, material_map: dict) -> None:
|
|||||||
|
|
||||||
target_names = set(material_map.values())
|
target_names = set(material_map.values())
|
||||||
|
|
||||||
# Link materials from the library
|
# Link or append materials from the library
|
||||||
with bpy.data.libraries.load(blend_path, link=True, assets_only=True) as (src, dst):
|
with bpy.data.libraries.load(blend_path, link=link, assets_only=True) as (src, dst):
|
||||||
dst.materials = [name for name in src.materials if name in target_names]
|
dst.materials = [name for name in src.materials if name in target_names]
|
||||||
|
|
||||||
linked = {m.name for m in dst.materials if m is not None}
|
loaded = {m.name for m in dst.materials if m is not None}
|
||||||
logger.info("Linked %d materials from %s", len(linked), blend_path)
|
logger.info("%s %d materials from %s", "Linked" if link else "Appended", len(loaded), blend_path)
|
||||||
|
|
||||||
# Apply to all mesh object material slots
|
# Apply to all mesh object material slots
|
||||||
for obj in bpy.data.objects:
|
for obj in bpy.data.objects:
|
||||||
|
|||||||
@@ -113,20 +113,26 @@ def main() -> None:
|
|||||||
mark_sharp_edges_by_proximity(sharp_edge_midpoints)
|
mark_sharp_edges_by_proximity(sharp_edge_midpoints)
|
||||||
print(f"Marked sharp edges from {len(sharp_edge_midpoints)} hint points")
|
print(f"Marked sharp edges from {len(sharp_edge_midpoints)} hint points")
|
||||||
|
|
||||||
# Apply asset library materials if provided
|
# Apply asset library materials if provided.
|
||||||
|
# link=False (append) is required for GLB export: the GLTF exporter can only
|
||||||
|
# traverse local (appended) Principled BSDF node trees to extract PBR values.
|
||||||
|
# Linked materials are external references whose node data is not accessible.
|
||||||
if args.asset_library_blend and material_map:
|
if args.asset_library_blend and material_map:
|
||||||
import os
|
import os
|
||||||
sys.path.insert(0, os.path.dirname(__file__))
|
sys.path.insert(0, os.path.dirname(__file__))
|
||||||
from asset_library import apply_asset_library_materials
|
from asset_library import apply_asset_library_materials
|
||||||
apply_asset_library_materials(args.asset_library_blend, material_map)
|
apply_asset_library_materials(args.asset_library_blend, material_map, link=False)
|
||||||
|
|
||||||
# Export GLB
|
# Export GLB with full PBR material data
|
||||||
try:
|
try:
|
||||||
bpy.ops.export_scene.gltf(
|
bpy.ops.export_scene.gltf(
|
||||||
filepath=args.output_path,
|
filepath=args.output_path,
|
||||||
export_format="GLB",
|
export_format="GLB",
|
||||||
export_apply=True,
|
export_apply=True,
|
||||||
use_selection=False,
|
use_selection=False,
|
||||||
|
export_materials="EXPORT", # export all materials (Principled BSDF → glTF PBR)
|
||||||
|
export_image_format="AUTO", # embed textures (base color, normal, roughness maps)
|
||||||
|
export_colors=False, # skip vertex colors (we use library materials)
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
print(f"GLB export failed: {exc}", file=sys.stderr)
|
print(f"GLB export failed: {exc}", file=sys.stderr)
|
||||||
|
|||||||
Reference in New Issue
Block a user