Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
authorBrecht Van Lommel <brechtvanlommel@gmail.com>2019-03-26 21:48:16 +0300
committerBrecht Van Lommel <brechtvanlommel@gmail.com>2019-03-26 21:57:51 +0300
commit337eb8c1de4c57c34520b467d79779153335eecb (patch)
tree671bf57ecf0caa154145216901c4dc95ac949501 /doc
parent85915ae1aad761fc79eccf005e68a2334ad6b81c (diff)
Python API: add more detailed example for RenderEngine.
Diffstat (limited to 'doc')
-rw-r--r--doc/python_api/examples/bpy.types.RenderEngine.py229
1 files changed, 183 insertions, 46 deletions
diff --git a/doc/python_api/examples/bpy.types.RenderEngine.py b/doc/python_api/examples/bpy.types.RenderEngine.py
index f7b2be48bc4..1195204bdeb 100644
--- a/doc/python_api/examples/bpy.types.RenderEngine.py
+++ b/doc/python_api/examples/bpy.types.RenderEngine.py
@@ -4,82 +4,219 @@ 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_renderer"
- bl_label = "Flat Color Renderer"
+ bl_idname = "CUSTOM"
+ bl_label = "Custom"
bl_use_preview = True
- # This is the only method called by blender, in this example
- # we use it to detect preview rendering and call the implementation
- # in another method.
- def render(self, scene):
+ # 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:
- self.render_preview(scene)
+ color = [0.1, 0.2, 0.1, 1.0]
else:
- self.render_scene(scene)
+ color = [0.2, 0.1, 0.1, 1.0]
- # In this example, we fill the preview renders with a flat green color.
- def render_preview(self, scene):
pixel_count = self.size_x * self.size_y
-
- # The framebuffer is defined as a list of pixels, each pixel
- # itself being a list of R,G,B,A values
- green_rect = [[0.0, 1.0, 0.0, 1.0]] * pixel_count
+ 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 = green_rect
- self.end_result(result)
-
- # In this example, we fill the full renders with a flat blue color.
- def render_scene(self, scene):
- pixel_count = self.size_x * self.size_y
-
- # The framebuffer is defined as a list of pixels, each pixel
- # itself being a list of R,G,B,A values
- blue_rect = [[0.0, 0.0, 1.0, 1.0]] * 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 = blue_rect
+ 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):
+ region = context.region
+ view3d = context.space_data
+ depsgraph = context.depsgraph
+ 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_update('MATERIAL'):
+ print("Materials updated")
+
+ # Loop over all object instances in the scene.
+ if first_time or depsgraph.id_type_update('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):
+ region = context.region
+ depsgraph = context.depsgraph
+ 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)
+
+ self.texturecoord_location = bgl.glGetAttribLocation(shader_program[0], "texCoord");
+ self.position_location = bgl.glGetAttribLocation(shader_program[0], "pos");
+
+ # 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.glBindBuffer(bgl.GL_ARRAY_BUFFER, self.vertex_buffer[1])
+ bgl.glBufferData(bgl.GL_ARRAY_BUFFER, 32, texcoord, bgl.GL_STATIC_DRAW)
+ bgl.glBindBuffer(bgl.GL_ARRAY_BUFFER, 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.glEnableVertexAttribArray(self.texturecoord_location);
+ bgl.glEnableVertexAttribArray(self.position_location);
+
+ bgl.glBindBuffer(bgl.GL_ARRAY_BUFFER, self.vertex_buffer[0])
+ bgl.glVertexAttribPointer(self.position_location, 2, bgl.GL_FLOAT, bgl.GL_FALSE, 0, None)
+ bgl.glBindBuffer(bgl.GL_ARRAY_BUFFER, self.vertex_buffer[1])
+ bgl.glVertexAttribPointer(self.texturecoord_location, 2, bgl.GL_FLOAT, bgl.GL_FALSE, 0, None)
+ bgl.glBindBuffer(bgl.GL_ARRAY_BUFFER, 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)
- # RenderEngines also need to tell UI Panels that they are compatible
- # Otherwise most of the UI will be empty when the engine is selected.
- # In this example, we need to see the main render image button and
- # the material preview panel.
- from bl_ui import (
- properties_render,
- properties_material,
- )
- properties_render.RENDER_PT_render.COMPAT_ENGINES.add(CustomRenderEngine.bl_idname)
- properties_material.MATERIAL_PT_preview.COMPAT_ENGINES.add(CustomRenderEngine.bl_idname)
-
+ for panel in get_panels():
+ panel.COMPAT_ENGINES.add('CUSTOM')
def unregister():
bpy.utils.unregister_class(CustomRenderEngine)
- from bl_ui import (
- properties_render,
- properties_material,
- )
- properties_render.RENDER_PT_render.COMPAT_ENGINES.remove(CustomRenderEngine.bl_idname)
- properties_material.MATERIAL_PT_preview.COMPAT_ENGINES.remove(CustomRenderEngine.bl_idname)
+ for panel in get_panels():
+ if 'CUSTOM' in panel.COMPAT_ENGINES:
+ panel.COMPAT_ENGINES.remove('CUSTOM')
if __name__ == "__main__":