Asset-Frameworker/Project Notes/BLENDER_MATERIAL_CREATION_PLAN.md
2025-04-29 18:26:13 +02:00

9.5 KiB

Blender Material Creation Script Plan

This document outlines the plan for creating a new Blender script (create_materials.py) in the blenderscripts/ directory. This script will scan the processed asset library output by the Asset Processor Tool, read the metadata.json files, and create or update Blender materials that link to the corresponding PBRSET node groups found in a specified Blender Asset Library. The script will also set the material's viewport properties using pre-calculated statistics from the metadata. The script will skip processing an asset if the corresponding material already exists in the current Blender file.

1. Script Location and Naming

  • Create a new file: blenderscripts/create_materials.py.

2. Script Structure

The script will follow a similar structure to blenderscripts/create_nodegroups.py, including:

  • Import statements (bpy, os, json, pathlib, time, base64).
  • A --- USER CONFIGURATION --- section at the top.
  • Helper functions.
  • A main processing function (e.g., process_library_for_materials).
  • An execution block (if __name__ == "__main__":) to run the main function.

3. Configuration Variables

The script will include the following configuration variables in the --- USER CONFIGURATION --- section:

  • PROCESSED_ASSET_LIBRARY_ROOT: Path to the root output directory of the Asset Processor Tool (same as in create_nodegroups.py). This is used to find the metadata.json files and reference images for previews.
  • PBRSET_ASSET_LIBRARY_NAME: The name of the Blender Asset Library (configured in Blender Preferences) that contains the PBRSET node groups created by create_nodegroups.py.
  • TEMPLATE_MATERIAL_NAME: Name of the required template material in the Blender file (e.g., "Template_PBRMaterial").
  • PLACEHOLDER_NODE_LABEL: Label of the placeholder Group node within the template material's node tree where the PBRSET node group will be linked (e.g., "PBRSET_PLACEHOLDER").
  • MATERIAL_NAME_PREFIX: Prefix for the created materials (e.g., "Mat_").
  • PBRSET_GROUP_PREFIX: Prefix used for the PBRSET node groups created by create_nodegroups.py (e.g., "PBRSET_").
  • REFERENCE_MAP_TYPES: List of map types to look for to find a reference image for the material preview (e.g., ["COL", "COL-1"]).
  • REFERENCE_RESOLUTION_ORDER: Preferred resolution order for the reference image (e.g., ["1K", "512", "2K", "4K"]).
  • IMAGE_FILENAME_PATTERN: Assumed filename pattern for processed images (same as in create_nodegroups.py).
  • FALLBACK_IMAGE_EXTENSIONS: Fallback extensions for finding image files (same as in create_nodegroups.py).
  • VIEWPORT_COLOR_MAP_TYPES: List of map types to check in metadata's image_stats_1k for viewport diffuse color.
  • VIEWPORT_ROUGHNESS_MAP_TYPES: List of map types to check in metadata's image_stats_1k for viewport roughness.
  • VIEWPORT_METALLIC_MAP_TYPES: List of map types to check in metadata's image_stats_1k for viewport metallic.

4. Helper Functions

The script will include the following helper functions:

  • find_nodes_by_label(node_tree, label, node_type=None): Reusable from create_nodegroups.py to find nodes in a node tree.
  • add_tag_if_new(asset_data, tag_name): Reusable from create_nodegroups.py to add asset tags.
  • reconstruct_image_path_with_fallback(...): Reusable from create_nodegroups.py to find image paths (needed for setting the custom preview).
  • get_stat_value(stats_dict, map_type_list, stat_key): A helper function to safely retrieve a specific statistic from the image_stats_1k dictionary.

5. Main Processing Logic (process_library_for_materials)

The main function will perform the following steps:

  • Pre-run Checks:
    • Verify PROCESSED_ASSET_LIBRARY_ROOT exists and is a directory.
    • Verify the PBRSET_ASSET_LIBRARY_NAME exists in Blender's user preferences (bpy.context.preferences.filepaths.asset_libraries).
    • Verify the TEMPLATE_MATERIAL_NAME material exists and uses nodes.
    • Verify the PLACEHOLDER_NODE_LABEL Group node exists in the template material's node tree.
  • Scan for Metadata:
    • Iterate through supplier directories within PROCESSED_ASSET_LIBRARY_ROOT.
    • Iterate through asset directories within each supplier directory.
    • Identify metadata.json files.
  • Process Each Metadata File:
    • Load the metadata.json file.
    • Extract asset_name, supplier_name, archetype, processed_map_resolutions, merged_map_resolutions, map_details, and image_stats_1k.
    • Determine the expected PBRSET node group name: f"{PBRSET_GROUP_PREFIX}{asset_name}".
    • Determine the target material name: f"{MATERIAL_NAME_PREFIX}{asset_name}".
    • Find or Create Material:
      • Check if a material with the target_material_name already exists in bpy.data.materials.
      • If it exists, log a message indicating the asset is being skipped and move to the next metadata file.
      • If it doesn't exist, copy the TEMPLATE_MATERIAL_NAME material and rename the copy to target_material_name (create mode). Handle potential copy failures.
    • Find Placeholder Node:
      • Find the node with PLACEHOLDER_NODE_LABEL in the target material's node tree using find_nodes_by_label. Handle cases where the node is not found or is not a Group node.
    • Find and Link PBRSET Node Group from Asset Library:
      • Get the path to the .blend file associated with the PBRSET_ASSET_LIBRARY_NAME from user preferences.
      • Use bpy.data.libraries.load(filepath, link=True) to link the node group with target_pbrset_group_name from the external .blend file into the current file. Handle cases where the library or the node group is not found.
      • Once linked, get the reference to the newly linked node group in bpy.data.node_groups.
    • Link Linked Node Group to Placeholder:
      • If both the placeholder node and the newly linked PBRSET node group are found, assign the linked node group to the node_tree property of the placeholder node.
    • Mark Material as Asset:
      • If the material is new or not already marked, call material.asset_mark().
    • Copy Asset Tags:
      • If both the material and the linked PBRSET node group have asset data, copy tags (supplier, archetype) from the node group to the material using add_tag_if_new.
    • Set Custom Preview:
      • Find a suitable reference image path (e.g., lowest resolution COL map) using reconstruct_image_path_with_fallback and the REFERENCE_MAP_TYPES and REFERENCE_RESOLUTION_ORDER configurations.
      • If a reference image path is found, use bpy.ops.ed.lib_id_load_custom_preview to set the custom preview for the material. This operation requires overriding the context.
    • Set Viewport Properties (using metadata stats):
      • Check if image_stats_1k is present and valid in the metadata.
      • Diffuse Color: Use the get_stat_value helper to get the 'mean' stat for map types in VIEWPORT_COLOR_MAP_TYPES. If found and is a valid color list [R, G, B], set material.diffuse_color to this value.
      • Roughness: Use the get_stat_value helper to get the 'mean' stat for map types in VIEWPORT_ROUGHNESS_MAP_TYPES. If found, get the first value (for grayscale). Check if stats for VIEWPORT_METALLIC_MAP_TYPES exist. If metallic stats are not found, invert the roughness value (1.0 - value) before assigning it to material.roughness. Clamp the final value between 0.0 and 1.0.
      • Metallic: Use the get_stat_value helper to get the 'mean' stat for map types in VIEWPORT_METALLIC_MAP_TYPES. If found, get the first value (for grayscale) and assign it to material.metallic. If metallic stats are not found, set material.metallic to 0.0.
    • Error Handling and Reporting:
      • Include try...except blocks to catch errors during file reading, JSON parsing, Blender operations, linking, etc.
      • Print informative messages about progress, creation/update status, and errors.
  • Summary Report:
    • Print a summary of how many metadata files were processed, materials created/updated, node groups linked, errors encountered, and assets skipped.

6. Process Flow Diagram (Updated)

graph TD
    A[Start Script] --> B{Pre-run Checks Pass?};
    B -- No --> C[Abort Script];
    B -- Yes --> D[Scan Processed Asset Root];
    D --> E{Found metadata.json?};
    E -- No --> F[Finish Script (No Assets)];
    E -- Yes --> G[Loop through metadata.json files];
    G --> H[Read metadata.json];
    H --> I{Metadata Valid?};
    I -- No --> J[Log Error, Skip Asset];
    I -- Yes --> K[Extract Asset Info & Stats];
    K --> L[Find or Create Material];
    L --> M{Material Exists?};
    M -- Yes --> N[Log Skip, Continue Loop];
    M -- No --> O[Find Placeholder Node in Material];
    O --> P[Find PBRSET NG in Library & Link];
    P --> Q{Linking Successful?};
    Q -- No --> R[Log Error, Skip Asset];
    Q -- Yes --> S[Link Linked NG to Placeholder];
    S --> T[Mark Material as Asset];
    T --> U[Copy Asset Tags];
    U --> V[Find Reference Image Path for Preview];
    V --> W{Reference Image Found?};
    W -- Yes --> X[Set Custom Material Preview];
    W -- No --> Y[Log Warning (No Preview)];
    X --> Z[Set Viewport Properties from Stats];
    Y --> Z;
    Z --> AA[Increment Counters];
    AA --> G;
    G --> AB[Print Summary Report];
    AB --> AC[End Script];

    J --> G;
    N --> G;
    R --> G;