Basic gpu examples for Blender 3.5+
Last active
May 22, 2023 16:18
-
-
Save p2or/78daaee234a26f7984f7b447bbf04435 to your computer and use it in GitHub Desktop.
Modal-Draw 2d & 3d (gpu, blf) #Blender
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import bpy | |
import math | |
import gpu, blf | |
from gpu_extras.batch import batch_for_shader | |
from mathutils import Vector | |
def draw_mouse_path(coords, color, width=1.0): | |
shader = gpu.shader.from_builtin('UNIFORM_COLOR') | |
gpu.state.line_width_set(width) | |
batch = batch_for_shader(shader, 'LINE_STRIP', {"pos": coords}) | |
shader.uniform_float("color", color) | |
batch.draw(shader) | |
def draw_poly(coords, color, width=1.0): | |
shader = gpu.shader.from_builtin('2D_UNIFORM_COLOR') | |
gpu.state.line_width_set(width) | |
batch = batch_for_shader(shader,'LINE_STRIP', {"pos": coords}) | |
shader.bind() | |
shader.uniform_float("color", color) | |
batch.draw(shader) | |
def draw_circle_2d(color, cx, cy, r, num_segments, width=1.0): | |
theta = 2 * math.pi / num_segments | |
c = math.cos(theta) | |
s = math.sin(theta) | |
x = r # we start at angle = 0 | |
y = 0 | |
vector_list = [] | |
for i in range (num_segments+1): | |
vector_list.append(Vector((x + cx, y + cy))) | |
t = x | |
x = c * x - s * y | |
y = s * t + c * y | |
draw_poly(vector_list, color, width) | |
def draw_line_2d(color, start, end, width=1.0): | |
shader = gpu.shader.from_builtin('2D_UNIFORM_COLOR') | |
gpu.state.line_width_set(width) | |
batch = batch_for_shader(shader, 'LINES', {"pos": [start,end]}) | |
shader.bind() | |
shader.uniform_float("color", color) | |
batch.draw(shader) | |
def draw_type_2d(color, text, size=17): | |
font_id = 0 | |
blf.position(font_id, 20, 70, 0) | |
blf.color(font_id, *color) | |
blf.size(font_id, size*(bpy.context.preferences.system.dpi/72)) | |
blf.draw(font_id, text) | |
def draw_callback_2d(self, context): | |
# ...api_current/bpy.types.Area.html?highlight=bpy.types.area | |
editor_width = context.area.width | |
editor_height = context.area.height - context.area.regions[0].height | |
# set the gpu state | |
gpu.state.blend_set('ALPHA') | |
# draw each shape | |
draw_mouse_path(self.mouse_path, (1.0, 1.0, 1.0, 1.0), 1.0) | |
draw_line_2d((0.0, 1.0, 0.0, 0.8), (0,0), (editor_width, editor_height), 3.0) | |
draw_line_2d((1.0, 1.0, 0.0, 0.8), (editor_width, 0), (0, editor_height), 1.0) | |
draw_circle_2d((1.0, 1.0, 1.0, 0.6), editor_width*.5, editor_height*.5, 70, 360, 1) | |
draw_circle_2d((1.0, 0.0, 0.0, 0.4), editor_width*.5, editor_height*.5, 230, 5) | |
# draw the text | |
hud = "Hello Word {} {}".format(len(self.mouse_path), self.mouse_path[-1]) | |
draw_type_2d((1.0, 1.0, 1.0, 0.8), hud) | |
# restore gpu defaults | |
gpu.state.line_width_set(1.0) | |
gpu.state.blend_set('NONE') | |
class ModalDrawOperator(bpy.types.Operator): | |
"""Draw 2d Operator""" | |
bl_idname = "node.modal_draw_operator" | |
bl_label = "Simple Modal Node Editor Operator" | |
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': | |
bpy.types.SpaceNodeEditor.draw_handler_remove(self._handle, 'WINDOW') | |
return {'FINISHED'} | |
elif event.type in {'RIGHTMOUSE', 'ESC'}: | |
bpy.types.SpaceNodeEditor.draw_handler_remove(self._handle, 'WINDOW') | |
return {'CANCELLED'} | |
return {'RUNNING_MODAL'} | |
def invoke(self, context, event): | |
if context.area.type == 'NODE_EDITOR': | |
# 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.SpaceNodeEditor.draw_handler_add(draw_callback_2d, args, 'WINDOW', 'POST_PIXEL') | |
self.mouse_path = [] | |
context.window_manager.modal_handler_add(self) | |
return {'RUNNING_MODAL'} | |
else: | |
self.report({'WARNING'}, "NodeEditor not found, cannot run operator") | |
return {'CANCELLED'} | |
def menu_func(self, context): | |
self.layout.operator(ModalDrawOperator.bl_idname, text="Modal Draw Operator") | |
# Register and add to the "view" menu (required to also use F3 search "Modal Draw Operator" for quick access). | |
def register(): | |
bpy.utils.register_class(ModalDrawOperator) | |
bpy.types.NODE_MT_view.append(menu_func) | |
def unregister(): | |
bpy.utils.unregister_class(ModalDrawOperator) | |
bpy.types.NODE_MT_view.remove(menu_func) | |
if __name__ == "__main__": | |
register() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import bpy | |
import blf | |
import gpu | |
from gpu_extras.batch import batch_for_shader | |
def draw_line_3d(color, start, end, width=1.0): | |
shader = gpu.shader.from_builtin('2D_UNIFORM_COLOR') | |
gpu.state.line_width_set(width) | |
batch = batch_for_shader(shader, 'LINES', {"pos": [start,end]}) | |
shader.bind() | |
shader.uniform_float("color", color) | |
batch.draw(shader) | |
def draw_type_2d(color, text, size=17): | |
font_id = 0 | |
blf.position(font_id, 20, 70, 0) | |
blf.color(font_id, *color) | |
blf.size(font_id, size*(bpy.context.preferences.system.dpi/72)) | |
blf.draw(font_id, text) | |
def draw_callback_3d(self, context): | |
cube_loc = context.scene.objects['Cube'].location | |
lamp_loc = context.scene.objects['Light'].location | |
camera_loc = context.scene.objects['Camera'].location | |
# set the gpu state | |
gpu.state.blend_set('ALPHA') | |
# green, red and blue line | |
draw_line_3d((0.0, 1.0, 0.0, 0.7), camera_loc, cube_loc) | |
draw_line_3d((1.0, 0.0, 0.0, 0.7), cube_loc, lamp_loc) | |
draw_line_3d((0.0, 0.0, 1.0, 0.7), lamp_loc, camera_loc) | |
# restore gpu defaults | |
gpu.state.line_width_set(1.0) | |
gpu.state.blend_set('NONE') | |
def draw_callback_2d(self, context): | |
gpu.state.blend_set('ALPHA') | |
# dynamic text | |
hud = "Hello Word {} {}".format(len(self.mouse_path), self.mouse_path[-1]) | |
draw_type_2d((1.0, 0.5, 0.0, 0.8), hud) | |
# restore gpu defaults | |
gpu.state.line_width_set(1.0) | |
gpu.state.blend_set('NONE') | |
class ModalDrawOperator(bpy.types.Operator): | |
"""Draw 3d Operator""" | |
bl_idname = "view3d.modal_draw_operator" | |
bl_label = "Simple Modal View3D Operator" | |
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)) | |
if event.type in {'RIGHTMOUSE', 'ESC'}: | |
bpy.types.SpaceView3D.draw_handler_remove(self._handle_3d, 'WINDOW') | |
bpy.types.SpaceView3D.draw_handler_remove(self._handle_2d, 'WINDOW') | |
return {'CANCELLED'} | |
return {'PASS_THROUGH'} | |
#return {'RUNNING_MODAL'} | |
def invoke(self, context, event): | |
if context.area.type == 'VIEW_3D': | |
# the arguments we pass the the callback | |
args = (self, context) | |
# draw in view space with 'POST_VIEW' and 'PRE_VIEW' | |
self._handle_3d = bpy.types.SpaceView3D.draw_handler_add(draw_callback_3d, args, 'WINDOW', 'POST_VIEW') | |
self._handle_2d = bpy.types.SpaceView3D.draw_handler_add(draw_callback_2d, args, 'WINDOW', 'POST_PIXEL') | |
self.mouse_path = [] | |
context.window_manager.modal_handler_add(self) | |
return {'RUNNING_MODAL'} | |
else: | |
self.report({'WARNING'}, "View3D not found, cannot run operator") | |
return {'CANCELLED'} | |
def menu_func(self, context): | |
self.layout.operator(ModalDrawOperator.bl_idname, text="Modal Draw Operator") | |
# Register and add to the "view" menu (required to also use F3 search "Modal Draw Operator" for quick access). | |
def register(): | |
bpy.utils.register_class(ModalDrawOperator) | |
bpy.types.VIEW3D_MT_view.append(menu_func) | |
def unregister(): | |
bpy.utils.unregister_class(ModalDrawOperator) | |
bpy.types.VIEW3D_MT_view.remove(menu_func) | |
if __name__ == "__main__": | |
register() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment