RenderEngine(bpy_struct)

Simple Render Engine


import bpy
import bgl


class CustomRenderEngine(bpy.types.RenderEngine):
    # These three members are used by blender to set up the
    # RenderEngine; define its internal name, visible name and capabilities.
    bl_idname = "CUSTOM"
    bl_label = "Custom"
    bl_use_preview = True

    # Init is called whenever a new render engine instance is created. Multiple
    # instances may exist at the same time, for example for a viewport and final
    # render.
    def __init__(self):
        self.scene_data = None
        self.draw_data = None

    # When the render engine instance is destroy, this is called. Clean up any
    # render engine data here, for example stopping running render threads.
    def __del__(self):
        pass

    # This is the method called by Blender for both final renders (F12) and
    # small preview for materials, world and lights.
    def render(self, depsgraph):
        scene = depsgraph.scene
        scale = scene.render.resolution_percentage / 100.0
        self.size_x = int(scene.render.resolution_x * scale)
        self.size_y = int(scene.render.resolution_y * scale)

        # Fill the render result with a flat color. The framebuffer is
        # defined as a list of pixels, each pixel itself being a list of
        # R,G,B,A values.
        if self.is_preview:
            color = [0.1, 0.2, 0.1, 1.0]
        else:
            color = [0.2, 0.1, 0.1, 1.0]

        pixel_count = self.size_x * self.size_y
        rect = [color] * pixel_count

        # Here we write the pixel values to the RenderResult
        result = self.begin_result(0, 0, self.size_x, self.size_y)
        layer = result.layers[0].passes["Combined"]
        layer.rect = rect
        self.end_result(result)

    # For viewport renders, this method gets called once at the start and
    # whenever the scene or 3D viewport changes. This method is where data
    # should be read from Blender in the same thread. Typically a render
    # thread will be started to do the work while keeping Blender responsive.
    def view_update(self, context, depsgraph):
        region = context.region
        view3d = context.space_data
        scene = depsgraph.scene

        # Get viewport dimensions
        dimensions = region.width, region.height

        if not self.scene_data:
            # First time initialization
            self.scene_data = []
            first_time = True

            # Loop over all datablocks used in the scene.
            for datablock in depsgraph.ids:
                pass
        else:
            first_time = False

            # Test which datablocks changed
            for update in depsgraph.updates:
                print("Datablock updated: ", update.id.name)

            # Test if any material was added, removed or changed.
            if depsgraph.id_type_updated('MATERIAL'):
                print("Materials updated")

        # Loop over all object instances in the scene.
        if first_time or depsgraph.id_type_updated('OBJECT'):
            for instance in depsgraph.object_instances:
                pass

    # For viewport renders, this method is called whenever Blender redraws
    # the 3D viewport. The renderer is expected to quickly draw the render
    # with OpenGL, and not perform other expensive work.
    # Blender will draw overlays for selection and editing on top of the
    # rendered image automatically.
    def view_draw(self, context, depsgraph):
        region = context.region
        scene = depsgraph.scene

        # Get viewport dimensions
        dimensions = region.width, region.height

        # Bind shader that converts from scene linear to display space,
        bgl.glEnable(bgl.GL_BLEND)
        bgl.glBlendFunc(bgl.GL_ONE, bgl.GL_ONE_MINUS_SRC_ALPHA);
        self.bind_display_space_shader(scene)

        if not self.draw_data or self.draw_data.dimensions != dimensions:
            self.draw_data = CustomDrawData(dimensions)

        self.draw_data.draw()

        self.unbind_display_space_shader()
        bgl.glDisable(bgl.GL_BLEND)


class CustomDrawData:
    def __init__(self, dimensions):
        # Generate dummy float image buffer
        self.dimensions = dimensions
        width, height = dimensions

        pixels = [0.1, 0.2, 0.1, 1.0] * width * height
        pixels = bgl.Buffer(bgl.GL_FLOAT, width * height * 4, pixels)

        # Generate texture
        self.texture = bgl.Buffer(bgl.GL_INT, 1)
        bgl.glGenTextures(1, self.texture)
        bgl.glActiveTexture(bgl.GL_TEXTURE0)
        bgl.glBindTexture(bgl.GL_TEXTURE_2D, self.texture[0])
        bgl.glTexImage2D(bgl.GL_TEXTURE_2D, 0, bgl.GL_RGBA16F, width, height, 0, bgl.GL_RGBA, bgl.GL_FLOAT, pixels)
        bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MIN_FILTER, bgl.GL_LINEAR)
        bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MAG_FILTER, bgl.GL_LINEAR)
        bgl.glBindTexture(bgl.GL_TEXTURE_2D, 0)

        # Bind shader that converts from scene linear to display space,
        # use the scene's color management settings.
        shader_program = bgl.Buffer(bgl.GL_INT, 1)
        bgl.glGetIntegerv(bgl.GL_CURRENT_PROGRAM, shader_program);

        # Generate vertex array
        self.vertex_array = bgl.Buffer(bgl.GL_INT, 1)
        bgl.glGenVertexArrays(1, self.vertex_array)
        bgl.glBindVertexArray(self.vertex_array[0])

        texturecoord_location = bgl.glGetAttribLocation(shader_program[0], "texCoord");
        position_location = bgl.glGetAttribLocation(shader_program[0], "pos");

        bgl.glEnableVertexAttribArray(texturecoord_location);
        bgl.glEnableVertexAttribArray(position_location);

        # Generate geometry buffers for drawing textured quad
        position = [0.0, 0.0, width, 0.0, width, height, 0.0, height]
        position = bgl.Buffer(bgl.GL_FLOAT, len(position), position)
        texcoord = [0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0]
        texcoord = bgl.Buffer(bgl.GL_FLOAT, len(texcoord), texcoord)

        self.vertex_buffer = bgl.Buffer(bgl.GL_INT, 2)

        bgl.glGenBuffers(2, self.vertex_buffer)
        bgl.glBindBuffer(bgl.GL_ARRAY_BUFFER, self.vertex_buffer[0])
        bgl.glBufferData(bgl.GL_ARRAY_BUFFER, 32, position, bgl.GL_STATIC_DRAW)
        bgl.glVertexAttribPointer(position_location, 2, bgl.GL_FLOAT, bgl.GL_FALSE, 0, None)

        bgl.glBindBuffer(bgl.GL_ARRAY_BUFFER, self.vertex_buffer[1])
        bgl.glBufferData(bgl.GL_ARRAY_BUFFER, 32, texcoord, bgl.GL_STATIC_DRAW)
        bgl.glVertexAttribPointer(texturecoord_location, 2, bgl.GL_FLOAT, bgl.GL_FALSE, 0, None)

        bgl.glBindBuffer(bgl.GL_ARRAY_BUFFER, 0)
        bgl.glBindVertexArray(0)

    def __del__(self):
        bgl.glDeleteBuffers(2, self.vertex_buffer)
        bgl.glDeleteVertexArrays(1, self.vertex_array)
        bgl.glBindTexture(bgl.GL_TEXTURE_2D, 0)
        bgl.glDeleteTextures(1, self.texture)

    def draw(self):
        bgl.glActiveTexture(bgl.GL_TEXTURE0)
        bgl.glBindTexture(bgl.GL_TEXTURE_2D, self.texture[0])
        bgl.glBindVertexArray(self.vertex_array[0])
        bgl.glDrawArrays(bgl.GL_TRIANGLE_FAN, 0, 4);
        bgl.glBindVertexArray(0)
        bgl.glBindTexture(bgl.GL_TEXTURE_2D, 0)


# RenderEngines also need to tell UI Panels that they are compatible with.
# We recommend to enable all panels marked as BLENDER_RENDER, and then
# exclude any panels that are replaced by custom panels registered by the
# render engine, or that are not supported.
def get_panels():
    exclude_panels = {
        'VIEWLAYER_PT_filter',
        'VIEWLAYER_PT_layer_passes',
    }

    panels = []
    for panel in bpy.types.Panel.__subclasses__():
        if hasattr(panel, 'COMPAT_ENGINES') and 'BLENDER_RENDER' in panel.COMPAT_ENGINES:
            if panel.__name__ not in exclude_panels:
                panels.append(panel)

    return panels

def register():
    # Register the RenderEngine
    bpy.utils.register_class(CustomRenderEngine)

    for panel in get_panels():
        panel.COMPAT_ENGINES.add('CUSTOM')

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

    for panel in get_panels():
        if 'CUSTOM' in panel.COMPAT_ENGINES:
            panel.COMPAT_ENGINES.remove('CUSTOM')


if __name__ == "__main__":
    register()

base class — bpy_struct

class bpy.types.RenderEngine(bpy_struct)

Render engine

bl_idname
Type:string, default “”, (never None)
bl_label
Type:string, default “”, (never None)
bl_use_exclude_layers
Type:boolean, default False
bl_use_postprocess
Type:boolean, default False
bl_use_preview
Type:boolean, default False
bl_use_save_buffers
Type:boolean, default False
bl_use_shading_nodes
Type:boolean, default False
bl_use_shading_nodes_custom
Type:boolean, default True
bl_use_spherical_stereo
Type:boolean, default False
camera_override
Type:Object, (readonly)
is_animation
Type:boolean, default False
is_preview
Type:boolean, default False
layer_override
Type:boolean array of 20 items, default (False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False)
render
Type:RenderSettings, (readonly)
resolution_x
Type:int in [-inf, inf], default 0, (readonly)
resolution_y
Type:int in [-inf, inf], default 0, (readonly)
tile_x
Type:int in [0, inf], default 0
tile_y
Type:int in [0, inf], default 0
use_highlight_tiles
Type:boolean, default False
update(data=None, depsgraph=None)

Export scene data for render

render(depsgraph)

Render scene into an image

bake(depsgraph, object, pass_type, pass_filter, object_id, pixel_array, num_pixels, depth, result)

Bake passes

Parameters:
  • pass_type (enum in ['COMBINED', 'AO', 'SHADOW', 'NORMAL', 'UV', 'ROUGHNESS', 'EMIT', 'ENVIRONMENT', 'DIFFUSE', 'GLOSSY', 'TRANSMISSION', 'SUBSURFACE']) – Pass, Pass to bake
  • pass_filter (int in [0, inf]) – Pass Filter, Filter to combined, diffuse, glossy, transmission and subsurface passes
  • object_id (int in [0, inf]) – Object Id, Id of the current object being baked in relation to the others
  • num_pixels (int in [0, inf]) – Number of Pixels, Size of the baking batch
  • depth (int in [0, inf]) – Pixels depth, Number of channels
view_update(context, depsgraph)

Update on data changes for viewport render

view_draw(context, depsgraph)

Draw viewport render

update_script_node(node=None)

Compile shader script node

update_render_passes(scene=None, renderlayer=None)

Update the render passes that will be generated

tag_redraw()

Request redraw for viewport rendering

tag_update()

Request update call for viewport rendering

begin_result(x, y, w, h, layer="", view="")

Create render result to write linear floating point render layers and passes

Parameters:
  • x (int in [0, inf]) – X
  • y (int in [0, inf]) – Y
  • w (int in [0, inf]) – Width
  • h (int in [0, inf]) – Height
  • layer (string, (optional, never None)) – Layer, Single layer to get render result for
  • view (string, (optional, never None)) – View, Single view to get render result for
Returns:

Result

Return type:

RenderResult

update_result(result)

Signal that pixels have been updated and can be redrawn in the user interface

Parameters:result (RenderResult) – Result
end_result(result, cancel=False, highlight=False, do_merge_results=False)

All pixels in the render result have been set and are final

Parameters:
  • result (RenderResult) – Result
  • cancel (boolean, (optional)) – Cancel, Don’t mark tile as done, don’t merge results unless forced
  • highlight (boolean, (optional)) – Highlight, Don’t mark tile as done yet
  • do_merge_results (boolean, (optional)) – Merge Results, Merge results even if cancel=true
add_pass(name, channels, chan_id, layer="")

Add a pass to the render layer

Parameters:
  • name (string, (never None)) – Name, Name of the Pass, without view or channel tag
  • channels (int in [0, inf]) – Channels
  • chan_id (string, (never None)) – Channel IDs, Channel names, one character per channel
  • layer (string, (optional, never None)) – Layer, Single layer to add render pass to
get_result()

Get final result for non-pixel operations

Returns:Result
Return type:RenderResult
test_break()

Test if the render operation should been canceled, this is a fast call that should be used regularly for responsiveness

Returns:Break
Return type:boolean
active_view_get()

active_view_get

Returns:View, Single view active
Return type:string, (never None)
active_view_set(view)

active_view_set

Parameters:view (string, (never None)) – View, Single view to set as active
camera_shift_x(camera, use_spherical_stereo=False)

camera_shift_x

Parameters:use_spherical_stereo (boolean, (optional)) – Spherical Stereo
Returns:Shift X
Return type:float in [0, inf]
camera_model_matrix(camera, use_spherical_stereo=False)

camera_model_matrix

Parameters:use_spherical_stereo (boolean, (optional)) – Spherical Stereo
Returns:Model Matrix, Normalized camera model matrix
Return type:float multi-dimensional array of 4 * 4 items in [-inf, inf]
use_spherical_stereo(camera)

use_spherical_stereo

Returns:Spherical Stereo
Return type:boolean
update_stats(stats, info)

Update and signal to redraw render status text

Parameters:
  • stats (string, (never None)) – Stats
  • info (string, (never None)) – Info
frame_set(frame, subframe)

Evaluate scene at a different frame (for motion blur)

Parameters:
  • frame (int in [-inf, inf]) – Frame
  • subframe (float in [0, 1]) – Subframe
update_progress(progress)

Update progress percentage of render

Parameters:progress (float in [0, 1]) – Percentage of render that’s done
update_memory_stats(memory_used=0.0, memory_peak=0.0)

Update memory usage statistics

Parameters:
  • memory_used (float in [0, inf], (optional)) – Current memory usage in megabytes
  • memory_peak (float in [0, inf], (optional)) – Peak memory usage in megabytes
report(type, message)

Report info, warning or error messages

Parameters:
  • type (enum set in {'DEBUG', 'INFO', 'OPERATOR', 'PROPERTY', 'WARNING', 'ERROR', 'ERROR_INVALID_INPUT', 'ERROR_INVALID_CONTEXT', 'ERROR_OUT_OF_MEMORY'}) – Type
  • message (string, (never None)) – Report Message
error_set(message)

Set error message displaying after the render is finished

Parameters:message (string, (never None)) – Report Message
bind_display_space_shader(scene)

Bind GLSL fragment shader that converts linear colors to display space colors using scene color management settings

unbind_display_space_shader()

Unbind GLSL display space shader, must always be called after binding the shader

support_display_space_shader(scene)

Test if GLSL display space shader is supported for the combination of graphics card and scene settings

Returns:Supported
Return type:boolean
get_preview_pixel_size(scene)

Free Blender side memory of render engine

Returns:Pixel Size
Return type:int in [1, 8]
free_blender_memory()

free_blender_memory

register_pass(scene, view_layer, name, channels, chanid, type)

Register a render pass that will be part of the render with the current settings

Parameters:
  • name (string, (never None)) – Name
  • channels (int in [1, 8]) – Channels
  • chanid (string, (never None)) – Channel IDs
  • type (enum in ['VALUE', 'VECTOR', 'COLOR']) – Type
classmethod bl_rna_get_subclass(id, default=None)
Parameters:id (string) – The RNA type identifier.
Returns:The RNA type or default when not found.
Return type:bpy.types.Struct subclass
classmethod bl_rna_get_subclass_py(id, default=None)
Parameters:id (string) – The RNA type identifier.
Returns:The class or default when not found.
Return type:type

Inherited Properties

Inherited Functions