diff options
author | Dalai Felinto <dfelinto@gmail.com> | 2018-09-21 01:06:51 +0300 |
---|---|---|
committer | Dalai Felinto <dfelinto@gmail.com> | 2018-09-21 01:21:19 +0300 |
commit | fbc837b2f8e165f313a16843cfef54620a6d86d3 (patch) | |
tree | ce513809b5ac1aec79cf20f8eadacf3f4e021ee7 /doc | |
parent | 5340e9ac1b4f4553b0235ab5016b6cda4254ab63 (diff) |
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..
Diffstat (limited to 'doc')
-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() |