tobbew
(tobbew)
July 13, 2013, 7:43am
1
Hi!
Working on a scifi live action movie (lots of greenscreen footage), so I’ve created some scripts for things we are doing frequently. We are using ae cs 6 for parts of the camera tracking and since I’ve only found an ae script to export to maya/3dsmax or lightwave I created a script which takes the exported .ma (maya) file and creates the transforms and cameras from it. I have no intention to develop this script past the current state where it works (it only supports cameras, and not target cameras, but the exporter does not use that so for my purpose it’s not needed). I might in the future modify the AE script to create a python script for blender directly instead.
The code is quite ugly, and does not make a lot of error testing - it’s expecting a valid file (as the exporter creates them valid it should not be a problem). Usage: I tend to append the script to the file, remove the # from the beginning of the last line (the loadfile line), and change the path to the file I want loaded.
Please let me know if you find it useful! Or find bugs that are not part of the limitations.
Best wishes and happy blending!
/Torbjörn
PS I could not remember the password for the server I usually use, so for the moment I’ll post the script split into several posts here (as it was too long)
# NOTES:
# only supports cameras. Expects animation curves to be named in the pattern objectname_variable (the exporter
# follows that pattern, so it should not be a problem)
# UNSUPPORTED:
# does not check if created objects get the expected names. One could argue for using a dictionary
# to be sure to use the final name, but this has been omitted due to the fact that I don't personally need this.
# Maya files support the same names existing under different paths (ie in different groups). Blender probably does not.
# target cameras are not supported (but are not used by the exporter, so it does not matter)
# I have not tried if it's working to have several nested transforms before the camera, but can't see that the exporter will
# and it's not part of our workflow anyway.
#
# Limitations:
# really expects a correct file, very little error detection is created.
import bpy
import re
from mathutils import Vector, Euler
# to do if you want it to be good : add a lookup table for intended names and final names.
tw_main_node="tw_main_node"
def splitArguments(line):
argumentssplit = str.split(line,"-")
arguments = {}
for a in argumentssplit:
# print (a)
tmp = a.partition(' ')
# print (tmp)
arguments[ tmp[0] ] = tmp[2]
# print(arguments)
return arguments
def stripCitation(line):
tmp = line.strip()
if not tmp.startswith('\"'):
raise ValueError("Stripping citations, but not a citation")
return tmp[1:].partition('\"')[0]
def splitXYZ(line):
x, y, z = line.strip().split() # note very weird! even splits = line.strip().split() changes the order
return [float(x),-float(z),float(y)]
#createNode animCurveTL -n "L3DTrackerCameCC1_TranslateY";
# setAttr ".tan" 9;
# setAttr ".wgt" no;
# setAttr -s 424 ".ktv[1:424]" 1 3.2121153944043 2 3.20538667823737 3 3.1916467368099 4 3.17486470189342 5 3.16492863722789 6 3.15168543781801 7 3.14271647613811 8 3.13756700958293 9 3.
currentAnimCurveObject =0
currentAnimCurveParameter = ""
tobbew
(tobbew)
July 13, 2013, 7:44am
2
def processKeyframes(line):
global currentAnimCurveObject
global currentAnimCurveParameter
arguments = splitArguments(line)
name = stripCitation( arguments['n'] )
#print(name)
splits = name.rpartition('_')
#print(splits)
try:
currentAnimCurveObject = bpy.data.objects[splits[0]]
if(currentAnimCurveObject is None):
ValueError("Object for animationcurve not found")
currentAnimCurveParameter = splits[2]
except:
print("Object for animationcurve not found.")
print (name)
currentAnimCurveObject = 0;
currentAnimCurveParameter = "Not found"
return
def processSetAttrLine(line):
# global currentAnimCurveObject
# global currentAnimCurveParameter
TRANSLATION_STRING_CONST = '\".t\" -type \"double3\" '
ROTATION_STRING_CONST = '\".r\" -type \"double3\" '
SCALE_STRING_CONST = '\".s\" -type \"double3\" '
CAMERA_APPERTURE_STRING_CONST = '\".cap\" -type \"double2\" '
CAMERA_FAR_CLIP_PLANE = '\".fcp\" '
CAMERA_FOCAL_LENGTH = '\".fl\" '
#CAMERA_
parts = line.strip().partition(' ')
#print(parts[2][0:30])
to_process = None
if parts[2].startswith(TRANSLATION_STRING_CONST):
#print("TRANSLATION")
location = parts[2][len(TRANSLATION_STRING_CONST): ]
#print (location)
#if location :
location = splitXYZ( location )
#print("Translating to: "+location)
#bpy.context.active_object.location.x = location[0]
#bpy.context.active_object.location.y = location[1]
#bpy.context.active_object.location.z = location[2]
bpy.ops.transform.translate(value=(location[0], location[1], location[2]))
#else :
# raise ValueError("Missing location for translation!")
elif parts[2].startswith(SCALE_STRING_CONST):
#print("SCALE")
location = parts[2][len(SCALE_STRING_CONST): ]
#print (location)
location = splitXYZ( location )
bpy.ops.transform.resize(value=(location[0], location[1], location[2]))
elif parts[2].startswith(ROTATION_STRING_CONST):
#print("ROTATION")
rotation = parts[2][len(ROTATION_STRING_CONST): ]
#print (rotation)
if rotation :
rotation = splitXYZ( rotation )
#print(rotation)
bpy.ops.transform.rotate(value= rotation[0]* 0.017453292523928, axis=(1,0,0) );
bpy.ops.transform.rotate(value= rotation[1]* 0.017453292523928, axis=(0,1,0) );
bpy.ops.transform.rotate(value= rotation[2]* 0.017453292523928, axis=(0,0,1) );
else :
raise ValueError("Missing location for rotation!")
elif parts[2].startswith(CAMERA_APPERTURE_STRING_CONST):
to_process = parts[2][len(CAMERA_APPERTURE_STRING_CONST): ]
width, junk, height = to_process.partition(' ')
#bpy.context.object.data.sensor_fit = 'HORIZONTAL' # let it stay at auto
bpy.context.object.data.sensor_width = float(width) * 25.4
bpy.context.object.data.sensor_height = float(height)*25.4
elif parts[2].startswith(CAMERA_FAR_CLIP_PLANE):
to_process = parts[2][len(CAMERA_FAR_CLIP_PLANE): ]
bpy.context.object.data.clip_end = float(to_process)
elif parts[2].startswith(CAMERA_FOCAL_LENGTH):
to_process = parts[2][len(CAMERA_FOCAL_LENGTH): ]
bpy.context.object.data.lens_unit = 'MILLIMETERS'
bpy.context.object.data.lens = float(to_process)
elif parts[2].startswith("-s") or parts[2].startswith('\".ktv['):
#process keyframes
if(currentAnimCurveObject == 0):
#print("Ignoring uncreated objecttype")
return
keys = 0
if( parts[2].startswith("-s") ):
#print("Animcurve by -s")
to_process = parts[2][3:]
#print(to_process)
to_process = to_process.partition(' ')
keys = int( to_process[0] )
to_process = to_process[2]
if(not to_process.startswith("\".ktv")):
#print("Ignoring")
return
if(to_process.strip() == '\".ktv\"') :
# this means the keyframes will be passed on a different line. ignore?
return
if(parts[2].startswith('\".ktv[') ):
# get the amount of keyframes to create from
print(parts[2])
process = parts[2][len('\".ktv['):]
keytext, junk, to_process = process.partition(']\" ')
print("K: "+keytext + " j: "+junk+" TP: "+to_process)
keystart, junk, keystop = keytext.partition(':')
if junk==':':
keys = len( range( int(keystart), int(keystop) ) )
else:
keys =1
print ("No_keys : " +str(keys))
obj = currentAnimCurveObject
if(obj.animation_data is None):
print("Creating animation data and action")
obj.animation_data_create()
obj.animation_data.action = bpy.data.actions.new(name=currentAnimCurveObject.parent.name+"."+currentAnimCurveObject.name+"_"+currentAnimCurveParameter)
else:
print("Animation data already exists")
curve = 0
conversion_rate = 1.0
print("Processing keyframes for object : " + currentAnimCurveObject.name)
print("Parameter: "+currentAnimCurveParameter)
if(currentAnimCurveParameter.startswith("translate") or
currentAnimCurveParameter.startswith("Translate")):
if(currentAnimCurveParameter.endswith("X")):
curve = obj.animation_data.action.fcurves.new(data_path="location", index=0)
elif(currentAnimCurveParameter.endswith("Y")):
curve = obj.animation_data.action.fcurves.new(data_path="location", index=2)
elif(currentAnimCurveParameter.endswith("Z")):
curve = obj.animation_data.action.fcurves.new(data_path="location", index=1)
conversion_rate = -1.0
else:
ValueError("Wrong translation axis!")
s="""mindex =0
if(currentAnimCurveParameter.endswith("X")):
mindex = 0
elif(currentAnimCurveParameter.endswith("Y")):
mindex = 1
elif(currentAnimCurveParameter.endswith("Z")):
mindex = 2
else:
ValueError("Got translation but weird axis!")
try:
#matches = ( x for x in obj.animation_data.action.fcurves if (x.data_path=="location" and x.array_index==mindex) )
for x in obj.animation_data.action.fcurves:
if(x.data_path=="location" and x.array_index==mindex):
curve = x
print("Found curve!")
print("Curve has : "+ curve
break
#curve = matches[0] #obj.animation_data.action.fcurves[0] #index=mindex)
#if(curve.data_path=="location" and curve.array_index==mindex)
# print("has right curve!")
#else:
# ValueError()
except:
print("No curve found, creating new")
curve = obj.animation_data.action.fcurves.new(data_path="location", index=mindex)
"""
if(currentAnimCurveParameter.startswith("rotate") or
currentAnimCurveParameter.startswith("Rotate")):
conversion_rate = 0.017453292523928
if(currentAnimCurveParameter.endswith("X")):
curve = obj.animation_data.action.fcurves.new(data_path="rotation_euler", index=0)
elif(currentAnimCurveParameter.endswith("Y")):
curve = obj.animation_data.action.fcurves.new(data_path="rotation_euler", index=2)
elif(currentAnimCurveParameter.endswith("Z")):
curve = obj.animation_data.action.fcurves.new(data_path="rotation_euler", index=1)
conversion_rate*=-1
else:
ValueError("Wrong rotation axis!")
if(currentAnimCurveParameter.startswith("focalLength") or
currentAnimCurveParameter.startswith("FocalLength")):
curve = obj.animation_data.action.fcurves.new(data_path="data.lens")
obj.data.lens_unit = 'MILLIMETERS'
if curve==0:
print("Ignoring unsupported animation curve "+currentAnimCurveParameter)
return
if(curve is not 0):
to_process = to_process.partition(' ')[2].strip()
print(to_process[0:30])
curve.keyframe_points.add(keys - len(curve.keyframe_points) )
for i in range (0, keys):
frame, skip, value = to_process.partition(' ')
to_process = value.partition(' ')
value = to_process[0]
try:
#print("Adding keyframe "+str(i)+"/"+str(keys)+" f: "+frame+" v: "+value)
f = float(frame)
v = float(value) * conversion_rate
curve.keyframe_points[i].co = f, v
curve.keyframe_points[i].handle_left = (f-2), v
curve.keyframe_points[i].handle_left_type = 'AUTO'
curve.keyframe_points[i].handle_right = (f+2),v
curve.keyframe_points[i].handle_right_type = 'AUTO'
curve.keyframe_points[i].interpolation = 'LINEAR'
except ValueError as e:
print("Failed to convert strings f: "+frame+" v: "+value)
raise e
to_process = to_process[2]
return
tobbew
(tobbew)
July 13, 2013, 7:45am
3
#createNode camera -n "CamShape762" -p "Cam762"
def processCameraLine(line):
global tw_main_node
args = splitArguments(line)
name = stripCitation( args['n'] )
parent = stripCitation( args['p'] )
bpy.ops.object.camera_add()
#just insert some default values
bpy.context.object.data.sensor_width = 1.417* 25.4
bpy.context.object.data.sensor_height = 0.945*25.4
bpy.context.object.data.clip_end = 1000000.0
# bpy.context.object.rotation_mode = 'XZY'
bpy.ops.transform.rotate(value= 90* 0.017453292523928, axis=(1,0,0) );
camera = bpy.context.active_object
camera.name = name
try:
parent_obj = bpy.data.objects[ parent ]
if(parent_obj) :
camera.parent = parent_obj
except:
bpy.context.active_object.parent = tw_main_node
return
def processTransformLine(line):
global tw_main_node
arguments = splitArguments(line)
name = stripCitation( arguments['n'] )
print("Creating transform "+name)
bpy.ops.object.empty_add()
bpy.context.active_object.name = name
bpy.context.object.rotation_mode = 'XZY'
try :
parent = stripCitation( arguments['p'] )
parent_obj = bpy.data.objects[ parent ]
if(parent_obj) :
bpy.context.active_object.parent = parent_obj
except:
bpy.context.active_object.parent = tw_main_node
return
tw_file_line_number = 0 # not really meaningful unless the file ends each ; ended line with a newline
def loadFile(filename):
# create main node to parent everything to
global tw_main_node
tw_main_node = "tw_main_node_"+filename
bpy.ops.object.empty_add()
bpy.context.active_object.name = tw_main_node
tw_main_node = bpy.context.active_object
global tw_file_line_number
with open(filename,'r') as file:
filecontents = file.read()
lines = str.split(filecontents, ';')
for line in lines:
tw_file_line_number+=1
text_to_process = str.strip(line)
if(text_to_process.startswith("createNode transform")):
processTransformLine(line)
elif(text_to_process.startswith("createNode camera")):
processCameraLine(line)
elif(text_to_process.startswith("createNode animCurve")):
processKeyframes(text_to_process)
elif(text_to_process.startswith("setAttr")):
processSetAttrLine(line)
file.close()
print("SCRIPT STARTING")
print("=======================================")
#bpy.ops.view3d.snap_cursor_to_center()
#loadFile("f:\\blender\ est\\7_6_cam_export.ma")