[Bf-blender-cvs] [fbc837b2f8e] blender2.8: Updated gpu.types.GPUOffscreen.py example file

Dalai Felinto noreply at git.blender.org
Fri Sep 21 00:21:35 CEST 2018


Commit: fbc837b2f8e165f313a16843cfef54620a6d86d3
Author: Dalai Felinto
Date:   Thu Sep 20 22:06:51 2018 +0000
Branches: blender2.8
https://developer.blender.org/rBfbc837b2f8e165f313a16843cfef54620a6d86d3

Updated gpu.types.GPUOffscreen.py example file

The image I get is a bit too dark, which is the same I get in the viewport
itself when there is no Display Device. So I believe for cases like this
we need to have color management on top of the buffer.

Also, on EEVEE it looks like it needs to clear some extra buffers. You can see
that, by rotating the camera view around.

That said, this is the first step to bring back fun addons
that use external offscreen buffers.

Note: When using gpu offscreen with POST_VIEW (as oppose to POST_PIXEL)
I get a crash with DST having 0xFF..

===================================================================

M	doc/python_api/examples/gpu.types.GPUOffScreen.py

===================================================================

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()



More information about the Bf-blender-cvs mailing list