Hi all,
After struggling to make good 3D stereoscopic animations in TG, I wanted to share with the community the script we developed.
We came up with a python script to generate a Stereo camera based on the position and rotation of the first camera and the 1/30th eye separation rule.
This is still a work in progress and at this stage, the z rotation of the main camera is not taken into account. So if you use this script, avoid rotating your camera using z axis.
To run the script, you will need to install Python 2.7 and vpython:
http://www.lfd.uci.edu/~gohlke/pythonlibs/ this is how it works:
copy the code below into a file called
stereo.py create a text file with your zero-paralax heights (this is the location right in the middle of your camera frame where you want your terrain to be right on the screen) . One height per keyframe.
for example if you have a 200 frames animation with 4 key-frames at 0, 50, 150 and 200, your file will look like:
35
35
35
35 (make sure there is no other caracter after the last number).
with 35m being the projection plane altitude at the center of your frame. this value will be probably different for at each key-frame, just check the altitude of your center point.
The script will create a new project file with a second camera called "Stereo Camera".
I've used the 1/30th rule to create the stereo camera location and rotation.
http://www.dashwood3d.com/blog/beginners-guide-to-shooting-stereoscopic-3d/to run the script, open a cmd windows and use the following command line:
c:\python27\python [script folder\]stereo.py [input TGD project] [output TGD project name] [focal-height text file]
Have fun!
check out our Youtube channel, I will upload one of our 3D stereo animation very soon.
http://www.youtube.com/user/Aerometrex/'''
Created on 03/09/2012
Parse TGD XML file and add second camera, offsetting and rotating first camera
@author: Tisham- Aerometrex
'''
from visual import *
import codecs
import xml.dom.minidom as mdom
import sys
infile = sys.argv[1]
outfile = sys.argv[2]
focal_heights = sys.argv[3]
focals = map(lambda x : float(x), file(focal_heights).readlines())
doc = mdom.parse(infile)
camera_node = doc.getElementsByTagName("camera")[0]
anim_datas = camera_node.getElementsByTagName("animationData")
camera_data = {"position_0":list(),
"position_1":list(),
"position_2":list(),
"rotation_0":list(),
"rotation_1":list(),
"rotation_2":list(),
"motion_blur_length_0":list()}
for anim_data in anim_datas:
pa = anim_data.getAttribute("param")
index = anim_data.getAttribute("componentIndex")
dict_key = pa+"_"+index
keys = anim_data.getElementsByTagName("key")
for key in keys:
camera_data[dict_key].append(float(key.getAttribute("value")))
num_keys = len(camera_data['position_0'])
if (len(focals) != num_keys):
print "Need matching",len(focals),"!=",num_keys,"focal heights"
print "Offsetting",num_keys,"Key Frames"
for i in range(num_keys):
x = camera_data["position_0"][i]
y = camera_data["position_1"][i]
z = camera_data["position_2"][i]
o = camera_data["rotation_0"][i]
t = camera_data["rotation_1"][i]
k = camera_data["rotation_2"][i]
eye_sep = (y-focals[i])/(cos(radians(90+o))*30)
v = vector(eye_sep,0,0)
print "Key Frame:",i,"Magic var:",eye_sep*30,"Eye sep:",eye_sep
pos = vector(x,y,z)
offset = v.rotate(radians(o),vector(1,0,0)).rotate(radians(t),vector(0,1,0))
pos = pos+offset
camera_data["position_0"][i] = pos.x
camera_data["position_1"][i] = pos.y
camera_data["position_2"][i] = pos.z
camera_copy_node = camera_node.cloneNode(True)
camera_copy_node.setAttribute("name","Stereo Camera")
copy_anim_datas = camera_copy_node.getElementsByTagName("animationData")
for anim_data in copy_anim_datas:
pa = anim_data.getAttribute("param")
index = anim_data.getAttribute("componentIndex")
dict_key = pa+"_"+index
keys = anim_data.getElementsByTagName("key")
if pa=="position":
for i in range(num_keys):
keys[i].setAttribute("value",str(camera_data[dict_key][i]))
doc.childNodes[0].appendChild(camera_copy_node)
with codecs.open(outfile, "w", "utf-8") as out:
doc.writexml(out)