These last 2 days have been all about getting my scene set up in Blender 3D. And guess what… it’s been a challenge. Here’s why: I have 8660 objects, which make up 720 characters. Each character has 2 rigs, and at least 8 constraints, plus two sets of animation data. Oh, and I’m working on a laptop, which means, the computer basicly can’t handle it, becomes uncooperative, and everything takes for ever. Here’s me at my geekiest…
Solution
Thus, the only way to nicely edit things in my scene is to do everything by python script. Luckily Campbell Barton has done an amazing job with the Python API for the new Blender version (2.54). It is just magic. So I thought I’d share the little scripts I’ve made to mess around. I’ll try to comment them, but they’re not real “released” scripts, just stuff I’ve hacked together, but they might be of use to you.
Setting subdivision levels, and removing subsurf modifiers
import bpy
for ob in bpy.data.objects:
try:
# Set the subdivision level for all objects with a mesh named 'iris'
if ob.data.name == 'iris':
ob.data = bpy.data.meshes['simpleiris']
print('set data for',ob.name)
#for m in ob.modifiers:
if m.type == 'SUBSURF':
m.levels = 1
m.render_levels = 1
# Remove all subsurf modifiers from objects with a mesh named 'simpleiris'
if ob.data.name == 'simpleiris':
ob.name = 'iris'
d = 'x'
for i, m in enumerate(ob.modifiers):
if m.type == 'SUBSURF':
d = i
if not d == 'x':
ob.modifiers.remove(ob.modifiers[d])
print('removing from',ob.name)
except:
print('no data or error')
print(' -- finished --')
Display clean python code for copying
import bpy
for ob in bpy.data.objects:
try:
# Set the subdivision level for all objects with a mesh named 'iris'
if ob.data.name == 'iris':
ob.data = bpy.data.meshes['simpleiris']
print('set data for',ob.name)
#for m in ob.modifiers:
if m.type == 'SUBSURF':
m.levels = 1
m.render_levels = 1
# Remove all subsurf modifiers from objects with a mesh named 'simpleiris'
if ob.data.name == 'simpleiris':
ob.name = 'iris'
d = 'x'
for i, m in enumerate(ob.modifiers):
if m.type == 'SUBSURF':
d = i
if not d == 'x':
ob.modifiers.remove(ob.modifiers[d])
print('removing from',ob.name)
except:
print('no data or error')
print(' -- finished --')
Enable disable layers on specific objects
import bpy
lTargets = [ob for ob in bpy.data.groups['localtargets'].objects]
print(len(lTargets),'to do')
#lTargets = [ob for ob in bpy.context.selected_objects]
#Loop through the target objects and enable/disable specific layers
for c, ob in enumerate(lTargets):
tLayers = []
for i, l in enumerate(ob.layers):
if i == 5:
tLayers.append(True)
elif i == 15:
tLayers.append(False)
elif i < 20:
tLayers.append(l)
print(i,l)
print(len(tLayers))
ob.layers = tLayers
print(c, ob.name)
print('--finished--')
Display clean python code for copying
import bpy
lTargets = [ob for ob in bpy.data.groups['localtargets'].objects]
print(len(lTargets),'to do')
#lTargets = [ob for ob in bpy.context.selected_objects]
#Loop through the target objects and enable/disable specific layers
for c, ob in enumerate(lTargets):
tLayers = []
for i, l in enumerate(ob.layers):
if i == 5:
tLayers.append(True)
elif i == 15:
tLayers.append(False)
elif i < 20:
tLayers.append(l)
print(i,l)
print(len(tLayers))
ob.layers = tLayers
print(c, ob.name)
print('--finished--')
Set the subdivision level on objects lower the further they are from the camera
import bpy
camLoc = bpy.data.objects['Camera'].matrix_world.translation_part()
for ob in bpy.data.objects:
try:
n = ob.data.name
# Only work on objects with a specific mesh linked in
if n == 'neck' or n == 'eyeball' or n == 'pupil' or n == 'foot':
gLoc = ob.matrix_world.translation_part()
# Get the vector from the camera to the object so we know how far away it is
relLoc = gLoc - camLoc
if relLoc.length > 40:
nLevel = 0
elif relLoc.length < 20 and not (n == 'pupil' or n == 'foot'):
nLevel = 2
else:
nLevel = 1
# Set the subdivision level
for m in ob.modifiers:
if m.type == 'SUBSURF':
m.render_levels = nLevel
m.levels = nLevel
print('set level',nLevel,'for',ob.name)
except:
print('no data or error')
print('--finished--')
Display clean python code for copying
import bpy
camLoc = bpy.data.objects['Camera'].matrix_world.translation_part()
for ob in bpy.data.objects:
try:
n = ob.data.name
# Only work on objects with a specific mesh linked in
if n == 'neck' or n == 'eyeball' or n == 'pupil' or n == 'foot':
gLoc = ob.matrix_world.translation_part()
# Get the vector from the camera to the object so we know how far away it is
relLoc = gLoc - camLoc
if relLoc.length > 40:
nLevel = 0
elif relLoc.length < 20 and not (n == 'pupil' or n == 'foot'):
nLevel = 2
else:
nLevel = 1
# Set the subdivision level
for m in ob.modifiers:
if m.type == 'SUBSURF':
m.render_levels = nLevel
m.levels = nLevel
print('set level',nLevel,'for',ob.name)
except:
print('no data or error')
print('--finished--')
Set a whole bunch of objects to a specific “local” location
import bpy, mathutils
newLoc = mathutils.Vector([0.0, -5.0, 10.0])
scene = bpy.data.scenes[0]
for ob in bpy.data.groups['localtargets'].objects:
ob.location = newLoc
ob.update(scene)
print('reset',ob.name)
print('-- finished --')
Display clean python code for copying
import bpy, mathutils
newLoc = mathutils.Vector([0.0, -5.0, 10.0])
scene = bpy.data.scenes[0]
for ob in bpy.data.groups['localtargets'].objects:
ob.location = newLoc
ob.update(scene)
print('reset',ob.name)
print('-- finished --')
Assign a specific action to a list of objects
import bpy
oList = [ob for ob in bpy.data.groups['localtargets'].objects]
ac = bpy.data.actions['LocalTargetAction']
for ob in oList:
try:
ob.animation_data.action = ac
except:
ob.animation_data_create()
ob.animation_data.action = ac
print('set',ob.name)
print('-- finished --')
Display clean python code for copying
import bpy
oList = [ob for ob in bpy.data.groups['localtargets'].objects]
ac = bpy.data.actions['LocalTargetAction']
for ob in oList:
try:
ob.animation_data.action = ac
except:
ob.animation_data_create()
ob.animation_data.action = ac
print('set',ob.name)
print('-- finished --')
Setting a whole heap of bone rotations and keyframes for them at specific frames
import bpy, math, random
scene = bpy.data.scenes[0]
boneList = [[ob.pose.bones['iriscontrol'],0] for ob in bpy.data.objects if 'iriscontrol' in ob.name]
startList = []
blinkList = []
endList = []
cnt = 0
# Set a random frame for a blink
for b in boneList:
r = 15.0
while r > 13 and r < 17:
r = int(300.0 * random.random())
startList.append(r)
blinkList.append(r+1)
endList.append(r+2)
if r < 30:
cnt += 1
print('cnt',cnt)
#print(boneList)
# Loop through all the frames
for f in range(31):
fr = f+1
scene.frame_set(fr)
for i, b in enumerate(boneList):
if startList[i] == fr:
b[0].rotation_euler = [math.radians(-15.0), 0.0, 0.0]
b[0].keyframe_insert('rotation_euler')
print('start blink',i)
elif blinkList[i] == fr:
b[0].rotation_euler = [math.radians(-0.0), 0.0, 0.0]
b[0].keyframe_insert('rotation_euler')
b[1] = 3
boneList[i][1] = 3
print('blink',i)
if endList[i] == fr:
b[0].rotation_euler = [math.radians(-15.0), 0.0, 0.0]
b[0].keyframe_insert('rotation_euler')
b[1] = 0
boneList[i][1] = 0
print('end blink', i)
print('-- set',f)
print('-- finished --')
Display clean python code for copying
import bpy, math, random
scene = bpy.data.scenes[0]
boneList = [[ob.pose.bones['iriscontrol'],0] for ob in bpy.data.objects if 'iriscontrol' in ob.name]
startList = []
blinkList = []
endList = []
cnt = 0
# Set a random frame for a blink
for b in boneList:
r = 15.0
while r > 13 and r < 17:
r = int(300.0 * random.random())
startList.append(r)
blinkList.append(r+1)
endList.append(r+2)
if r < 30:
cnt += 1
print('cnt',cnt)
#print(boneList)
# Loop through all the frames
for f in range(31):
fr = f+1
scene.frame_set(fr)
for i, b in enumerate(boneList):
if startList[i] == fr:
b[0].rotation_euler = [math.radians(-15.0), 0.0, 0.0]
b[0].keyframe_insert('rotation_euler')
print('start blink',i)
elif blinkList[i] == fr:
b[0].rotation_euler = [math.radians(-0.0), 0.0, 0.0]
b[0].keyframe_insert('rotation_euler')
b[1] = 3
boneList[i][1] = 3
print('blink',i)
if endList[i] == fr:
b[0].rotation_euler = [math.radians(-15.0), 0.0, 0.0]
b[0].keyframe_insert('rotation_euler')
b[1] = 0
boneList[i][1] = 0
print('end blink', i)
print('-- set',f)
print('-- finished --')
Offset NLA strips relative to lots of position calculations
import bpy
offs = [ob.matrix_world.translation_part() for ob in bpy.data.groups['offsets'].objects]
ofDist = 10
cLoc = bpy.data.objects['Camera'].matrix_world.translation_part()
minDist = 'x'
maxDist = 'x'
start = 11
end = 511
for ob in bpy.data.groups['localtargets'].objects:
t = ob.animation_data.nla_tracks['NlaTrack']
s = t.strips[0]
offset = 0
obLoc = ob.matrix_world.translation_part()
cDist = obLoc - cLoc
cDist = cDist.length
offset -= (cDist * 0.4)
if minDist == 'x' or cDist < minDist: minDist = cDist if maxDist == 'x' or cDist > maxDist:
maxDist = cDist
for i, of in enumerate(offs):
cDist = obLoc - of
cDist = cDist.length
if cDist < ofDist:
# Use modulo to set a nice maximum deviation
if (i%2) == 1:
if (i%3) == 1:
max = -5
else:
max = -10
else:
if(i%3) == 1:
max = -15
else:
max = - 20
cFact = (1.0/ofDist) * (ofDist - cDist)
offset = offset + (max * cFact)
s.action_frame_start = start + offset
s.action_frame_end = end + offset
print('set', ob.name)
print('minDist',minDist)
print('maxDist',maxDist)
print('-- finished --')
Display clean python code for copying
import bpy
offs = [ob.matrix_world.translation_part() for ob in bpy.data.groups['offsets'].objects]
ofDist = 10
cLoc = bpy.data.objects['Camera'].matrix_world.translation_part()
minDist = 'x'
maxDist = 'x'
start = 11
end = 511
for ob in bpy.data.groups['localtargets'].objects:
t = ob.animation_data.nla_tracks['NlaTrack']
s = t.strips[0]
offset = 0
obLoc = ob.matrix_world.translation_part()
cDist = obLoc - cLoc
cDist = cDist.length
offset -= (cDist * 0.4)
if minDist == 'x' or cDist < minDist: minDist = cDist if maxDist == 'x' or cDist > maxDist:
maxDist = cDist
for i, of in enumerate(offs):
cDist = obLoc - of
cDist = cDist.length
if cDist < ofDist:
# Use modulo to set a nice maximum deviation
if (i%2) == 1:
if (i%3) == 1:
max = -5
else:
max = -10
else:
if(i%3) == 1:
max = -15
else:
max = - 20
cFact = (1.0/ofDist) * (ofDist - cDist)
offset = offset + (max * cFact)
s.action_frame_start = start + offset
s.action_frame_end = end + offset
print('set', ob.name)
print('minDist',minDist)
print('maxDist',maxDist)
print('-- finished --')
Messing with Constraints
import bpy, math
grp = bpy.data.groups['controllers']
ctrl = [ob for ob in grp.objects]
cam = bpy.data.objects['Camera']
camLoc = cam.matrix_world.translation_part()
minDist = 'x'
maxDist = 'x'
minF = 10
print(len(ctrl))
for ob in ctrl:
# Get locations and rotations to use
obLoc = ob.matrix_world.translation_part()
pRot = math.degrees(ob.parent.rotation_euler[1])
# Calculate the distance to the camera
obDist = obLoc - camLoc
obDist = obDist.length
# Set the minimum and maximum distance from the camera
if minDist == 'x' or obDist < minDist: minDist = obDist if maxDist == 'x' or obDist > maxDist:
maxDist = obDist
print('setting',ob.name)
# Add new constraints
ob.constraints.new('TRACK_TO')
ob.constraints.new('TRANSFORM')
ob.constraints.new('LOCKED_TRACK')
ob.constraints.new('LOCKED_TRACK')
# Retrieve the constraints
tr = ob.constraints[2] # track to
tf = ob.constraints[3] # transform
tr2 = ob.constraints[4] # track to
tr3 = ob.constraints[5] # locked track x
tr4 = ob.constraints[6] # locked track z
ob.constraints.remove(tr2)
# Use the rotation of the parent to set the influence of the camera position to world or local
if pRot > 360:
pRot = pRot - 360
if pRot > 270:
inf = (1.0/90.0) * (90 - (360 - pRot))
elif pRot < 90:
inf = (1.0/90.0) * (90 - pRot)
else:
inf = 0.0
# Set the influence of the constraints
tr.influence = 1.0
tf.influence = 1.0
tr2.influence = inf
tr3.influence = 0.0
tr4.influence = 0.0
# Insert a keyframe
tr.keyframe_insert('influence')
tf.keyframe_insert('influence')
tr2.keyframe_insert('influence')
tr3.keyframe_insert('influence')
tr4.keyframe_insert('influence')
# Set the track axis
tr.track_axis = 'TRACK_NEGATIVE_Y'
tr2.track_axis = 'TRACK_NEGATIVE_Y'
tr3.track_axis = 'TRACK_NEGATIVE_Y'
tr3.lock_axis = 'LOCK_X'
tr4.track_axis = 'TRACK_NEGATIVE_Y'
tr4.lock_axis = 'LOCK_Z'
# Set the target for the constraint
tr.target = cam
tf.target = cam
tr2.target = cam
tr3.target = cam
tr4.target = cam
# Set values for the transform constraint
tf.from_min_x = -50.0
tf.from_min_y = -50.0
tf.from_min_z = -50.0
tf.from_max_x = 50.0
tf.from_max_y = 50.0
tf.from_max_z = 50.0
tf.to_min_y = -0.5
tf.to_max_y = -0.5
if obDist < 11.0:
obDist = obDist - 6
n = obDist * 0.20
n = -n
if n < -1.0: n = -1.0 elif n > 0.0:
n = 0.0
else:
n = -1.0
tf.to_min_z = n
tf.to_max_z = n
tr.owner_space = 'LOCAL'
tf.owner_space = 'LOCAL'
print('minDist',minDist)
print('maxDist',maxDist)
print('--finished--')
Display clean python code for copying
import bpy, math
grp = bpy.data.groups['controllers']
ctrl = [ob for ob in grp.objects]
cam = bpy.data.objects['Camera']
camLoc = cam.matrix_world.translation_part()
minDist = 'x'
maxDist = 'x'
minF = 10
print(len(ctrl))
for ob in ctrl:
# Get locations and rotations to use
obLoc = ob.matrix_world.translation_part()
pRot = math.degrees(ob.parent.rotation_euler[1])
# Calculate the distance to the camera
obDist = obLoc - camLoc
obDist = obDist.length
# Set the minimum and maximum distance from the camera
if minDist == 'x' or obDist < minDist: minDist = obDist if maxDist == 'x' or obDist > maxDist:
maxDist = obDist
print('setting',ob.name)
# Add new constraints
ob.constraints.new('TRACK_TO')
ob.constraints.new('TRANSFORM')
ob.constraints.new('LOCKED_TRACK')
ob.constraints.new('LOCKED_TRACK')
# Retrieve the constraints
tr = ob.constraints[2] # track to
tf = ob.constraints[3] # transform
tr2 = ob.constraints[4] # track to
tr3 = ob.constraints[5] # locked track x
tr4 = ob.constraints[6] # locked track z
ob.constraints.remove(tr2)
# Use the rotation of the parent to set the influence of the camera position to world or local
if pRot > 360:
pRot = pRot - 360
if pRot > 270:
inf = (1.0/90.0) * (90 - (360 - pRot))
elif pRot < 90:
inf = (1.0/90.0) * (90 - pRot)
else:
inf = 0.0
# Set the influence of the constraints
tr.influence = 1.0
tf.influence = 1.0
tr2.influence = inf
tr3.influence = 0.0
tr4.influence = 0.0
# Insert a keyframe
tr.keyframe_insert('influence')
tf.keyframe_insert('influence')
tr2.keyframe_insert('influence')
tr3.keyframe_insert('influence')
tr4.keyframe_insert('influence')
# Set the track axis
tr.track_axis = 'TRACK_NEGATIVE_Y'
tr2.track_axis = 'TRACK_NEGATIVE_Y'
tr3.track_axis = 'TRACK_NEGATIVE_Y'
tr3.lock_axis = 'LOCK_X'
tr4.track_axis = 'TRACK_NEGATIVE_Y'
tr4.lock_axis = 'LOCK_Z'
# Set the target for the constraint
tr.target = cam
tf.target = cam
tr2.target = cam
tr3.target = cam
tr4.target = cam
# Set values for the transform constraint
tf.from_min_x = -50.0
tf.from_min_y = -50.0
tf.from_min_z = -50.0
tf.from_max_x = 50.0
tf.from_max_y = 50.0
tf.from_max_z = 50.0
tf.to_min_y = -0.5
tf.to_max_y = -0.5
if obDist < 11.0:
obDist = obDist - 6
n = obDist * 0.20
n = -n
if n < -1.0: n = -1.0 elif n > 0.0:
n = 0.0
else:
n = -1.0
tf.to_min_z = n
tf.to_max_z = n
tr.owner_space = 'LOCAL'
tf.owner_space = 'LOCAL'
print('minDist',minDist)
print('maxDist',maxDist)
print('--finished--')