gpu.types.GPUOffScreen higher resolution and in separate window


#1

Hi,
I recently discovered the gpu.types.GPUOffScreen class and I’m trying to use it to simply render the 3D viewport into some images, my full code in python if you’re interested (https://blender.stackexchange.com/questions/128174/python-get-image-of-3d-view-for-streaming-realtime-eevee-rendering):

import base64, io, os, bgl, gpu, bpy, threading, time, sys
import numpy as np
from gpu_extras.presets import draw_texture_2d
from PIL import Image
import multiprocessing.pool as mpool

finalPath = bpy.context.scene.render.filepath + "hithere.png"


WIDTH = 512
HEIGHT = 256



offscreen = gpu.types.GPUOffScreen(WIDTH, HEIGHT)
bpy.ops.screen.userpref_show('INVOKE_DEFAULT')
area = bpy.context.window_manager.windows[-1].screen.areas[0]
area.type = 'VIEW_3D'
def draw2():
    global finalPath
    global array
    global WIDTH
    global HEIGHT
    global needsSaving
    global area
    context = bpy.context
    scene = context.scene
    render = scene.render
    camera = scene.camera

    
    view_matrix = scene.camera.matrix_world.inverted()

    projection_matrix = scene.camera.calc_matrix_camera(
        context.depsgraph, 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, (0, 0), WIDTH, HEIGHT)
    
    buffer = bgl.Buffer(bgl.GL_BYTE, WIDTH * HEIGHT * 4)
    bgl.glReadBuffer(bgl.GL_BACK)
    bgl.glReadPixels(0, 0, WIDTH, HEIGHT, bgl.GL_RGBA, bgl.GL_UNSIGNED_BYTE, buffer)
   
    
    needle = threading.Thread(target=saveIt,args=[buffer, finalPath, WIDTH, HEIGHT])
    needle.daemon = True
    needle.start()
    #thread.start_new_thread(saveIt,(buffer, finalPath, WIDTH, HEIGHT))

     
     
def coby(scene):
    frame = scene.frame_current
    folder = scene.render.filepath
    myFormat = "png"#scene.render.image_settings.renderformat.lower()
    outputPath = os.path.join(folder, "%05d.%s" % (frame, myFormat))
    global finalPath
    finalPath = outputPath


    
h = bpy.types.SpaceView3D.draw_handler_add(draw2, (), 'WINDOW', 'POST_PIXEL')
#bpy.app.handlers.frame_change_pre.clear()
#bpy.app.handlers.frame_change_pre.append(coby)


def saveIt(buffer, path, width, height):
    array = np.asarray(buffer, dtype=np.uint8)
    myBytes = array.tobytes()
    im = Image.frombytes("RGBA",(width, height), myBytes)
    rawBytes = io.BytesIO()
    im.save(rawBytes, "PNG")
    rawBytes.seek(0)
    base64Encoded = base64.b64encode(rawBytes.read())
    txt =  "data:image/png;base64," + base64Encoded.decode()
    f = open(finalPath, "wb")
    f.write(base64.decodebytes(base64Encoded))
    f.close()
and I also had to modify the source code as in this answer:https://blender.stackexchange.com/questions/82539/bgl-buffer-to-bytes

SO the thing is everything works if the WIDTH and HEIGHT are just left at the default, because then it doesn’t go out of the viewport and the image doesn’t get smeared… but when I change it to a resolution greater than the 3D view, the output looks something like this:

So as you can see it becomes smeared at the bottom when I ncrease the size, it seems to just be showing more of the 3D view instead of expanding the camera view… I Want to achieve a result similar to the viewport render, where it simply scales up the camera view to the desired resolution… I tried the scale_x and scale_y arguments, but they just made it look pixelated.

SO: if modifying the source code is necessary, how can I get an image buffer of the offscreen render at a higher resolution?