diff options
-rw-r--r-- | doc/python_api/examples/gpu.types.GPUOffScreen.py | 207 |
1 files changed, 139 insertions, 68 deletions
diff --git a/doc/python_api/examples/gpu.types.GPUOffScreen.py b/doc/python_api/examples/gpu.types.GPUOffScreen.py index a1b38837278..b7f11b94a11 100644 --- a/doc/python_api/examples/gpu.types.GPUOffScreen.py +++ b/doc/python_api/examples/gpu.types.GPUOffScreen.py @@ -1,16 +1,58 @@ # Draws an off-screen buffer and display it in the corner of the view. import bpy -from bgl import * - - -class OffScreenDraw(bpy.types.Operator): +import bgl +import gpu +import numpy as np + +g_imageVertSrc = ''' +in vec2 texCoord; +in vec2 pos; + +out vec2 texCoord_interp; + +void main() +{ + gl_Position = vec4(pos.xy, 0.0f, 1.0); + gl_Position.z = 1.0f; + texCoord_interp = texCoord; +} +''' + +g_imageFragSrc = ''' +in vec2 texCoord_interp; +out vec4 fragColor; + +uniform sampler2D image; + +void main() +{ + fragColor = texture(image, texCoord_interp); +} +''' + +g_plane_vertices = np.array([ + ([-1.0, -1.0], [0.0, 0.0]), + ([1.0, -1.0], [1.0, 0.0]), + ([1.0, 1.0], [1.0, 1.0]), + ([1.0, 1.0], [1.0, 1.0]), + ([-1.0, 1.0], [0.0, 1.0]), + ([-1.0, -1.0], [0.0, 0.0]), +], [('pos', 'f4', 2), ('uv', 'f4', 2)]) + + +class VIEW3D_OT_draw_offscreen(bpy.types.Operator): bl_idname = "view3d.offscreen_draw" - bl_label = "View3D Offscreen Draw" + bl_label = "Viewport Offscreen Draw" _handle_calc = None _handle_draw = None is_enabled = False + global_shader = None + batch_plane = None + uniform_image = -1 + shader = None + # manage draw handler @staticmethod def draw_callback_px(self, context): @@ -22,22 +64,21 @@ class OffScreenDraw(bpy.types.Operator): @staticmethod def handle_add(self, context): - OffScreenDraw._handle_draw = bpy.types.SpaceView3D.draw_handler_add( + VIEW3D_OT_draw_offscreen._handle_draw = bpy.types.SpaceView3D.draw_handler_add( self.draw_callback_px, (self, context), 'WINDOW', 'POST_PIXEL', ) @staticmethod def handle_remove(): - if OffScreenDraw._handle_draw is not None: - bpy.types.SpaceView3D.draw_handler_remove(OffScreenDraw._handle_draw, 'WINDOW') + if VIEW3D_OT_draw_offscreen._handle_draw is not None: + bpy.types.SpaceView3D.draw_handler_remove(VIEW3D_OT_draw_offscreen._handle_draw, 'WINDOW') - OffScreenDraw._handle_draw = None + VIEW3D_OT_draw_offscreen._handle_draw = None # off-screen buffer @staticmethod def _setup_offscreen(context): - import gpu scene = context.scene aspect_ratio = scene.render.resolution_x / scene.render.resolution_y @@ -58,86 +99,96 @@ class OffScreenDraw(bpy.types.Operator): modelview_matrix = camera.matrix_world.inverted() projection_matrix = camera.calc_matrix_camera( - render.resolution_x, - render.resolution_y, - render.pixel_aspect_x, - render.pixel_aspect_y, + context.depsgraph, + x=render.resolution_x, + y=render.resolution_y, + scale_x=render.pixel_aspect_x, + scale_y=render.pixel_aspect_y, ) offscreen.draw_view3d( scene, - render_layer, + view_layer, context.space_data, context.region, projection_matrix, modelview_matrix, ) - @staticmethod - def _opengl_draw(context, texture, aspect_ratio, scale): + def _opengl_draw(self, context, texture, aspect_ratio, scale): """ OpenGL code to draw a rectangle in the viewport """ - - glDisable(GL_DEPTH_TEST) - # view setup - glMatrixMode(GL_PROJECTION) - glPushMatrix() - glLoadIdentity() + bgl.glDisable(bgl.GL_DEPTH_TEST) - glMatrixMode(GL_MODELVIEW) - glPushMatrix() - glLoadIdentity() + viewport = bgl.Buffer(bgl.GL_INT, 4) + bgl.glGetIntegerv(bgl.GL_VIEWPORT, viewport) - glOrtho(-1, 1, -1, 1, -15, 15) - gluLookAt(0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0) - - act_tex = Buffer(GL_INT, 1) - glGetIntegerv(GL_TEXTURE_2D, act_tex) - - viewport = Buffer(GL_INT, 4) - glGetIntegerv(GL_VIEWPORT, viewport) + active_texture = bgl.Buffer(bgl.GL_INT, 1) + bgl.glGetIntegerv(bgl.GL_TEXTURE_2D, active_texture) width = int(scale * viewport[2]) height = int(width / aspect_ratio) - glViewport(viewport[0], viewport[1], width, height) - glScissor(viewport[0], viewport[1], width, height) + bgl.glViewport(viewport[0], viewport[1], width, height) + bgl.glScissor(viewport[0], viewport[1], width, height) # draw routine - glEnable(GL_TEXTURE_2D) - glActiveTexture(GL_TEXTURE0) + batch_plane = self.get_batch_plane() - glBindTexture(GL_TEXTURE_2D, texture) + shader = VIEW3D_OT_draw_offscreen.shader + # bind it so we can pass the new uniform values + shader.bind() - texco = [(1, 1), (0, 1), (0, 0), (1, 0)] - verco = [(1.0, 1.0), (-1.0, 1.0), (-1.0, -1.0), (1.0, -1.0)] + bgl.glEnable(bgl.GL_TEXTURE_2D) + bgl.glActiveTexture(bgl.GL_TEXTURE0) + bgl.glBindTexture(bgl.GL_TEXTURE_2D, texture) - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) + shader.uniform_int(VIEW3D_OT_draw_offscreen.uniform_image, 0) + batch_plane.draw() - glColor4f(1.0, 1.0, 1.0, 1.0) + # restoring settings + bgl.glBindTexture(bgl.GL_TEXTURE_2D, active_texture[0]) + bgl.glDisable(bgl.GL_TEXTURE_2D) - glBegin(GL_QUADS) - for i in range(4): - glTexCoord3f(texco[i][0], texco[i][1], 0.0) - glVertex2f(verco[i][0], verco[i][1]) - glEnd() + # reset view + bgl.glViewport(viewport[0], viewport[1], viewport[2], viewport[3]) + bgl.glScissor(viewport[0], viewport[1], viewport[2], viewport[3]) - # restoring settings - glBindTexture(GL_TEXTURE_2D, act_tex[0]) + def get_batch_plane(self): + if self.batch_plane is None: + global g_plane_vertices - glDisable(GL_TEXTURE_2D) + format = gpu.types.GPUVertFormat() + pos_id = format.attr_add( + id="pos", + comp_type="F32", + len=2, + fetch_mode="FLOAT") - # reset view - glMatrixMode(GL_PROJECTION) - glPopMatrix() + uv_id = format.attr_add( + id="texCoord", + comp_type="F32", + len=2, + fetch_mode="FLOAT") - glMatrixMode(GL_MODELVIEW) - glPopMatrix() + vbo = gpu.types.GPUVertBuf( + len=len(g_plane_vertices), + format=format) - glViewport(viewport[0], viewport[1], viewport[2], viewport[3]) - glScissor(viewport[0], viewport[1], viewport[2], viewport[3]) + vbo.fill(id=pos_id, data=g_plane_vertices["pos"]) + vbo.fill(id=uv_id, data=g_plane_vertices["uv"]) + + batch_plane = gpu.types.GPUBatch(type="TRIS", buf=vbo) + shader = self.global_shader + + VIEW3D_OT_draw_offscreen.shader = shader + VIEW3D_OT_draw_offscreen.uniform_image = shader.uniform_from_name("image") + + batch_plane.program_set(shader) + VIEW3D_OT_draw_offscreen.batch_plane = batch_plane + return VIEW3D_OT_draw_offscreen.batch_plane # operator functions @classmethod @@ -148,24 +199,26 @@ class OffScreenDraw(bpy.types.Operator): if context.area: context.area.tag_redraw() + if event.type in {'RIGHTMOUSE', 'ESC'}: + self.cancel(context) + return {'CANCELLED'} + return {'PASS_THROUGH'} def invoke(self, context, event): - if OffScreenDraw.is_enabled: + if VIEW3D_OT_draw_offscreen.is_enabled: self.cancel(context) - return {'FINISHED'} - else: - self._offscreen = OffScreenDraw._setup_offscreen(context) + self._offscreen = VIEW3D_OT_draw_offscreen._setup_offscreen(context) if self._offscreen: self._texture = self._offscreen.color_texture else: self.report({'ERROR'}, "Error initializing offscreen buffer. More details in the console") return {'CANCELLED'} - OffScreenDraw.handle_add(self, context) - OffScreenDraw.is_enabled = True + VIEW3D_OT_draw_offscreen.handle_add(self, context) + VIEW3D_OT_draw_offscreen.is_enabled = True if context.area: context.area.tag_redraw() @@ -174,20 +227,38 @@ class OffScreenDraw(bpy.types.Operator): return {'RUNNING_MODAL'} def cancel(self, context): - OffScreenDraw.handle_remove() - OffScreenDraw.is_enabled = False + VIEW3D_OT_draw_offscreen.handle_remove() + VIEW3D_OT_draw_offscreen.is_enabled = False + + if VIEW3D_OT_draw_offscreen.batch_plane is not None: + del VIEW3D_OT_draw_offscreen.batch_plane + VIEW3D_OT_draw_offscreen.batch_plane = None + + VIEW3D_OT_draw_offscreen.shader = None if context.area: context.area.tag_redraw() def register(): - bpy.utils.register_class(OffScreenDraw) + if hasattr(bpy.types, "VIEW3D_OT_draw_offscreen"): + del VIEW3D_OT_draw_offscreen.global_shader + + shader = gpu.types.GPUShader(g_imageVertSrc, g_imageFragSrc) + VIEW3D_OT_draw_offscreen.global_shader = shader + + bpy.utils.register_class(VIEW3D_OT_draw_offscreen) def unregister(): - bpy.utils.unregister_class(OffScreenDraw) + bpy.utils.unregister_class(VIEW3D_OT_draw_offscreen) + VIEW3D_OT_draw_offscreen.global_shader = None if __name__ == "__main__": + try: + unregister() + except RuntimeError: + pass + register() |