I need to code my own Render Engine to do specific rendering passes. I don't want to build my own Blender app by coding in c/c++, so i try to make it work in Python.
But i need OpenGL functions.
Inside the render function, I call bgl functions to use OpenGL. This allows me to compute the render of the scene in a fast way and get the result from OpenGL to display it on the Blender editor.
CustomRenderEngine.py :
import bpy
import math
from mathutils import *
from bgl import *
import time
class CustomRenderEngine(bpy.types.RenderEngine):
bl_idname = "custom_renderer"
bl_label = "Custom Renderer"
use_preview = True
def render(self, scene):
scale = scene.render.resolution_percentage / 100.0
width = int(scene.render.resolution_x * scale)
height = int(scene.render.resolution_y * scale)
# Get mesh objects and cameras
camera_objects = []
mesh_objects = []
for obj in scene.objects:
print("\tName:%s \tType:%s"%(obj.name,obj.type))
if obj.type == 'MESH':
mesh_objects.append(obj)
elif obj.type == 'CAMERA':
camera_objects.append(obj)
if len(camera_objects) == 0:
print("No camera found.")
return
# Ideally, we could render for each camera in the scene
camera = camera_objects[0]
z_near = camera.data.clip_start
z_far = camera.data.clip_end
lens = camera.data.lens
factor = lens / 32.0
pr = float(width) / float(height)
fovx = math.atan(.5/factor)
fovy = math.atan(.5/pr/factor)
fov = fovy * 360 /math.pi
modelview_matrix = camera.matrix_world.inverted()
# OpenGL init
glClearColor( 1.0,1.0,1.0,1.0)
glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
glEnable(GL_DEPTH_TEST)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glViewport(0,0,width,height)
gluPerspective(fov, pr, z_near, z_far)
glMatrixMode( GL_MODELVIEW )
glLoadIdentity()
glShadeModel( GL_SMOOTH)
for obj in mesh_objects:
print("Handle Object : %s"%obj.name)
mesh = obj.data
diffuse_color = mesh.materials[0].diffuse_color
print("Diffuse color: %s"%diffuse_color)
for polygon in mesh.polygons:
glBegin(GL_POLYGON)
for vertex_id in polygon.vertices:
# This is quite simple for now, only diffuse color and geometry
vertex = mesh.vertices[vertex_id]
v = modelview_matrix * obj.matrix_local * vertex.co
glColor3f(diffuse_color[0],diffuse_color[1],diffuse_color[2])
glVertex3f(v[0],v[1],v[2])
glEnd()
# Get the result from Open GL
colBuff = Buffer(GL_FLOAT, (height,width,3))
glReadPixels(0, 0, width, height, GL_RGB, GL_FLOAT,colBuff )
# Write the result to Blender preview
output_pixels = []
for y in range (0,height):
for x in range(0,width):
col = colBuff[y][x]
output_pixels.append([col[0],col[1],col[2],1.0])
result = self.begin_result(0, 0, width, height)
layer = result.layers[0].passes["Combined"]
layer.rect = output_pixels
self.end_result(result)
def register() :
bpy.utils.register_class(CustomRenderEngine)
from bl_ui import (properties_render)
properties_render.RENDER_PT_render.COMPAT_ENGINES.add(CustomRenderEngine.bl_idname)
def unregister() :
bpy.utils.unregister_class(CustomRenderEngine)
from bl_ui import (properties_render)
properties_render.RENDER_PT_render.COMPAT_ENGINES.remove(CustomRenderEngine.bl_idname)
__ init __.py
bl_info = {
'name': 'CustomEngineTest',
'category': 'SVG Render',
'version': (0, 0, 1),
'blender': (2, 78, 0)
}
modulesNames = ['CustomRenderEngine']
import sys
import importlib
modulesFullNames = {}
for currentModuleName in modulesNames:
if 'DEBUG_MODE' in sys.argv:
modulesFullNames[currentModuleName] = ('{}'.format(currentModuleName))
else:
modulesFullNames[currentModuleName] = ('{}.{}'.format(__name__, currentModuleName))
for currentModuleFullName in modulesFullNames.values():
if currentModuleFullName in sys.modules:
importlib.reload(sys.modules[currentModuleFullName])
else:
globals()[currentModuleFullName] = importlib.import_module(currentModuleFullName)
setattr(globals()[currentModuleFullName], 'modulesNames', modulesFullNames)
def register():
for currentModuleName in modulesFullNames.values():
if currentModuleName in sys.modules:
if hasattr(sys.modules[currentModuleName], 'register'):
sys.modules[currentModuleName].register()
def unregister():
for currentModuleName in modulesFullNames.values():
if currentModuleName in sys.modules:
if hasattr(sys.modules[currentModuleName], 'unregister'):
sys.modules[currentModuleName].unregister()
if __name__ == "__main__":
register()
When I started Blender from command line and call render with a script (start_addon.py), bgl function calls work as expected.
For example :
start_addon.py
import os
import sys
import bpy
from bgl import *
filesDir = os.getcwd()
initFile = "__init__.py"
if filesDir not in sys.path:
sys.path.append(filesDir)
file = os.path.join(filesDir, initFile)
if 'DEBUG_MODE' not in sys.argv:
sys.argv.append('DEBUG_MODE')
exec(compile(open(file).read(), initFile, 'exec'))
if 'DEBUG_MODE' in sys.argv:
sys.argv.remove('DEBUG_MODE')
bpy.context.scene.render.engine = "custom_renderer"
bpy.ops.render.render()
But when I manually set the render engine inside Blender UI and press "Render" Button, i got a segmentation fault with this backtrace :
# Blender 2.79 (sub 0), Commit date: 2017-09-11 10:43, Hash 5bd8ac9
# backtrace
0 blender
0x0000000100c32b1a BLI_system_backtrace + 58
1 blender 0x000000010013ee1a sig_handle_crash + 362
2 libsystem_platform.dylib 0x00007fffc571fb3a _sigtramp + 26
3 blender 0x0000000102293ea6 PyObject_CallMethodObjArgs + 406
4 blender 0x000000010059861c Method_ClearColor + 76
5 blender 0x00000001022d93f8 PyCFunction_Call + 280
6 blender 0x00000001023540f2 PyEval_EvalFrameEx + 26210
7 blender 0x000000010235853f fast_function + 223
8 blender 0x0000000102353bbb PyEval_EvalFrameEx + 24875
9 blender 0x0000000102357cc5 _PyEval_EvalCodeWithName + 2421
10 blender 0x000000010234da6e PyEval_EvalCodeEx + 78
11 blender 0x00000001022bb7ad function_call + 381
12 blender 0x00000001022935c0 PyObject_Call + 96
13 blender 0x000000010057650d bpy_class_call + 1069
14 blender 0x0000000100b3e851 engine_render + 113
15 blender 0x00000001004f982b RE_engine_render + 971
16 blender 0x000000010050f190 do_render_3d + 48
17 blender 0x000000010050d8a1 do_render_fields_blur_3d + 289
18 blender 0x000000010050c984 do_render_all_options + 388
19 blender 0x000000010050c42e RE_BlenderFrame + 206
20 blender 0x000000010044786b render_startjob + 139
21 blender 0x0000000100150c2f do_job_thread + 31
22 libsystem_pthread.dylib 0x00007fffc572993b _pthread_body + 180
23 libsystem_pthread.dylib 0x00007fffc5729887 _pthread_body + 0
24 libsystem_pthread.dylib 0x00007fffc572908d thread_start + 13
It crashes on macOS high Sierra and also Sierra. Any ideas ?
Edit : Weirdest thing, if I tape in Python console bpy.ops.render.render() it works. But the Render button, which should call bpy.ops.render.render() finishes with the seg fault.
Thx in advance,


bl_idnameis lower case "customRender", and how have you definedmesh_objects. Suggest putting in theimport bpy(and bgl) and register methods for class too. Makes it easier for those interested to test, and hence answer. (even though it breaks question rules somewhat) – batFINGER Oct 10 '17 at 10:38