2
$\begingroup$

Im trying to draw a circle using the GPU/BGL module that appears on a given certain 3D position (in my example, the cursor's location) and, when drawing, it points towards the current view.

I'm using:

import bpy, gpu, bgl, blf, bpy_extras
from gpu_extras.presets import draw_circle_2d

class circle_outline(bpy.types.Operator):
    bl_idname = "object.circle_cursor"
    bl_label = "GPU Circle Draw in cursor"
    bl_options = {"REGISTER", "UNDO"}
    
    def execute(self, context):
        def draw_circle():
            cursor_pos = bpy.context.scene.cursor.location
            pos = cursor_pos

            draw_circle_2d(pos, [1,0.3,0.3,0.4], 3.0, segments=100)

        h = bpy.types.SpaceView3D.draw_handler_add(draw_circle, (),'WINDOW', 'POST_VIEW')
        context.area.tag_redraw()
        return {'FINISHED'}


if __name__ == "__main__":
    bpy.utils.register_class(circle_outline)

Note: I know I can draw directly in the screen like 2D using "POST_PIXEL" in the bpy.types.SpaceView3D.draw_handler_add(), but I need the circle to be in 3D.

At the moment, the circle is being drawn, but everything is drawn in the XY plane:

enter image description here

My goal is to have it looking towards the view, like:

enter image description here

I think I may be missing some matrix transformation or rotation, but I'm kinda lost.

Any idea?

Thank you so much.

$\endgroup$
0

1 Answer 1

1
$\begingroup$

Use gpu.matrix.multiply_matrix to multiply the matrix before drawing

Press F7 in the viewport to run the modal

import bpy, gpu, blf, bpy_extras
from gpu_extras.presets import draw_circle_2d

class circle_outline(bpy.types.Operator):
    bl_idname = "object.circle_cursor"
    bl_label = "GPU Circle Draw in cursor"
    bl_options = {"REGISTER", "UNDO"}
    
    def invoke(self, context, event):
        r3d = context.space_data.region_3d

        def draw_circle():
            cursor_pos = bpy.context.scene.cursor.location
            pos = cursor_pos

            # gpu.matrix.load_projection_matrix(..) # set it directly
            gpu.matrix.multiply_matrix(r3d.view_rotation.to_matrix().to_4x4())
            gpu.matrix.scale([2, 2, 2]) # double size
            draw_circle_2d(pos, [1,0.3,0.3,0.4], 3.0, segments=100)
            gpu.matrix.load_identity() # reset
            # draw other things...

        self.h = bpy.types.SpaceView3D.draw_handler_add(draw_circle, (),'WINDOW', 'POST_VIEW')
        context.area.tag_redraw()
        context.window_manager.modal_handler_add(self)
        return {'RUNNING_MODAL'}

    def modal(self, context, event):
        if event.type == 'ESC':
            bpy.types.SpaceView3D.draw_handler_remove(self.h, 'WINDOW')
            return {'CANCELLED'}
        return {'RUNNING_MODAL'}


if __name__ == "__main__":
    cls = circle_outline
    bpy.utils.register_class(cls)

    # add a keymap to test. If there is a conflict with F7, choose other
    key_map_type = "F7"

    wm = bpy.context.window_manager
    kc = wm.keyconfigs.addon
    if kc:
        km_name = "Window"
        km = kc.keymaps[km_name] if km_name in kc.keymaps else kc.keymaps.new(name=km_name)

        if not any(e.idname == cls.bl_idname  for e in km.keymap_items):
            kmi = km.keymap_items.new(cls.bl_idname, type=key_map_type, value='PRESS')
$\endgroup$
1
  • $\begingroup$ Works as a charm. Very much appreciated friend, thank you so much :) $\endgroup$
    – Ommadawn
    Nov 19, 2023 at 10:27

You must log in to answer this question.

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