blender-syntax-materials
blender-syntax-materials
Quick Reference
Critical Warnings
NEVER use Blender 3.x Principled BSDF socket names in 4.0+ code. Sockets were renamed in 4.0 (e.g., "Subsurface" -> "Subsurface Weight"). Using old names raises KeyError.
NEVER use mat.blend_method in Blender 4.2+. This property was removed. Use mat.surface_render_method instead.
NEVER access UV data per-vertex. UV coordinates are stored per-loop (per face corner). Access via uv_layers.data[loop_index].
NEVER call bpy.data.images.load() without check_existing=True. Omitting it creates duplicate image data blocks on repeated loads.
NEVER set colorspace_settings.name incorrectly. Use 'sRGB' for color/diffuse textures and 'Non-Color' for normal maps, roughness, metallic, and other data textures.
ALWAYS set mat.use_nodes = True before accessing mat.node_tree. Without this, node_tree is None.
ALWAYS store the reference returned by bpy.data.materials.new(). Blender may append .001 if the name already exists.
Version Decision Tree
Creating material code?
├── Target Blender 4.0+ ONLY?
│ ├── YES → Use 4.0+ Principled BSDF socket names directly
│ └── NO → Use version-safe helper (see Pattern 3)
│
Setting transparency/alpha blending?
├── Blender 4.2+?
│ ├── YES → mat.surface_render_method = 'BLENDED'
│ └── NO (3.x / 4.0-4.1) → mat.blend_method = 'BLEND'
│
Connecting texture to Principled BSDF?
├── Color texture (diffuse, base color)?
│ └── Connect to "Base Color" input (all versions)
├── Normal map?
│ └── Connect via ShaderNodeNormalMap → "Normal" input
└── Data texture (roughness, metallic, AO)?
└── Set image colorspace to 'Non-Color'
Essential Patterns
Pattern 1: Create and Assign a Material
# Blender 3.x/4.x/5.x — create material and assign to object
import bpy
mat = bpy.data.materials.new(name="MyMaterial")
mat.use_nodes = True # REQUIRED before accessing node_tree
obj = bpy.context.active_object
if obj.data.materials:
obj.data.materials[0] = mat # Replace first slot
else:
obj.data.materials.append(mat) # Add new slot
Pattern 2: Build a Complete Node Tree
# Blender 3.x/4.x/5.x — node tree from scratch
mat = bpy.data.materials.new("NodeMaterial")
mat.use_nodes = True
tree = mat.node_tree
# Clear defaults
tree.nodes.clear()
# Create nodes
principled = tree.nodes.new('ShaderNodeBsdfPrincipled')
principled.location = (0, 0)
output = tree.nodes.new('ShaderNodeOutputMaterial')
output.location = (400, 0)
# Link BSDF to output
tree.links.new(principled.outputs["BSDF"], output.inputs["Surface"])
Pattern 3: Version-Safe Principled BSDF Input Access
# Blender 3.x/4.0+ — handle renamed sockets
import bpy
def set_principled_value(node, socket_3x, socket_4x, value):
"""Set Principled BSDF input with version-safe socket name."""
if bpy.app.version >= (4, 0, 0):
socket_name = socket_4x
else:
socket_name = socket_3x
if socket_name in node.inputs:
node.inputs[socket_name].default_value = value
# Usage
set_principled_value(principled, "Subsurface", "Subsurface Weight", 0.1)
set_principled_value(principled, "Specular", "Specular IOR Level", 0.5)
set_principled_value(principled, "Transmission", "Transmission Weight", 1.0)
set_principled_value(principled, "Coat", "Coat Weight", 0.3)
set_principled_value(principled, "Sheen", "Sheen Weight", 0.1)
set_principled_value(principled, "Emission", "Emission Color", (1, 1, 1, 1))
Pattern 4: Texture Node with UV Mapping
# Blender 3.x/4.x/5.x — image texture with UV coordinates
tree = mat.node_tree
tex_coord = tree.nodes.new('ShaderNodeTexCoord')
tex_coord.location = (-800, 0)
mapping = tree.nodes.new('ShaderNodeMapping')
mapping.location = (-600, 0)
tex_node = tree.nodes.new('ShaderNodeTexImage')
tex_node.location = (-400, 0)
img = bpy.data.images.load("/path/to/texture.png", check_existing=True)
tex_node.image = img
# Link: TexCoord → Mapping → Image Texture → Principled BSDF
tree.links.new(tex_coord.outputs["UV"], mapping.inputs["Vector"])
tree.links.new(mapping.outputs["Vector"], tex_node.inputs["Vector"])
tree.links.new(tex_node.outputs["Color"], principled.inputs["Base Color"])
Pattern 5: Alpha/Transparency Setup (Version-Dependent)
# Blender 4.2+ — EEVEE transparency
mat.surface_render_method = 'BLENDED' # 4.2+ ONLY
# Blender 3.x / 4.0-4.1 — EEVEE transparency
# mat.blend_method = 'BLEND' # REMOVED in 4.2
# Version-safe pattern
if bpy.app.version >= (4, 2, 0):
mat.surface_render_method = 'BLENDED'
else:
mat.blend_method = 'BLEND'
Principled BSDF Socket Rename Table (3.x -> 4.0+)
| Blender 3.x Name | Blender 4.0+ Name | Notes |
|---|---|---|
Base Color |
Base Color |
Unchanged |
Subsurface |
Subsurface Weight |
Renamed |
Subsurface Color |
REMOVED | Use Base Color instead |
Specular |
Specular IOR Level |
Renamed |
Specular Tint |
Specular Tint |
Type changed: Float -> Color |
Transmission |
Transmission Weight |
Renamed |
Coat |
Coat Weight |
Renamed |
Sheen |
Sheen Weight |
Renamed |
Emission |
Emission Color |
Renamed |
Metallic |
Metallic |
Unchanged |
Roughness |
Roughness |
Unchanged |
IOR |
IOR |
Unchanged |
Alpha |
Alpha |
Unchanged |
Normal |
Normal |
Unchanged |
Common Operations
Assign Material to Specific Faces
# Blender 3.x/4.x/5.x — multi-material assignment
import bpy
obj = bpy.context.active_object
# Add two materials to object
mat_a = bpy.data.materials.new("Material_A")
mat_b = bpy.data.materials.new("Material_B")
obj.data.materials.append(mat_a)
obj.data.materials.append(mat_b)
# Assign material index per polygon
for polygon in obj.data.polygons:
if polygon.center.z > 0:
polygon.material_index = 1 # Material_B
else:
polygon.material_index = 0 # Material_A
Add Material Slot via Operator
# Blender 3.x/4.x/5.x — operator-based slot management
import bpy
obj = bpy.context.active_object
bpy.context.view_layer.objects.active = obj
# Add empty slot
bpy.ops.object.material_slot_add()
# Assign material to active slot
obj.material_slots[obj.active_material_index].material = mat
# Remove active slot
bpy.ops.object.material_slot_remove()
Access Default Principled BSDF
When use_nodes = True is set on a new material, Blender creates a default Principled BSDF and Material Output automatically.
# Blender 3.x/4.x/5.x — access default nodes without clearing
mat = bpy.data.materials.new("QuickMaterial")
mat.use_nodes = True
principled = mat.node_tree.nodes.get("Principled BSDF")
# principled is the auto-created ShaderNodeBsdfPrincipled
UV Layer Management
# Blender 3.x/4.x/5.x — UV layer access
mesh = obj.data
# List UV layers
for uv_layer in mesh.uv_layers:
print(uv_layer.name)
# Get active UV layer
active_uv = mesh.uv_layers.active
# Create new UV layer
new_uv = mesh.uv_layers.new(name="ProjectionUV")
# Read UV coordinates (per-loop, NOT per-vertex)
for loop_idx in range(len(mesh.loops)):
uv = active_uv.data[loop_idx].uv
# uv.x, uv.y are the coordinates
# Modify UV coordinates
for loop_idx in range(len(mesh.loops)):
active_uv.data[loop_idx].uv.x *= 2.0
active_uv.data[loop_idx].uv.y *= 2.0
Load and Configure Image Textures
# Blender 3.x/4.x/5.x — image loading
import bpy
# Load from file (reuse existing if already loaded)
img = bpy.data.images.load("/path/to/texture.png", check_existing=True)
# Create new blank image (for baking)
img = bpy.data.images.new("BakeTarget", width=2048, height=2048)
# Configure texture node
tex_node = tree.nodes.new('ShaderNodeTexImage')
tex_node.image = img
tex_node.interpolation = 'Linear' # 'Linear', 'Closest', 'Cubic', 'Smart'
tex_node.projection = 'FLAT' # 'FLAT', 'BOX', 'SPHERE', 'TUBE'
tex_node.extension = 'REPEAT' # 'REPEAT', 'EXTEND', 'CLIP'
# Set color space
img.colorspace_settings.name = 'sRGB' # For diffuse/color textures
# img.colorspace_settings.name = 'Non-Color' # For normal, roughness, metallic
Normal Map Setup
# Blender 3.x/4.x/5.x — normal map node chain
tree = mat.node_tree
normal_tex = tree.nodes.new('ShaderNodeTexImage')
normal_tex.image = bpy.data.images.load("/path/to/normal.png", check_existing=True)
normal_tex.image.colorspace_settings.name = 'Non-Color' # REQUIRED for normal maps
normal_map = tree.nodes.new('ShaderNodeNormalMap')
tree.links.new(normal_tex.outputs["Color"], normal_map.inputs["Color"])
tree.links.new(normal_map.outputs["Normal"], principled.inputs["Normal"])
Remove All Materials from Object
# Blender 3.x/4.x/5.x — clear all material slots
obj.data.materials.clear()
Common Shader Node Types
| Node Type String | Class | Purpose |
|---|---|---|
'ShaderNodeBsdfPrincipled' |
Principled BSDF | Main PBR shader |
'ShaderNodeOutputMaterial' |
Material Output | Final output |
'ShaderNodeTexImage' |
Image Texture | Load image files |
'ShaderNodeTexCoord' |
Texture Coordinate | UV, Object, Generated coords |
'ShaderNodeMapping' |
Mapping | Transform texture coordinates |
'ShaderNodeNormalMap' |
Normal Map | Convert image to normal vector |
'ShaderNodeMixShader' |
Mix Shader | Blend two shaders |
'ShaderNodeBsdfTransparent' |
Transparent BSDF | Transparency shader |
'ShaderNodeBsdfGlass' |
Glass BSDF | Glass shader |
'ShaderNodeMath' |
Math | Scalar math operations |
'ShaderNodeMixRGB' |
Mix (Color) | Blend colors (3.x name) |
'ShaderNodeMix' |
Mix | Blend colors/vectors (4.0+) |
'ShaderNodeValToRGB' |
Color Ramp | Map value to color gradient |
'ShaderNodeBump' |
Bump | Generate bump from height |
'ShaderNodeSeparateXYZ' |
Separate XYZ | Split vector components |
'ShaderNodeCombineXYZ' |
Combine XYZ | Merge components to vector |
'ShaderNodeTexNoise' |
Noise Texture | Procedural noise |
'ShaderNodeTexVoronoi' |
Voronoi Texture | Procedural voronoi |
'ShaderNodeGroup' |
Node Group | Reusable node group instance |
EEVEE vs Cycles Material Differences
| Property | EEVEE | Cycles | Notes |
|---|---|---|---|
| Transparency | Requires surface_render_method (4.2+) or blend_method (3.x-4.1) |
Automatic from Alpha | EEVEE needs explicit config |
| Screen Space Refraction | mat.use_screen_refraction = True |
Not needed | EEVEE-specific |
| Backface Culling | mat.use_backface_culling |
mat.use_backface_culling |
Same API |
| Displacement | mat.cycles.displacement_method |
mat.cycles.displacement_method |
Cycles-only |
| Shadow Mode | mat.shadow_method (3.x-4.1) |
Automatic | EEVEE-specific |
Version-Specific Migration Rules
| Feature | Blender 3.x | Blender 4.0+ | Blender 4.2+ |
|---|---|---|---|
| Principled BSDF sockets | Old names | New names (see table) | Same as 4.0 |
| Alpha blending (EEVEE) | mat.blend_method = 'BLEND' |
mat.blend_method = 'BLEND' |
mat.surface_render_method = 'BLENDED' |
| Shadow method (EEVEE) | mat.shadow_method |
mat.shadow_method |
Property restructured |
| Mix node | 'ShaderNodeMixRGB' |
'ShaderNodeMix' (preferred) |
'ShaderNodeMix' |
| Specular Tint type | Float (0.0-1.0) | Color (RGBA) | Color (RGBA) |
Reference Links
- references/methods.md — Complete API signatures for Material, NodeTree, ShaderNode, UV layers, Image
- references/examples.md — Working code examples for common material workflows
- references/anti-patterns.md — What NOT to do with materials, with WHY explanations
Official Sources
- https://docs.blender.org/api/current/bpy.types.Material.html
- https://docs.blender.org/api/current/bpy.types.ShaderNodeBsdfPrincipled.html
- https://docs.blender.org/api/current/bpy.types.ShaderNodeTree.html
- https://docs.blender.org/api/current/bpy.types.UVLoopLayers.html
- https://docs.blender.org/api/current/bpy.types.Image.html
- https://developer.blender.org/docs/release_notes/4.0/python_api/
More from openaec-foundation/computational-design-day-delft-march-2026
blender-core-api
Guides Blender Python API usage including bpy module structure, RNA data access, context system, dependency graph, and operator invocation. Activates when writing bpy scripts, creating Blender addons, or accessing Blender data blocks programmatically.
1blender-syntax-panels
Defines Blender UI panel creation including bpy.types.Panel, draw() method, UILayout API (row/column/box/split), bl_space_type, bl_region_type, bl_category, sub-panels, draw_header, menus, and UIList. Activates when creating custom Blender panels, building addon interfaces, or working with UILayout elements.
1ifcos-syntax-api
Documents the ifcopenshell.api module system with all 30+ API modules, invocation patterns via api.run() and direct module calls, parameter conventions, and module categorization. Activates when creating IFC entities, modifying properties, managing spatial structure, or using any ifcopenshell.api function.
1bonsai-impl-bcf
Guides implementation of BIM Collaboration Format (BCF) workflows in Bonsai including creating BCF topics, adding viewpoints with camera snapshots, managing comments, importing/exporting BCF files (v2.1 and v3.0), and integrating BCF issue tracking with IFC element references. Activates when working with BCF files, BIM issue tracking, clash report management, or collaboration workflows in Bonsai.
1ifcos-impl-mep
Guides MEP (Mechanical, Electrical, Plumbing) modeling in IFC using ifcopenshell.api.system including IfcSystem, IfcDistributionElement, ports, connections, flow segments, fittings, and MEP-specific property sets. Activates when creating HVAC systems, piping networks, electrical circuits, or MEP elements in IFC models.
1ifcos-impl-cost
Guides IFC cost management using ifcopenshell.api.cost including cost schedules, cost items, cost values, cost quantities, and 5D BIM workflows. Activates when implementing cost estimation in IFC models, creating cost schedules, or linking quantities to cost items.
1