1
$\begingroup$

How can I load an image from an images directory in GPU module?

From https://docs.blender.org/api/current/gpu.html#d-image

import bpy
import gpu
import bgl
from gpu_extras.batch import batch_for_shader

IMAGE_NAME = "Untitled"
image = bpy.data.images[IMAGE_NAME]

shader = gpu.shader.from_builtin('2D_IMAGE')
batch = batch_for_shader(
    shader, 'TRI_FAN',
    {
        "pos": ((100, 100), (200, 100), (200, 200), (100, 200)),
        "texCoord": ((0, 0), (1, 0), (1, 1), (0, 1)),
    },
)

if image.gl_load():
    raise Exception()


def draw():
    bgl.glActiveTexture(bgl.GL_TEXTURE0)
    bgl.glBindTexture(bgl.GL_TEXTURE_2D, image.bindcode)

    shader.bind()
    shader.uniform_int("image", 0)
    batch.draw(shader)


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

1 Answer 1

2
$\begingroup$

You can use BlendDataImages.load() to load and assign the image in one go:

>>> image = D.images.load("//textures/your_image.exr")
>>> image
bpy.data.images['your_image.exr']

Following demo is based on the given link to the docs:

enter image description here

import bpy
import gpu
import bgl
from gpu_extras.batch import batch_for_shader

image = bpy.data.images.load("//textures/your_image.exr")

shader = gpu.shader.from_builtin('2D_IMAGE')
batch = batch_for_shader(
    shader, 'TRI_FAN',
    {
        "pos": ((100, 100), (200, 100), (200, 200), (100, 200)),
        "texCoord": ((0, 0), (1, 0), (1, 1), (0, 1)),
    },
)

if image.gl_load():
    raise Exception()


def draw():
    bgl.glActiveTexture(bgl.GL_TEXTURE0)
    bgl.glBindTexture(bgl.GL_TEXTURE_2D, image.bindcode)

    shader.bind()
    shader.uniform_int("image", 0)
    batch.draw(shader)


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

Modal Draw Operator

Following demo is based on our famous Operator Modal View 3D template that comes with Blender. I'd suggest load the image before calling the actual draw method e.g. as part of invoke or register methods... or load it using another operator in the first place.

In order to avoid that Blender loads the same image from disc over and over again, you can pass check_existing=True to BlendDataImages.load() or just get the image via D.images.get("your_image.exr") once loaded:

enter image description here

import bpy
import gpu
import bgl
from gpu_extras.batch import batch_for_shader
import os.path


def draw_callback(self, context):
    shader = gpu.shader.from_builtin('2D_IMAGE')
    batch = batch_for_shader(
        shader, 'TRI_FAN',
        {
            "pos": ((100, 100), (600, 100), (600, 300), (100, 300)),
            "texCoord": ((0, 0), (1, 0), (1, 1), (0, 1)),
        },
    )
    image = self.image
    if image.gl_load():
        raise Exception()

    bgl.glActiveTexture(bgl.GL_TEXTURE0)
    bgl.glBindTexture(bgl.GL_TEXTURE_2D, image.bindcode)
    shader.bind()
    shader.uniform_int("image", 0)
    batch.draw(shader)


class ModalDrawOperator(bpy.types.Operator):
    """Draw a line with the mouse"""
    bl_idname = "view3d.modal_operator"
    bl_label = "Simple Modal View3D Operator"
    
    def modal(self, context, event):
        context.area.tag_redraw()
        if event.type in {'RIGHTMOUSE', 'ESC'}:
            bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
            # Remove the image from the data-blocks
            bpy.data.images.remove(self.image)
            return {'CANCELLED'}
        return {'PASS_THROUGH'} # {'RUNNING_MODAL'}

    def invoke(self, context, event):
        if context.area.type == 'VIEW_3D':
            
            # Load and assign the image
            self.image = bpy.data.images.load("//textures/your_image.exr", check_existing=True)
            # Or just get one from the data-blocks
            #self.image = bpy.data.images.get("your_image.exr")
            
            # Add the region OpenGL drawing callback
            self._handle = bpy.types.SpaceView3D.draw_handler_add(draw_callback, (self, context), 'WINDOW', 'POST_PIXEL')
            context.window_manager.modal_handler_add(self)
            return {'RUNNING_MODAL'}
        else:
            self.report({'WARNING'}, "View3D not found, cannot run operator")
            return {'CANCELLED'}
        
        
def register():
    bpy.utils.register_class(ModalDrawOperator)

def unregister():
    bpy.utils.unregister_class(ModalDrawOperator)

if __name__ == "__main__":
    register()

Make sure the path to your image is correct (line 44), run the script, press F3 in 3d View, type "Simple Modal View3D ..." and hit Enter. Press ESC to kill the image.

$\endgroup$
0

You must log in to answer this question.

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