{ "sourceFile": "Project Notes/BLENDER_MATERIAL_CREATION_PLAN.md", "activeCommit": 0, "commits": [ { "activePatchIndex": 2, "patches": [ { "date": 1745258705721, "content": "Index: \n===================================================================\n--- \n+++ \n" }, { "date": 1745259611867, "content": "Index: \n===================================================================\n--- \n+++ \n@@ -1,7 +1,7 @@\n # Blender Material Creation Script Plan\r\n \r\n-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 generated by `blenderscripts/create_nodegroups.py`. The script will also set the material's viewport properties using pre-calculated statistics from the metadata.\r\n+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.\r\n \r\n ## 1. Script Location and Naming\r\n \r\n * Create a new file: `blenderscripts/create_materials.py`.\r\n@@ -19,36 +19,38 @@\n ## 3. Configuration Variables\r\n \r\n The script will include the following configuration variables in the `--- USER CONFIGURATION ---` section:\r\n \r\n-* `PROCESSED_ASSET_LIBRARY_ROOT`: Path to the root output directory of the Asset Processor Tool (same as in `create_nodegroups.py`).\r\n+* `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.\r\n+* `PBRSET_ASSET_LIBRARY_NAME`: **NEW:** The name of the Blender Asset Library (configured in Blender Preferences) that contains the PBRSET node groups created by `create_nodegroups.py`.\r\n * `TEMPLATE_MATERIAL_NAME`: Name of the required template material in the Blender file (e.g., \"Template_PBRMaterial\").\r\n * `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\").\r\n * `MATERIAL_NAME_PREFIX`: Prefix for the created materials (e.g., \"Mat_\").\r\n * `PBRSET_GROUP_PREFIX`: Prefix used for the PBRSET node groups created by `create_nodegroups.py` (e.g., \"PBRSET_\").\r\n * `REFERENCE_MAP_TYPES`: List of map types to look for to find a reference image for the material preview (e.g., `[\"COL\", \"COL-1\"]`).\r\n * `REFERENCE_RESOLUTION_ORDER`: Preferred resolution order for the reference image (e.g., `[\"1K\", \"512\", \"2K\", \"4K\"]`).\r\n * `IMAGE_FILENAME_PATTERN`: Assumed filename pattern for processed images (same as in `create_nodegroups.py`).\r\n * `FALLBACK_IMAGE_EXTENSIONS`: Fallback extensions for finding image files (same as in `create_nodegroups.py`).\r\n-* `VIEWPORT_COLOR_MAP_TYPES`: List of map types to check for viewport diffuse color stats (e.g., `[\"COL\", \"COL-1\", \"COL-2\"]`).\r\n-* `VIEWPORT_ROUGHNESS_MAP_TYPES`: List of map types to check for viewport roughness stats (e.g., `[\"ROUGH\"]`).\r\n-* `VIEWPORT_METALLIC_MAP_TYPES`: List of map types to check for viewport metallic stats (e.g., `[\"METAL\"]`).\r\n+* `VIEWPORT_COLOR_MAP_TYPES`: List of map types to check in metadata's `image_stats_1k` for viewport diffuse color.\r\n+* `VIEWPORT_ROUGHNESS_MAP_TYPES`: List of map types to check in metadata's `image_stats_1k` for viewport roughness.\r\n+* `VIEWPORT_METALLIC_MAP_TYPES`: List of map types to check in metadata's `image_stats_1k` for viewport metallic.\r\n \r\n ## 4. Helper Functions\r\n \r\n The script will include the following helper functions:\r\n \r\n * `find_nodes_by_label(node_tree, label, node_type=None)`: Reusable from `create_nodegroups.py` to find nodes in a node tree.\r\n * `add_tag_if_new(asset_data, tag_name)`: Reusable from `create_nodegroups.py` to add asset tags.\r\n * `reconstruct_image_path_with_fallback(...)`: Reusable from `create_nodegroups.py` to find image paths (needed for setting the custom preview).\r\n-* `get_stat_value(stats_dict, map_type_list, stat_key)`: A new helper function to safely retrieve a specific statistic (e.g., 'mean') for a given list of map types from the `image_stats_1k` dictionary, handling potential missing keys or invalid data formats.\r\n+* `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.\r\n \r\n ## 5. Main Processing Logic (`process_library_for_materials`)\r\n \r\n The main function will perform the following steps:\r\n \r\n * **Pre-run Checks:**\r\n * Verify `PROCESSED_ASSET_LIBRARY_ROOT` exists and is a directory.\r\n+ * Verify the `PBRSET_ASSET_LIBRARY_NAME` exists in Blender's user preferences (`bpy.context.preferences.filepaths.asset_libraries`).\r\n * Verify the `TEMPLATE_MATERIAL_NAME` material exists and uses nodes.\r\n * Verify the `PLACEHOLDER_NODE_LABEL` Group node exists in the template material's node tree.\r\n * **Scan for Metadata:**\r\n * Iterate through supplier directories within `PROCESSED_ASSET_LIBRARY_ROOT`.\r\n@@ -64,16 +66,18 @@\n * If it exists, use the existing material (update mode).\r\n * 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.\r\n * **Find Placeholder Node:**\r\n * 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.\r\n- * **Find PBRSET Node Group:**\r\n- * Find the node group with the expected PBRSET name in `bpy.data.node_groups`. Handle cases where the node group is not found (this would indicate `create_nodegroups.py` hasn't been run or failed for this asset).\r\n- * **Link Node Group to Placeholder:**\r\n- * If both the placeholder node and the PBRSET node group are found, assign the PBRSET node group to the `node_tree` property of the placeholder node.\r\n+ * **Find and Link PBRSET Node Group from Asset Library:**\r\n+ * Get the path to the `.blend` file associated with the `PBRSET_ASSET_LIBRARY_NAME` from user preferences.\r\n+ * 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.\r\n+ * Once linked, get the reference to the newly linked node group in `bpy.data.node_groups`.\r\n+ * **Link Linked Node Group to Placeholder:**\r\n+ * 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.\r\n * **Mark Material as Asset:**\r\n * If the material is new or not already marked, call `material.asset_mark()`.\r\n * **Copy Asset Tags:**\r\n- * If both the material and the PBRSET node group have asset data, copy tags (supplier, archetype) from the node group to the material using `add_tag_if_new`.\r\n+ * 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`.\r\n * **Set Custom Preview:**\r\n * 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.\r\n * 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.\r\n * **Set Viewport Properties (using metadata stats):**\r\n@@ -81,14 +85,14 @@\n * **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.\r\n * **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.\r\n * **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.\r\n * **Error Handling and Reporting:**\r\n- * Include `try...except` blocks to catch errors during file reading, JSON parsing, Blender operations, etc.\r\n+ * Include `try...except` blocks to catch errors during file reading, JSON parsing, Blender operations, linking, etc.\r\n * Print informative messages about progress, creation/update status, and errors.\r\n * **Summary Report:**\r\n- * Print a summary of how many metadata files were processed, materials created/updated, errors encountered, etc.\r\n+ * Print a summary of how many metadata files were processed, materials created/updated, node groups linked, errors encountered, etc.\r\n \r\n-## 6. Process Flow Diagram\r\n+## 6. Process Flow Diagram (Updated)\r\n \r\n ```mermaid\r\n graph TD\r\n A[Start Script] --> B{Pre-run Checks Pass?};\r\n@@ -102,12 +106,12 @@\n I -- No --> J[Log Error, Skip Asset];\r\n I -- Yes --> K[Extract Asset Info & Stats];\r\n K --> L[Find or Create Material];\r\n L --> M[Find Placeholder Node in Material];\r\n- M --> N[Find PBRSET Node Group];\r\n- N --> O{Placeholder & NG Found?};\r\n+ M --> N[Find PBRSET NG in Library & Link];\r\n+ N --> O{Linking Successful?};\r\n O -- No --> P[Log Error, Skip Asset];\r\n- O -- Yes --> Q[Link PBRSET NG to Placeholder];\r\n+ O -- Yes --> Q[Link Linked NG to Placeholder];\r\n Q --> R[Mark Material as Asset];\r\n R --> S[Copy Asset Tags];\r\n S --> T[Find Reference Image Path for Preview];\r\n T --> U{Reference Image Found?};\r\n" }, { "date": 1745259690754, "content": "Index: \n===================================================================\n--- \n+++ \n@@ -1,7 +1,7 @@\n # Blender Material Creation Script Plan\r\n \r\n-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.\r\n+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.\r\n \r\n ## 1. Script Location and Naming\r\n \r\n * Create a new file: `blenderscripts/create_materials.py`.\r\n@@ -20,9 +20,9 @@\n \r\n The script will include the following configuration variables in the `--- USER CONFIGURATION ---` section:\r\n \r\n * `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.\r\n-* `PBRSET_ASSET_LIBRARY_NAME`: **NEW:** The name of the Blender Asset Library (configured in Blender Preferences) that contains the PBRSET node groups created by `create_nodegroups.py`.\r\n+* `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`.\r\n * `TEMPLATE_MATERIAL_NAME`: Name of the required template material in the Blender file (e.g., \"Template_PBRMaterial\").\r\n * `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\").\r\n * `MATERIAL_NAME_PREFIX`: Prefix for the created materials (e.g., \"Mat_\").\r\n * `PBRSET_GROUP_PREFIX`: Prefix used for the PBRSET node groups created by `create_nodegroups.py` (e.g., \"PBRSET_\").\r\n@@ -62,9 +62,9 @@\n * Determine the expected PBRSET node group name: `f\"{PBRSET_GROUP_PREFIX}{asset_name}\"`.\r\n * Determine the target material name: `f\"{MATERIAL_NAME_PREFIX}{asset_name}\"`.\r\n * **Find or Create Material:**\r\n * Check if a material with the `target_material_name` already exists in `bpy.data.materials`.\r\n- * If it exists, use the existing material (update mode).\r\n+ * If it exists, log a message indicating the asset is being skipped and move to the next metadata file.\r\n * 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.\r\n * **Find Placeholder Node:**\r\n * 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.\r\n * **Find and Link PBRSET Node Group from Asset Library:**\r\n@@ -88,9 +88,9 @@\n * **Error Handling and Reporting:**\r\n * Include `try...except` blocks to catch errors during file reading, JSON parsing, Blender operations, linking, etc.\r\n * Print informative messages about progress, creation/update status, and errors.\r\n * **Summary Report:**\r\n- * Print a summary of how many metadata files were processed, materials created/updated, node groups linked, errors encountered, etc.\r\n+ * Print a summary of how many metadata files were processed, materials created/updated, node groups linked, errors encountered, and assets skipped.\r\n \r\n ## 6. Process Flow Diagram (Updated)\r\n \r\n ```mermaid\r\n@@ -105,24 +105,27 @@\n H --> I{Metadata Valid?};\r\n I -- No --> J[Log Error, Skip Asset];\r\n I -- Yes --> K[Extract Asset Info & Stats];\r\n K --> L[Find or Create Material];\r\n- L --> M[Find Placeholder Node in Material];\r\n- M --> N[Find PBRSET NG in Library & Link];\r\n- N --> O{Linking Successful?};\r\n- O -- No --> P[Log Error, Skip Asset];\r\n- O -- Yes --> Q[Link Linked NG to Placeholder];\r\n- Q --> R[Mark Material as Asset];\r\n- R --> S[Copy Asset Tags];\r\n- S --> T[Find Reference Image Path for Preview];\r\n- T --> U{Reference Image Found?};\r\n- U -- Yes --> V[Set Custom Material Preview];\r\n- U -- No --> W[Log Warning (No Preview)];\r\n- V --> X[Set Viewport Properties from Stats];\r\n- W --> X;\r\n- X --> Y[Increment Counters];\r\n- Y --> G;\r\n- G --> Z[Print Summary Report];\r\n- Z --> AA[End Script];\r\n+ L --> M{Material Exists?};\r\n+ M -- Yes --> N[Log Skip, Continue Loop];\r\n+ M -- No --> O[Find Placeholder Node in Material];\r\n\\ No newline at end of file\n+ O --> P[Find PBRSET NG in Library & Link];\r\n+ P --> Q{Linking Successful?};\r\n+ Q -- No --> R[Log Error, Skip Asset];\r\n+ Q -- Yes --> S[Link Linked NG to Placeholder];\r\n+ S --> T[Mark Material as Asset];\r\n+ T --> U[Copy Asset Tags];\r\n+ U --> V[Find Reference Image Path for Preview];\r\n+ V --> W{Reference Image Found?};\r\n+ W -- Yes --> X[Set Custom Material Preview];\r\n+ W -- No --> Y[Log Warning (No Preview)];\r\n+ X --> Z[Set Viewport Properties from Stats];\r\n+ Y --> Z;\r\n+ Z --> AA[Increment Counters];\r\n+ AA --> G;\r\n+ G --> AB[Print Summary Report];\r\n+ AB --> AC[End Script];\r\n \r\n J --> G;\r\n- P --> G;\n+ N --> G;\r\n+ R --> G;\n\\ No newline at end of file\n" } ], "date": 1745258705721, "name": "Commit-0", "content": "# Blender Material Creation Script Plan\r\n\r\nThis 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 generated by `blenderscripts/create_nodegroups.py`. The script will also set the material's viewport properties using pre-calculated statistics from the metadata.\r\n\r\n## 1. Script Location and Naming\r\n\r\n* Create a new file: `blenderscripts/create_materials.py`.\r\n\r\n## 2. Script Structure\r\n\r\nThe script will follow a similar structure to `blenderscripts/create_nodegroups.py`, including:\r\n\r\n* Import statements (`bpy`, `os`, `json`, `pathlib`, `time`, `base64`).\r\n* A `--- USER CONFIGURATION ---` section at the top.\r\n* Helper functions.\r\n* A main processing function (e.g., `process_library_for_materials`).\r\n* An execution block (`if __name__ == \"__main__\":`) to run the main function.\r\n\r\n## 3. Configuration Variables\r\n\r\nThe script will include the following configuration variables in the `--- USER CONFIGURATION ---` section:\r\n\r\n* `PROCESSED_ASSET_LIBRARY_ROOT`: Path to the root output directory of the Asset Processor Tool (same as in `create_nodegroups.py`).\r\n* `TEMPLATE_MATERIAL_NAME`: Name of the required template material in the Blender file (e.g., \"Template_PBRMaterial\").\r\n* `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\").\r\n* `MATERIAL_NAME_PREFIX`: Prefix for the created materials (e.g., \"Mat_\").\r\n* `PBRSET_GROUP_PREFIX`: Prefix used for the PBRSET node groups created by `create_nodegroups.py` (e.g., \"PBRSET_\").\r\n* `REFERENCE_MAP_TYPES`: List of map types to look for to find a reference image for the material preview (e.g., `[\"COL\", \"COL-1\"]`).\r\n* `REFERENCE_RESOLUTION_ORDER`: Preferred resolution order for the reference image (e.g., `[\"1K\", \"512\", \"2K\", \"4K\"]`).\r\n* `IMAGE_FILENAME_PATTERN`: Assumed filename pattern for processed images (same as in `create_nodegroups.py`).\r\n* `FALLBACK_IMAGE_EXTENSIONS`: Fallback extensions for finding image files (same as in `create_nodegroups.py`).\r\n* `VIEWPORT_COLOR_MAP_TYPES`: List of map types to check for viewport diffuse color stats (e.g., `[\"COL\", \"COL-1\", \"COL-2\"]`).\r\n* `VIEWPORT_ROUGHNESS_MAP_TYPES`: List of map types to check for viewport roughness stats (e.g., `[\"ROUGH\"]`).\r\n* `VIEWPORT_METALLIC_MAP_TYPES`: List of map types to check for viewport metallic stats (e.g., `[\"METAL\"]`).\r\n\r\n## 4. Helper Functions\r\n\r\nThe script will include the following helper functions:\r\n\r\n* `find_nodes_by_label(node_tree, label, node_type=None)`: Reusable from `create_nodegroups.py` to find nodes in a node tree.\r\n* `add_tag_if_new(asset_data, tag_name)`: Reusable from `create_nodegroups.py` to add asset tags.\r\n* `reconstruct_image_path_with_fallback(...)`: Reusable from `create_nodegroups.py` to find image paths (needed for setting the custom preview).\r\n* `get_stat_value(stats_dict, map_type_list, stat_key)`: A new helper function to safely retrieve a specific statistic (e.g., 'mean') for a given list of map types from the `image_stats_1k` dictionary, handling potential missing keys or invalid data formats.\r\n\r\n## 5. Main Processing Logic (`process_library_for_materials`)\r\n\r\nThe main function will perform the following steps:\r\n\r\n* **Pre-run Checks:**\r\n * Verify `PROCESSED_ASSET_LIBRARY_ROOT` exists and is a directory.\r\n * Verify the `TEMPLATE_MATERIAL_NAME` material exists and uses nodes.\r\n * Verify the `PLACEHOLDER_NODE_LABEL` Group node exists in the template material's node tree.\r\n* **Scan for Metadata:**\r\n * Iterate through supplier directories within `PROCESSED_ASSET_LIBRARY_ROOT`.\r\n * Iterate through asset directories within each supplier directory.\r\n * Identify `metadata.json` files.\r\n* **Process Each Metadata File:**\r\n * Load the `metadata.json` file.\r\n * Extract `asset_name`, `supplier_name`, `archetype`, `processed_map_resolutions`, `merged_map_resolutions`, `map_details`, and `image_stats_1k`.\r\n * Determine the expected PBRSET node group name: `f\"{PBRSET_GROUP_PREFIX}{asset_name}\"`.\r\n * Determine the target material name: `f\"{MATERIAL_NAME_PREFIX}{asset_name}\"`.\r\n * **Find or Create Material:**\r\n * Check if a material with the `target_material_name` already exists in `bpy.data.materials`.\r\n * If it exists, use the existing material (update mode).\r\n * 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.\r\n * **Find Placeholder Node:**\r\n * 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.\r\n * **Find PBRSET Node Group:**\r\n * Find the node group with the expected PBRSET name in `bpy.data.node_groups`. Handle cases where the node group is not found (this would indicate `create_nodegroups.py` hasn't been run or failed for this asset).\r\n * **Link Node Group to Placeholder:**\r\n * If both the placeholder node and the PBRSET node group are found, assign the PBRSET node group to the `node_tree` property of the placeholder node.\r\n * **Mark Material as Asset:**\r\n * If the material is new or not already marked, call `material.asset_mark()`.\r\n * **Copy Asset Tags:**\r\n * If both the material and the PBRSET node group have asset data, copy tags (supplier, archetype) from the node group to the material using `add_tag_if_new`.\r\n * **Set Custom Preview:**\r\n * 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.\r\n * 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.\r\n * **Set Viewport Properties (using metadata stats):**\r\n * Check if `image_stats_1k` is present and valid in the metadata.\r\n * **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.\r\n * **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.\r\n * **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.\r\n * **Error Handling and Reporting:**\r\n * Include `try...except` blocks to catch errors during file reading, JSON parsing, Blender operations, etc.\r\n * Print informative messages about progress, creation/update status, and errors.\r\n* **Summary Report:**\r\n * Print a summary of how many metadata files were processed, materials created/updated, errors encountered, etc.\r\n\r\n## 6. Process Flow Diagram\r\n\r\n```mermaid\r\ngraph TD\r\n A[Start Script] --> B{Pre-run Checks Pass?};\r\n B -- No --> C[Abort Script];\r\n B -- Yes --> D[Scan Processed Asset Root];\r\n D --> E{Found metadata.json?};\r\n E -- No --> F[Finish Script (No Assets)];\r\n E -- Yes --> G[Loop through metadata.json files];\r\n G --> H[Read metadata.json];\r\n H --> I{Metadata Valid?};\r\n I -- No --> J[Log Error, Skip Asset];\r\n I -- Yes --> K[Extract Asset Info & Stats];\r\n K --> L[Find or Create Material];\r\n L --> M[Find Placeholder Node in Material];\r\n M --> N[Find PBRSET Node Group];\r\n N --> O{Placeholder & NG Found?};\r\n O -- No --> P[Log Error, Skip Asset];\r\n O -- Yes --> Q[Link PBRSET NG to Placeholder];\r\n Q --> R[Mark Material as Asset];\r\n R --> S[Copy Asset Tags];\r\n S --> T[Find Reference Image Path for Preview];\r\n T --> U{Reference Image Found?};\r\n U -- Yes --> V[Set Custom Material Preview];\r\n U -- No --> W[Log Warning (No Preview)];\r\n V --> X[Set Viewport Properties from Stats];\r\n W --> X;\r\n X --> Y[Increment Counters];\r\n Y --> G;\r\n G --> Z[Print Summary Report];\r\n Z --> AA[End Script];\r\n\r\n J --> G;\r\n P --> G;" } ] }