162 lines
5.2 KiB
Markdown
162 lines
5.2 KiB
Markdown
# Blender Shader Node Exporter
|
|
|
|
Exports the active object's material shader node tree to a readable JSON file. Useful for documenting materials, diffing shader changes, or feeding node data into external tools.
|
|
|
|
---
|
|
|
|
## Requirements
|
|
|
|
- Blender 4.0 or later (tested on 4.5)
|
|
- No additional Python packages — uses only Blender's built-in `bpy`, `json`, and `os`
|
|
|
|
---
|
|
|
|
## Quick Start
|
|
|
|
1. Open your `.blend` file and select the object whose material you want to export.
|
|
2. In Blender, go to the **Text Editor** (you can split any panel and switch it to Text Editor).
|
|
3. Click **New** to create a new text block, then paste in `export_shader_nodes.py`.
|
|
4. Click **Run Script** (or press `Alt + P`).
|
|
5. The JSON file is saved automatically next to your `.blend` file, named `<MaterialName>_shader.json`.
|
|
|
|
Check the **System Console** (`Window → Toggle System Console` on Windows) for a confirmation message and node/link counts.
|
|
|
|
---
|
|
|
|
## Configuration
|
|
|
|
At the top of the script there are two settings you can change:
|
|
|
|
```python
|
|
EXPORT_PATH = None # Set a custom output path, e.g. r"C:\Users\You\my_shader.json"
|
|
MATERIAL_INDEX = 0 # Which material slot to export (0 = first slot)
|
|
```
|
|
|
|
**`EXPORT_PATH`** — leave as `None` to auto-save next to the `.blend` file. If the `.blend` hasn't been saved yet, the file goes to your home directory (`~/`).
|
|
|
|
**`MATERIAL_INDEX`** — if your object has multiple material slots, set this to the slot number you want (0-indexed). For example, `1` exports the second material.
|
|
|
|
---
|
|
|
|
## Output format
|
|
|
|
The JSON has this structure:
|
|
|
|
```json
|
|
{
|
|
"material_name": "MyMaterial",
|
|
"blend_method": "OPAQUE",
|
|
"shadow_method": "OPAQUE",
|
|
"use_backface_culling": false,
|
|
"node_tree": {
|
|
"name": "MyMaterial",
|
|
"type": "SHADER",
|
|
"nodes": [ ... ],
|
|
"links": [ ... ]
|
|
}
|
|
}
|
|
```
|
|
|
|
### Nodes
|
|
|
|
Each entry in `nodes` looks like:
|
|
|
|
```json
|
|
{
|
|
"name": "Principled BSDF",
|
|
"label": "",
|
|
"type": "BSDF_PRINCIPLED",
|
|
"bl_idname": "ShaderNodeBsdfPrincipled",
|
|
"location": [-200.0, 300.0],
|
|
"width": 240.0,
|
|
"height": 100.0,
|
|
"hide": false,
|
|
"mute": false,
|
|
"use_custom_color": false,
|
|
"color": [0.6, 0.6, 0.6],
|
|
"inputs": [
|
|
{
|
|
"name": "Base Color",
|
|
"identifier": "Base Color",
|
|
"type": "RGBA",
|
|
"is_linked": true,
|
|
"default_value": [0.8, 0.8, 0.8, 1.0]
|
|
}
|
|
],
|
|
"outputs": [ ... ],
|
|
"properties": {
|
|
"distribution": "MULTI_GGX",
|
|
"subsurface_method": "RANDOM_WALK"
|
|
}
|
|
}
|
|
```
|
|
|
|
### Links
|
|
|
|
Each entry in `links` describes one connection between nodes:
|
|
|
|
```json
|
|
{
|
|
"from_node": "Image Texture",
|
|
"from_socket": "Color",
|
|
"to_node": "Principled BSDF",
|
|
"to_socket": "Base Color",
|
|
"is_muted": false
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## What gets exported per node type
|
|
|
|
| Node | Extra properties captured |
|
|
|---|---|
|
|
| Principled BSDF | `distribution`, `subsurface_method` |
|
|
| Image Texture | `interpolation`, `projection`, `extension`, `image_name`, `image_filepath` |
|
|
| Noise Texture | `noise_dimensions` |
|
|
| Wave Texture | `wave_type`, `bands_direction`, `rings_direction`, `wave_profile` |
|
|
| Voronoi Texture | `voronoi_dimensions`, `feature`, `distance` |
|
|
| Mapping | `vector_type` |
|
|
| Math | `operation`, `use_clamp` |
|
|
| Vector Math | `operation` |
|
|
| Mix / MixRGB | `blend_type`, `use_clamp` / `data_type`, `clamp_factor`, `clamp_result`, `factor_mode` |
|
|
| Bump | `invert` |
|
|
| Normal Map | `space`, `uv_map` |
|
|
| Displacement | `space` |
|
|
| Value | `value` (the output number) |
|
|
| RGB | `color` (the output color as RGBA list) |
|
|
| Group | `node_tree` (the name of the node group) |
|
|
| Script | `mode`, `script`, `filepath` |
|
|
| All others | Sockets + default values only |
|
|
|
|
> **Note:** Image pixel data is not exported — only the image name and its filepath as stored in Blender.
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
**`No active object selected`** — click on your object in the viewport before running the script. Make sure it's highlighted orange, not just in the scene.
|
|
|
|
**`Object has no material slots`** — the selected object has no material assigned. Add one in the Properties panel → Material tab.
|
|
|
|
**`Material slot N is out of range`** — you set `MATERIAL_INDEX` higher than the number of slots the object has. Slot numbering starts at 0.
|
|
|
|
**`Material does not use nodes`** — the material has node editing disabled. In the Material Properties panel, enable **Use Nodes**.
|
|
|
|
**Permission error on the output file** — Blender doesn't have write access to the target directory. Either set `EXPORT_PATH` to a folder you own (e.g. your Desktop), or run Blender as an administrator (Windows).
|
|
|
|
**The JSON only has generic socket data for a node type I care about** — the script has an explicit allowlist of properties per node type. You can add your node's `bl_idname` and the property attribute names to the `prop_names` dict near the top of `export_node()`. All available attributes are listed in the [Blender Python API docs](https://docs.blender.org/api/current/).
|
|
|
|
---
|
|
|
|
## Exporting multiple materials
|
|
|
|
The script exports one material at a time. To batch-export all materials on an object, you can wrap the `main()` call in a loop:
|
|
|
|
```python
|
|
for i in range(len(bpy.context.active_object.material_slots)):
|
|
MATERIAL_INDEX = i
|
|
main()
|
|
```
|
|
|
|
Paste this at the bottom of the script in place of the final `main()` call.
|