I am trying to apply a custom shader (OpenGL, but if that's not possible I can learn OSL) to a STL. I will not use any lights, cameras, I'm not going to render it eventually. I would like to have the preview in realtime only to see how mesh modifications affect the colors (coming from the shader only) on its surface.

So in practice I want to be able to compute final color value for each and every place on the surface using the shader. Something like this, where you are given coordinates, and the shader computes colors.

The issue I'm having is the multitude of sources: they refer to different Blender versions with different hardware specs, multiple renderers (which apparently changed in Blender 2.8*), BI/BGE, Nodes, Circles, Eeevee, etc. This causes online tutorials to be incompatible with each other.

Without having much experience with it I am trying to find out whether Blender can be used as a inspection/modification tool in such a way as I described above.

Is this doable? How?


2 Answers 2


You can use viewport draw callback for rendering in the viewport. In your case, I would think of rendering a mesh with a small bias offset over existing meshes to avoid Z-fighting. Then making this mesh semi-transparent with appropriate blending modes to overlay the underlying geometry. Also do not forget to enable depth testing. You can use the GPU module and BGL modules for achieving that.


The example link to shadertoy uses a reference to iTime, i'm not sure if our draw handlers support the time variable (but it might!). I suspect you will not need that ultimately, and it can always be supplied at runtime.

The Blender openGL / shader docs are good enough to get you displaying GLSL shaders, but you will need to dig deeper using external resources if the information isn't extensive enough. Especially if the knowledge vacuum concerns the ins and outs of GLSL. A good place to start is https://wiki.blender.org/wiki/Reference/Release_Notes/2.80/Python_API/Draw_API#Examples

A snippet I like to use is pasted below. It lets you run, and rerun (on and on...) the code so you can see what small code changes do to the final output.

import bpy
import gpu
import bgl
import numpy as np
from random import random
from gpu_extras.batch import batch_for_shader

if hasattr(bpy, 'test_handler'):
    bpy.types.SpaceView3D.draw_handler_remove(bpy.test_handler, 'WINDOW')

mesh = bpy.context.active_object.data

vertices = np.empty((len(mesh.vertices), 3), 'f')
poly_indices = np.empty((len(mesh.loop_triangles), 3), 'i')
edge_indices = np.array(mesh.edge_keys)

mesh.vertices.foreach_get("co", np.reshape(vertices, len(mesh.vertices) * 3))
mesh.loop_triangles.foreach_get("vertices", np.reshape(poly_indices, len(mesh.loop_triangles) * 3))

shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR')
batch = batch_for_shader(shader, 'TRIS', {"pos": vertices}, indices=poly_indices)

wire_shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR')
wire_batch = batch_for_shader(shader, 'LINES', {"pos": vertices}, indices=edge_indices)

def draw():

    bgl.glPolygonOffset(1.0, 1.0)
    shader.uniform_float("color", (0.3, 0.3, 0.3, 1.0))

    wire_shader.uniform_float("color", (1, 1, 0, 1))


bpy.test_handler = bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_VIEW')

In Sverchok we use GLSL shaders to display the meshes we create. It might be worth checking out the code of the viz nodes.

for example in this node (VDMK3, viewer Draw Mk3) you'll see references to imported shaders. You'll get an idea how to pass variables.


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .