"""Asset library helpers for Blender render scripts. Provides functions to link materials and node groups from a .blend asset library into the current scene, and apply them to mesh objects. These functions are intended to be imported by still_render.py / turntable_render.py when a RenderTemplate has an asset library associated. """ from __future__ import annotations import logging logger = logging.getLogger(__name__) def apply_asset_library_materials(blend_path: str, material_map: dict) -> None: """Link materials from an asset library .blend and apply them to mesh slots. Args: blend_path: Absolute path to the .blend library file. material_map: Mapping of current slot material name -> library material name. E.g. {"Steel--Stahl": "SCHAEFFLER_010101_Steel-Bare"} """ import bpy # type: ignore[import] if not material_map: return target_names = set(material_map.values()) # Link materials from the library with bpy.data.libraries.load(blend_path, link=True, assets_only=True) as (src, dst): 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} logger.info("Linked %d materials from %s", len(linked), blend_path) # Apply to all mesh object material slots for obj in bpy.data.objects: if obj.type != "MESH": continue for slot in obj.material_slots: if slot.material is None: continue resolved = material_map.get(slot.material.name) if resolved and resolved in bpy.data.materials: slot.material = bpy.data.materials[resolved] def apply_asset_library_node_groups(blend_path: str, modifier_map: dict) -> None: """Link geometry node groups from an asset library and apply as modifiers. Args: blend_path: Absolute path to the .blend library file. modifier_map: Mapping of object name substring -> node group name. E.g. {"ring": "WearPattern_GeoNodes"} """ import bpy # type: ignore[import] if not modifier_map: return target_names = set(modifier_map.values()) with bpy.data.libraries.load(blend_path, link=True, assets_only=True) as (src, dst): dst.node_groups = [name for name in src.node_groups if name in target_names] for obj in bpy.data.objects: if obj.type != "MESH": continue for part_substr, ng_name in modifier_map.items(): if part_substr.lower() in obj.name.lower(): ng = bpy.data.node_groups.get(ng_name) if ng: mod = obj.modifiers.new(name=ng_name, type="NODES") mod.node_group = ng logger.info("Applied node group %s to %s", ng_name, obj.name)