# Rendering through python code

import bpy
def makeMaterial(name, diffuse, specular, alpha):
mat=bpy.data.materials.new(name)
mat.diffuse_color = diffuse
mat.diffuse_intensity = 1.0
mat.specular_color = specular
mat.specular_intensity = 0.5
mat.alpha = alpha
mat.ambient = 1
return mat

def setMaterial(ob, mat):
me = ob.data
me.materials.append(mat)

def run(origin):
red = makeMaterial('Red', (1,0,0), (1,1,1), 1)
blue = makeMaterial( 'Blue', (0,0,1), (0.5,0.5,0), 0.5)
setMaterial(bpy.context.object,red)
bpy.ops.transform.translate(value = (1,0,0))
setMaterial(bpy.context.object,blue);
****bpy.ops.render.render()**// This code doesn't seem to execute**

if __name__=="__main__":
run((0,0,0))


The above code when executed doesn't give me the render output. I have no idea why. I'm running the latest blender version. Any help would be welcome.

• Try getting rid of the semicolon at the end of the setMaterial line. Looks like you've been coding too much c++ :) Make sure you get rid of the asterisks also. – TARDIS Maker Oct 10 '15 at 5:01
• do you mean it does render but doesn't change one of the views to show the result ? – zeffii Oct 10 '15 at 5:34

The makeMaterial function's return statement isn't indented correctly. The semicolon is syntactically allowed, but it's used to place multiple statements on a single line. 2 space indentation makes it less obvious where your indentation is incorrect, standard Python practice is 4 spaces.

This works:

import bpy
def makeMaterial(name, diffuse, specular, alpha):
mat=bpy.data.materials.new(name)
mat.diffuse_color = diffuse
mat.diffuse_intensity = 1.0
mat.specular_color = specular
mat.specular_intensity = 0.5
mat.alpha = alpha
mat.ambient = 1
return mat

def setMaterial(ob, mat):
me = ob.data
me.materials.append(mat)

def run(origin):
red = makeMaterial('Red', (1,0,0), (1,1,1), 1)
blue = makeMaterial( 'Blue', (0,0,1), (0.5,0.5,0), 0.5)
setMaterial(bpy.context.object, red)
bpy.ops.transform.translate(value = (1,0,0))
setMaterial(bpy.context.object, blue);
bpy.ops.render.render()

if __name__=="__main__":
run((0,0,0))


Setting a material is a little bit easier too:

obj.active_material = bpy.data.materials['Blue']


this also works, reusing the makeMaterial function:

def run(origin):
red = makeMaterial('Red', (1,0,0), (1,1,1), 1)
blue = makeMaterial( 'Blue', (0,0,1), (0.5,0.5,0), 0.5)
bpy.context.object.active_material = red
bpy.ops.transform.translate(value = (1,0,0))
bpy.context.object.active_material = blue
bpy.ops.render.render()

if __name__=="__main__":
run((0,0,0))


You won't see the objects or material changes until the render has completed.

Changing the render call to bpy.ops.render.render('INVOKE_DEFAULT'), will switch the current TextEditor window to a UV editor, and show the render progress. When we press the UI button for render.render() it does a few more things behind the scene, like pick where to display the render based on the setting in render.display_mode.

Which amounts to something like this:

def find_largest_3dview_and_switch():
collected_areas = []
for window in bpy.context.window_manager.windows:
for area in window.screen.areas:
if area.type == 'VIEW_3D':
size = area.height * area.width
collected_areas.append([size, area])

# no 3dview found? use texeditor.
if len(collected_areas) == 0:
bpy.ops.render.render('INVOKE_DEFAULT')
return

# else use largest 3dview.
for area in sorted(collected_areas, reverse=True):
area[1].type = 'IMAGE_EDITOR'
bpy.ops.render.render('INVOKE_AREA')
return


Instead of calling the naked bpy.ops.render.render() you could call something like find_largest_3dview_and_switch() and let that decide how to call the render function. It would switch any available 3dview (or largest) to an 'IMAGE_EDITOR' and show the render progress.

• well i did use 4 indent spaces. Its just that i pasted them here that way. Either way that isn't the problem. The problem is why it doesn't show the render output. – Gabriel Oct 10 '15 at 5:29