5
$\begingroup$

For a while now in blender there has been this GPU Off-screen renderer; however, I think it has changed a bit in 2.8, and plus, I never even knew how to use it before.

Basically I want to be able to render a video animation using the offscreen rendering API, specifically the "3D View into Texture" example, here is the code from the docs on the website:

import bpy
import bgl
import gpu
from gpu_extras.presets import draw_texture_2d

WIDTH = 512
HEIGHT = 256

offscreen = gpu.types.GPUOffScreen(WIDTH, HEIGHT)


def draw():
    context = bpy.context
    scene = context.scene

    view_matrix = scene.camera.matrix_world.inverted()

    projection_matrix = scene.camera.calc_matrix_camera(
        context.evaluated_depsgraph_get(), x=WIDTH, y=HEIGHT)

    offscreen.draw_view3d(
        scene,
        context.view_layer,
        context.space_data,
        context.region,
        view_matrix,
        projection_matrix)

    bgl.glDisable(bgl.GL_DEPTH_TEST)
    draw_texture_2d(offscreen.color_texture, (10, 10), WIDTH, HEIGHT)


bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_PIXEL')

Although this works great for making a texture, it doesn't explain how to use this to save the image, I want to eventually implement an interface that will save the image, or store it into some kind of base64 image buffer (To send to a server) to render faster / real time, but even more importantly: it doesn't explain how to change the resolution of the output, so:

How exactly do I render (e.g. save onto disk OR store in buffer) a simple animation (I.e, image sequence) using the GPU Off-Screen Render API, at any given resolution (even 1920 / 1080) in Blender 2.8?

$\endgroup$
2
  • $\begingroup$ Isn't there an example on same page that creates a texture image of circles? $\endgroup$
    – batFINGER
    May 10, 2020 at 22:51
  • $\begingroup$ @batFINGER yes, there is and it gives some important insights - I managed to write the 3D view into an image. However, I can not execute offscreen.draw_view3d(...) without bpy.types.SpaceView3D.draw_handler_add(draw, ...), which makes my current state a bit messy ... $\endgroup$ May 11, 2020 at 6:11

1 Answer 1

2
$\begingroup$

The following code shows the essential steps to write the 3D view into a Blender image.

The main caveat is that the currently offscreen.draw_view3d() is called within draw() using bpy.types.SpaceView3D.draw_handler_add. This has a few consequences:

  • one must ensure that the 3D view is redrawn, for example by clicking onto some object in the 3D view
  • the function is called multiple times

When moving offscreen.draw_view3d() outside of draw(), I received the following error message: TypeError: expected 'SpaceView3D' type found 'SpaceTextEditor' instead. So currently, I'm stuck setting the correct context. Any help would be highly appreciated - I'll update the post correspondingly.

import bpy
import bgl
import gpu
from mathutils import Matrix
from gpu.types import GPUOffScreen


def draw():

    print('draw: bpy.context.area.type',  bpy.context.area.type)
    global write_view_3d

    if write_view_3d:

        # Write the image into the offscreen buffer
        offscreen.draw_view3d(
            scene=scene,
            view_layer=bpy.context.view_layer,
            view3d=bpy.context.space_data,
            region=bpy.context.region,
            view_matrix=view_matrix,
            projection_matrix=projection_matrix)

        buffer = bgl.Buffer(bgl.GL_BYTE, width * height * 4)
        bgl.glReadPixels(0, 0, width, height, bgl.GL_RGBA, bgl.GL_UNSIGNED_BYTE, buffer)

        if(image_name not in bpy.data.images):
            bpy.data.images.new(image_name, width, height)
        image = bpy.data.images[image_name]
        image.pixels = [v / 255 for v in buffer]

        print('write_view_3d', write_view_3d)
        write_view_3d = False
    else:
        print('write_view_3d', write_view_3d)

image_name = "Result"
scene = bpy.context.scene
render = bpy.context.scene.render
width = bpy.context.region.width
height = bpy.context.region.height

offscreen = gpu.types.GPUOffScreen(width, height)
view_matrix = scene.camera.matrix_world.inverted()
projection_matrix = scene.camera.calc_matrix_camera(
    bpy.context.evaluated_depsgraph_get(), 
    x=width,
    y=height)

write_view_3d = True
current_draw_handler = bpy.types.SpaceView3D.draw_handler_add(
    draw, (), 'WINDOW', 'POST_PIXEL')
$\endgroup$
9
  • $\begingroup$ interesting, any way to get the resolution to 1920 x 1080 even if the 3d view window is smaller than that? $\endgroup$ May 11, 2020 at 8:20
  • $\begingroup$ resize the image. $\endgroup$
    – batFINGER
    May 14, 2020 at 18:31
  • $\begingroup$ @batFINGER how would one do that? and does that change the quality of the scene itself? $\endgroup$ May 31, 2020 at 6:56
  • $\begingroup$ No it resizes the image IIRC its Image.resize(x, y) of a blender image instance. Wont be the resolution just the size.... previous comment needed a question mark. $\endgroup$
    – batFINGER
    May 31, 2020 at 10:08
  • 1
    $\begingroup$ @Mr.EpicFail that is no where near real time rendering $\endgroup$ Aug 9, 2020 at 12:20

You must log in to answer this question.

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