(no more) BGL in 2.8

There seems to be a bit of uncertainty in regards to the bgl module in 2.8, with parts of it not working, having been removed, and some talk of bgl being removed completely.

I*m starting this thread to collect what we know. Hopefully, we can get some official input as well.

Here’s some links, with bits of information but leaving a lot of uncertainty:




For those unaware, bgl is an opengl wrapper allowing addon developers to essentially draw anything on top of the 3d view. It’s used heavily by various popular addons, such as retopoflow, boxcutter, speedflow, relast etc.

1 Like

Info from Dalai Felinto

If you really really want to, you can get it to work right now.

The API may change but you can actually draw things with 2.8 + OpenGL. For example:
https://developer.blender.org/diffusion/B/browse/blender2.8/doc/python_api/examples/gpu.types.GPUOffScreen.py

1 Like

Is this still relevant? https://developer.blender.org/T49043

1 Like

How to draw point in bgl 2.8 (based on - https://developer.blender.org/D3688 - draw lines by mano-wii)

import bpy
import bgl
import blf
import gpu
import numpy as np


g_vertSrc = '''
uniform mat4 viewproj;

in vec3 pos;

void main()
{
	gl_Position = viewproj * vec4(pos, 1.0);
}

'''

g_fragSrc = '''
uniform vec4 color;

out vec4 fragColor;

void main()
{
	fragColor = color;
}
'''
g_plane_vertices = np.array([ ([0.5, 0.5, 0]),], [('pos', 'f4', 3)])

class SnapDrawn():
    def __init__(self):
        self._format = gpu.types.GPUVertFormat()
        self._pos_id = self._format.attr_add(
                id = "pos",
                comp_type = "F32",
                len = 3,
                fetch_mode = "FLOAT")

        self.shader = gpu.types.GPUShader(g_vertSrc, g_fragSrc)
        self.unif_color = self.shader.uniform_from_name("color")
        self.color = np.array([1.0, 0.8, 0.0, 0.5], 'f')
        
        self.per_mat = self.shader.uniform_from_name("viewproj")


    def batch_line_strip_create(self, coords):
        global g_plane_vertices
        vbo = gpu.types.GPUVertBuf(len = len(g_plane_vertices), format = self._format)
        vbo.fill(id = self._pos_id, data = g_plane_vertices)

        batch_lines = gpu.types.GPUBatch(type = "POINTS", buf = vbo)
        #batch_lines.program_set_builtin(id = "2D_UNIFORM_COLOR")
        batch_lines.program_set(self.shader)

        return batch_lines


    def draw(self, list_verts_co, rv3d):
        

        batch = self.batch_line_strip_create(list_verts_co)

        #batch.uniform_f32("color", 1.0, 0.8, 0.0, 0.5)
        self.shader.uniform_vector_float(self.unif_color, self.color, 4)
        
        
       
        viewproj = np.array(rv3d.perspective_matrix.transposed(), 'f')
        self.shader.bind()
        self.shader.uniform_vector_float(self.per_mat, viewproj, 16)
        
        batch.draw()
        del batch


def draw_callback_px(self, context):
    print("mouse points", len(self.mouse_path))

    font_id = 0  # XXX, need to find out how best to get this.

    # draw some text
    blf.position(font_id, 15, 30, 0)
    blf.size(font_id, 20, 72)
    blf.draw(font_id, "Hello Word " + str(len(self.mouse_path)))

    # 50% alpha, 2 pixel width line
    bgl.glEnable(bgl.GL_BLEND)
    bgl.glLineWidth(2.0)

    self.snap_draw.draw(self.mouse_path, self.rv3d)

    #restore opengl defaults
    bgl.glLineWidth(1)
    bgl.glDisable(bgl.GL_BLEND)


class ModalDrawOperator(bpy.types.Operator):
    """Draw a line with the mouse"""
    bl_idname = "view3d.modal_operator"
    bl_label = "Simple Modal View3D Operator"
    
    global_shader = None
    unif_viewproj = -1
   
    def modal(self, context, event):
        context.area.tag_redraw()

        if event.type == 'MOUSEMOVE':
            self.mouse_path.append((event.mouse_region_x, event.mouse_region_y))

        elif event.type == 'LEFTMOUSE':
            del self.snap_draw
            bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
            return {'FINISHED'}

        elif event.type in {'RIGHTMOUSE', 'ESC'}:
            del self.snap_draw
            bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
            return {'CANCELLED'}

        return {'PASS_THROUGH'}

    def invoke(self, context, event):
        if context.area.type == 'VIEW_3D':
            self.rv3d = context.region_data
           
            # the arguments we pass the the callback
            args = (self, context)
            # Add the region OpenGL drawing callback
            # draw in view space with 'POST_VIEW' and 'PRE_VIEW'
            self._handle = bpy.types.SpaceView3D.draw_handler_add(draw_callback_px, args, 'WINDOW', 'POST_PIXEL')

            self.mouse_path = []
            self.snap_draw = SnapDrawn()

            context.window_manager.modal_handler_add(self)
            return {'RUNNING_MODAL'}
        else:
            self.report({'WARNING'}, "View3D not found, cannot run operator")
            return {'CANCELLED'}


def register():
    bpy.utils.register_class(ModalDrawOperator)


def unregister():
    bpy.utils.unregister_class(ModalDrawOperator)


if __name__ == "__main__":
    register()
1 Like

Heads up !
those examples will get outdated fast as long as we do not have a definite API

Very nice, thanks! I’ll take a closer look in a bit.

https://wiki.blender.org/wiki/Reference/Release_Notes/2.80/Python_API/Draw_API

Awesome , it’s finally here and this seems much more powerful than old bgl.

Just a question, let’s say I want to draw several lines, is it ok to make several :
batch = shader.new_batch(‘LINES’, {“pos” : coords}) ?

Or it’s better to put them all in the same batch ? if this the case does someone know how ?
I’ve read that it’s better to upload all at once to the GPU, but maybe this is where you’ll use :
shader.bind()
shader.uniform_float(“color”, (1, 1, 0, 1))
batch.draw(shader)

I know this is old, im trying to test this on OSX. Does this GPU type only work when a proper GPU is available?

I think it should work for all gpus (I only know it works on nvidia on Win and Linux)

It does work on same platform / gpu than eevee.