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:
![enter image description here](https://i.sstatic.net/OC9n8.png)
import bpy
def makeMaterial(name, diffuse, specular, alpha):
mat=bpy.data.materials.new(name)
mat.diffuse_color = diffuse
mat.diffuse_shader = 'LAMBERT'
mat.diffuse_intensity = 1.0
mat.specular_color = specular
mat.specular_shader = 'COOKTORR'
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)
bpy.ops.mesh.primitive_plane_add(location = origin)
setMaterial(bpy.context.object, red)
bpy.ops.mesh.primitive_uv_sphere_add(location = origin)
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.ops.mesh.primitive_plane_add(location = origin)
bpy.context.object.active_material = red
bpy.ops.mesh.primitive_uv_sphere_add(location = origin)
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.