blender-core-gpu
blender-core-gpu
Quick Reference
Critical Warnings
NEVER use the bgl module — it is deprecated since Blender 3.5 and completely removed in Blender 5.0. ALL drawing code MUST use the gpu module.
NEVER use shader name 3D_UNIFORM_COLOR or 3D_FLAT_COLOR in Blender 4.0+ — the 3D_ prefix was removed. Use UNIFORM_COLOR, POLYLINE_UNIFORM_COLOR, etc.
NEVER forget to restore gpu.state to defaults at the end of draw callbacks — failing to restore state corrupts rendering for ALL subsequent draw handlers and Blender's own UI.
NEVER create gpu.types.GPUOffScreen outside a valid OpenGL/GPU context — offscreen buffers require a graphics context (viewport draw callback or bpy.types.SpaceView3D).
NEVER call gpu.shader.from_builtin() or create batches from a background thread — ALL GPU operations MUST execute on the main thread.
ALWAYS remove draw handlers in addon unregister() — leaked handlers cause crashes or persistent ghost overlays.
ALWAYS set viewportSize and lineWidth uniforms when using POLYLINE_* shaders — these are REQUIRED uniforms (Blender 4.0+).
ALWAYS call offscreen.free() when done with offscreen buffers to prevent GPU memory leaks.
Module Overview
| Module | Purpose |
|---|---|
gpu |
Core GPU module — shader creation, state management |
gpu.shader |
Shader compilation, built-in shader access |
gpu.types |
GPU types: GPUShader, GPUBatch, GPUOffScreen, GPUTexture |
gpu.state |
OpenGL-like state: blend, depth, line width, viewport |
gpu.texture |
Texture creation from images |
gpu.matrix |
Model-view-projection matrix stack |
gpu.select |
GPU-based selection utilities |
gpu.platform |
GPU backend info (vendor, renderer, version) |
gpu_extras.batch |
batch_for_shader() helper |
gpu_extras.presets |
draw_circle_2d(), draw_texture_2d() |
Built-in Shaders (Blender 4.0+)
| Shader Name | Geometry | Use Case |
|---|---|---|
'UNIFORM_COLOR' |
Triangles, points | Flat colored filled geometry |
'POLYLINE_UNIFORM_COLOR' |
Lines | Lines with configurable width |
'FLAT_COLOR' |
Triangles | Per-vertex colored (flat shaded) |
'POLYLINE_FLAT_COLOR' |
Lines | Per-vertex colored lines |
'SMOOTH_COLOR' |
Triangles | Per-vertex colored (smooth shaded) |
'POLYLINE_SMOOTH_COLOR' |
Lines | Smooth per-vertex colored lines |
'IMAGE' |
Triangles | Textured quads/geometry |
'IMAGE_COLOR' |
Triangles | Textured with color tint |
Shader Name Version Map
| Blender 3.x Name | Blender 4.0+ Name |
|---|---|
'3D_UNIFORM_COLOR' |
'UNIFORM_COLOR' |
'3D_FLAT_COLOR' |
'FLAT_COLOR' |
'3D_SMOOTH_COLOR' |
'SMOOTH_COLOR' |
'3D_IMAGE' |
'IMAGE' |
'2D_UNIFORM_COLOR' |
'UNIFORM_COLOR' |
'2D_FLAT_COLOR' |
'FLAT_COLOR' |
'2D_SMOOTH_COLOR' |
'SMOOTH_COLOR' |
'2D_IMAGE' |
'IMAGE' |
In Blender 4.0+, the 2D_/3D_ distinction is removed. A single 'UNIFORM_COLOR' works in both 2D and 3D contexts.
Essential Patterns
Pattern 1: Basic Line Drawing with POLYLINE Shader
# Blender 4.0+/5.x — Draw colored lines in 3D viewport
import bpy
import gpu
from gpu_extras.batch import batch_for_shader
def draw_lines():
coords = [(0, 0, 0), (5, 0, 0), (5, 5, 0), (0, 5, 0), (0, 0, 0)]
shader = gpu.shader.from_builtin('POLYLINE_UNIFORM_COLOR')
batch = batch_for_shader(shader, 'LINE_STRIP', {"pos": coords})
gpu.state.blend_set('ALPHA')
gpu.state.line_width_set(2.0)
shader.bind()
region = bpy.context.region
shader.uniform_float("viewportSize", (region.width, region.height))
shader.uniform_float("lineWidth", 2.0)
shader.uniform_float("color", (1.0, 0.0, 0.0, 0.8))
batch.draw(shader)
# ALWAYS restore state
gpu.state.blend_set('NONE')
gpu.state.line_width_set(1.0)
_handle = bpy.types.SpaceView3D.draw_handler_add(draw_lines, (), 'WINDOW', 'POST_VIEW')
# Remove: bpy.types.SpaceView3D.draw_handler_remove(_handle, 'WINDOW')
Pattern 2: Filled Triangles with UNIFORM_COLOR
# Blender 4.0+/5.x — Draw a filled quad (two triangles)
import gpu
from gpu_extras.batch import batch_for_shader
def draw_filled():
verts = [(0, 0, 0), (5, 0, 0), (5, 5, 0), (0, 5, 0)]
indices = ((0, 1, 2), (2, 3, 0))
shader = gpu.shader.from_builtin('UNIFORM_COLOR')
batch = batch_for_shader(shader, 'TRIS', {"pos": verts}, indices=indices)
gpu.state.blend_set('ALPHA')
shader.bind()
shader.uniform_float("color", (0.0, 0.5, 1.0, 0.3))
batch.draw(shader)
gpu.state.blend_set('NONE')
Pattern 3: Draw Handler Registration/Removal
# Blender 3.x/4.x/5.x — Proper handler lifecycle in an addon
import bpy
_draw_handle = None
def register():
global _draw_handle
_draw_handle = bpy.types.SpaceView3D.draw_handler_add(
draw_callback, (), 'WINDOW', 'POST_VIEW'
)
def unregister():
global _draw_handle
if _draw_handle is not None:
bpy.types.SpaceView3D.draw_handler_remove(_draw_handle, 'WINDOW')
_draw_handle = None
Draw Handler Layer Options
| Layer | When | Coordinate Space |
|---|---|---|
'PRE_VIEW' |
Before 3D scene | 3D world space |
'POST_VIEW' |
After 3D scene, before gizmos | 3D world space |
'POST_PIXEL' |
After everything, on top | 2D pixel space |
Pattern 4: Version-Compatible Shader Selection
# Blender 3.x/4.x/5.x — Version-safe shader selection
import bpy
import gpu
def get_line_shader():
if bpy.app.version >= (4, 0, 0):
return gpu.shader.from_builtin('POLYLINE_UNIFORM_COLOR')
else:
return gpu.shader.from_builtin('3D_UNIFORM_COLOR')
def get_flat_shader():
if bpy.app.version >= (4, 0, 0):
return gpu.shader.from_builtin('UNIFORM_COLOR')
else:
return gpu.shader.from_builtin('3D_UNIFORM_COLOR')
Pattern 5: Offscreen Rendering
# Blender 4.x/5.x — Render to offscreen buffer
import gpu
offscreen = gpu.types.GPUOffScreen(512, 512)
with offscreen.bind():
fb = gpu.state.active_framebuffer_get()
fb.clear(color=(0.0, 0.0, 0.0, 0.0))
# Draw operations here (shaders, batches)
texture = offscreen.texture_color # GPUTexture
offscreen.free() # ALWAYS free when done
Pattern 6: GPU State Management
# Blender 3.5+/4.x/5.x — Full state management pattern
import gpu
def draw_with_state():
# Save implicit state by setting explicitly
gpu.state.blend_set('ALPHA')
gpu.state.depth_test_set('LESS_EQUAL')
gpu.state.depth_mask_set(True)
gpu.state.line_width_set(2.0)
gpu.state.point_size_set(5.0)
gpu.state.face_culling_set('BACK')
# ... draw calls ...
# ALWAYS restore defaults
gpu.state.blend_set('NONE')
gpu.state.depth_test_set('NONE')
gpu.state.depth_mask_set(False)
gpu.state.line_width_set(1.0)
gpu.state.point_size_set(1.0)
gpu.state.face_culling_set('NONE')
Common Operations
Drawing 2D Overlays (POST_PIXEL)
# Blender 4.0+/5.x — 2D HUD overlay in pixel coordinates
import bpy
import gpu
from gpu_extras.batch import batch_for_shader
def draw_2d_overlay():
verts = [(10, 10), (200, 10), (200, 50), (10, 50)]
indices = ((0, 1, 2), (2, 3, 0))
shader = gpu.shader.from_builtin('UNIFORM_COLOR')
batch = batch_for_shader(shader, 'TRIS', {"pos": verts}, indices=indices)
gpu.state.blend_set('ALPHA')
shader.bind()
shader.uniform_float("color", (0.0, 0.0, 0.0, 0.5))
batch.draw(shader)
gpu.state.blend_set('NONE')
# POST_PIXEL = 2D pixel space overlay
_handle = bpy.types.SpaceView3D.draw_handler_add(
draw_2d_overlay, (), 'WINDOW', 'POST_PIXEL'
)
Drawing Textured Quads
# Blender 4.0+/5.x — Draw image texture in viewport
import gpu
from gpu_extras.batch import batch_for_shader
def draw_image(texture):
shader = gpu.shader.from_builtin('IMAGE')
batch = batch_for_shader(
shader, 'TRI_FAN',
{
"pos": ((0, 0), (200, 0), (200, 200), (0, 200)),
"texCoord": ((0, 0), (1, 0), (1, 1), (0, 1)),
},
)
shader.bind()
shader.uniform_sampler("image", texture)
batch.draw(shader)
Per-Vertex Colored Geometry
# Blender 4.0+/5.x — Smooth colored triangle
import gpu
from gpu_extras.batch import batch_for_shader
shader = gpu.shader.from_builtin('SMOOTH_COLOR')
batch = batch_for_shader(shader, 'TRIS', {
"pos": [(0, 0, 0), (5, 0, 0), (2.5, 5, 0)],
"color": [(1, 0, 0, 1), (0, 1, 0, 1), (0, 0, 1, 1)],
})
shader.bind()
batch.draw(shader)
Loading Image as GPU Texture
# Blender 4.0+/5.x — Load image to GPU texture (replaces bgl texture binding)
import bpy
import gpu
image = bpy.data.images.load("/path/to/image.png")
texture = gpu.texture.from_image(image)
# Use texture with IMAGE shader via shader.uniform_sampler("image", texture)
BGL-to-gpu Migration Checklist
When migrating code from bgl to gpu:
- Remove ALL
import bglstatements - Replace
bgl.glEnable(bgl.GL_BLEND)→gpu.state.blend_set('ALPHA') - Replace
bgl.glDisable(bgl.GL_BLEND)→gpu.state.blend_set('NONE') - Replace
bgl.glLineWidth(w)→gpu.state.line_width_set(w) - Replace
bgl.glEnable(bgl.GL_DEPTH_TEST)→gpu.state.depth_test_set('LESS_EQUAL') - Replace
bgl.glDisable(bgl.GL_DEPTH_TEST)→gpu.state.depth_test_set('NONE') - Replace
bgl.glDepthMask(GL_TRUE)→gpu.state.depth_mask_set(True) - Replace
bgl.glPointSize(s)→gpu.state.point_size_set(s) - Replace
bgl.glEnable(bgl.GL_LINE_SMOOTH)→ usePOLYLINE_*shaders (no direct replacement) - Replace
image.gl_load()/bgl.glBindTexture()→gpu.texture.from_image(image) - Replace
3D_UNIFORM_COLOR→POLYLINE_UNIFORM_COLOR(for lines) orUNIFORM_COLOR(for triangles) - Replace
3D_FLAT_COLOR→POLYLINE_FLAT_COLOR(for lines) orFLAT_COLOR(for triangles) - Add
viewportSizeandlineWidthuniforms for ALLPOLYLINE_*shaders - Add state restoration at end of every draw callback
- Test on Apple Silicon (Metal backend) — bgl was already non-functional there
BGL-to-gpu API Mapping
| bgl (REMOVED in 5.0) | gpu replacement (3.5+) | Notes |
|---|---|---|
bgl.glEnable(bgl.GL_BLEND) |
gpu.state.blend_set('ALPHA') |
Options: 'ALPHA', 'ADDITIVE', 'ADDITIVE_PREMUL', 'MULTIPLY' |
bgl.glDisable(bgl.GL_BLEND) |
gpu.state.blend_set('NONE') |
|
bgl.glLineWidth(w) |
gpu.state.line_width_set(w) |
Also set lineWidth uniform for POLYLINE shaders |
bgl.glEnable(bgl.GL_DEPTH_TEST) |
gpu.state.depth_test_set('LESS_EQUAL') |
Options: 'NONE', 'LESS', 'LESS_EQUAL', 'EQUAL', 'GREATER' |
bgl.glDisable(bgl.GL_DEPTH_TEST) |
gpu.state.depth_test_set('NONE') |
|
bgl.glDepthMask(GL_TRUE) |
gpu.state.depth_mask_set(True) |
|
bgl.glPointSize(s) |
gpu.state.point_size_set(s) |
|
bgl.glEnable(bgl.GL_LINE_SMOOTH) |
(no direct replacement) | Use POLYLINE_* shaders for antialiased lines |
image.gl_load() / bgl.glBindTexture() |
gpu.texture.from_image(image) |
Completely different API |
Version Timeline
| Version | Change |
|---|---|
| Blender 3.0 | gpu module stable, gpu_extras.batch available |
| Blender 3.5 | bgl module officially deprecated |
| Blender 4.0 | 3D_/2D_ shader name prefixes removed; POLYLINE_* shaders added |
| Blender 5.0 | bgl module completely removed; gpu is the ONLY drawing API |
Reference Links
- references/methods.md — Complete API signatures for gpu, gpu.shader, gpu.state, gpu.types, gpu_extras
- references/examples.md — Working code examples for all drawing scenarios
- references/anti-patterns.md — What NOT to do with GPU drawing
Cross-References
- blender-core-api — bpy.context, draw handler registration, restricted contexts
Official Sources
- https://docs.blender.org/api/current/gpu.html
- https://docs.blender.org/api/current/gpu.shader.html
- https://docs.blender.org/api/current/gpu.types.html
- https://docs.blender.org/api/current/gpu.state.html
- https://docs.blender.org/api/current/gpu_extras.batch.html
- https://docs.blender.org/api/current/gpu_extras.presets.html
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-modifiers
Covers Blender modifier stack API including adding/removing modifiers, applying modifiers via operators, evaluated mesh access via depsgraph, Geometry Nodes modifier input identifiers, and common AEC modifiers (Array, Boolean, Solidify). Activates when working with modifiers programmatically, applying modifiers to meshes, or accessing Geometry Nodes inputs.
1ifcos-impl-validation
Implements IfcOpenShell validation workflows including ifcopenshell.validate for schema compliance checking, ifctester for IDS (Information Delivery Specification) validation, georeference validation across IFC2X3 vs IFC4+ differences, and custom validation rule creation. Covers file-level validation, entity-level checks, property set completeness verification, and automated quality assurance pipelines for IFC models.
1blender-syntax-materials
Covers Blender material and shader node API including Principled BSDF input name changes (4.0), material slot assignment, UV mapping, texture node setup, material_slot_add, and node-based material creation. Activates when creating materials programmatically, assigning textures, setting up shaders, or migrating material code between Blender versions.
1bonsai-impl-drawing
Implements Bonsai drawing and documentation workflows including creating 2D drawings from IFC models, managing drawing views (plans, sections, elevations), annotation placement, sheet layout composition, SVG generation and export, and titleblock management. Covers the complete documentation pipeline from model views through annotated drawings to printable sheet output.
1blender-impl-addons
Guides complete Blender addon development workflows including project structure for multi-file addons, testing strategies, extension packaging for extensions.blender.org, CI/CD pipelines, dependency management, and addon distribution. Activates when building production Blender addons, packaging extensions, or setting up addon development environments.
1