diff options
Diffstat (limited to 'release/scripts/c3d_import.py')
-rw-r--r-- | release/scripts/c3d_import.py | 1243 |
1 files changed, 1243 insertions, 0 deletions
diff --git a/release/scripts/c3d_import.py b/release/scripts/c3d_import.py new file mode 100644 index 00000000000..bfe691c394c --- /dev/null +++ b/release/scripts/c3d_import.py @@ -0,0 +1,1243 @@ +#!BPY +# -*- coding: latin-1 -*- +""" +Name: 'Motion Capture (.c3d)...' +Blender: 246 +Group: 'Import' +Tooltip: 'Import a C3D Motion Capture file' +""" +__script__ = "C3D Motion Capture file import" +__author__ = " Jean-Baptiste PERIN, Roger D. Wickes (rogerwickes@yahoo.com)" +__version__ = "0.9" +__url__ = ["Communicate problems and errors, BlenderArtists.org, Python forum"] +__email__= ["rogerwickes@yahoo.com", "c3d script"] +__bpydoc__ = """\ +c3d_import.py v0.8 + +Script loading Graphics Lab Motion Capture file, +Usage:<br> + - Run the script <br> + - Choose the file to open<br> + - Press Import C3D button<br> + +Version History: + 0.4: PERIN Released under Blender Artistic Licence + 0.5: WICKES used marker names, fixed 2.45 depricated call + 0.6: WICKES creates armature for each subject + 0.7: WICKES constrains armature to follow the empties (markers). Verified for shake hands s + 0.8: WICKES resolved DEC support issue + 0.9: BARTON removed scene name change, whitespace edits. WICKES added IK layers +""" + +#---------------------------------------------- +# (c) Jean-Baptiste PERIN december 2005, released under Blender Artistic Licence +# for the Blender 2.40 Python Scripts Bundle. +#---------------------------------------------- + +###################################################### +# This script imports a C3D file into blender. +# Loader is based on MATLAB C3D loader from +# Alan Morris, Toronto, October 1998 +# Jaap Harlaar, Amsterdam, april 2002 +###################################################### + +import string +import Blender +from Blender import * +import bpy +import struct +import BPyMessages +Vector= Blender.Mathutils.Vector +Euler= Blender.Mathutils.Euler +Matrix= Blender.Mathutils.Matrix +RotationMatrix = Blender.Mathutils.RotationMatrix +TranslationMatrix= Blender.Mathutils.TranslationMatrix + +#================= +# Global Variables, Constants, Defaults, and Shorthand References +#================= +# set senstitivity for displaying debug/console messages. 0=few, 100=max, including clicks at major steps +# debug(num,string) to conditionally display status/info in console window +DEBUG=Blender.Get('rt') + +# marker sets known in the world +HUMAN_CMU= "HumanRTKm.mkr" # The Human Real-Time capture marker set used by CMU +HUMAN_CMU2="HumanRT.mkr" # found in another file, seems same as others in that series +MARKER_SETS = [ HUMAN_CMU, HUMAN_CMU2 ] # marker sets that this program supports (can make an armature for) +XYZ_LIMIT= 10000 #max value for coordinates if in integer format + +# what layers to put stuff on in scene. 1 is selected, so everything goes there +# selecting only layer 2 shows only the armature moving, 12 shows only the empties +LAYERS_ARMOB= [1,2] +LAYERS_MARKER=[1,12] +LAYERS_IK=[1,11] +IK_PREFIX="ik_" # prefix in empty name: ik_prefix+subject prefix+bone name + +CLEAN=True # Should program ignore markers at (0,0,0) and beyond the outer limits? + +scn = Blender.Scene.GetCurrent() + +BCS=Blender.Constraint.Settings # shorthand dictionary - define with brace, reference with bracket +trackto={"+x":BCS.TRACKX, "+y":BCS.TRACKY, "+z":BCS.TRACKZ, "-x":BCS.TRACKNEGX, "-y":BCS.TRACKNEGY, "-z":BCS.TRACKNEGZ} +trackup={"x":BCS.UPX, "y":BCS.UPY, "z":BCS.UPZ} + +#=============================# +# Classes +#=============================# +class Marker: + def __init__(self, x, y, z): + self.x=0.0 + self.y=0.0 + self.z=0.0 + + def __repr__(self): #report on self, as in if just printed + return str("[x = "+str(self.x) +" y = " + str(self.y)+" z = "+ str(self.z)+"]") + +class ParameterGroup: + def __init__(self, nom, description, parameter): + self.name = nom + self.description = description + self.parameter = parameter + + def __repr__(self): + return self.name, " ", self.description, " ", self.parameter + +class Parameter: + def __init__(self, name, datatype, dim, data, description): + self.name = name + self.datatype = datatype + self.dim = dim + self.data = data + self.description = description + + def __repr__(self): + return self.name, " ", self.description, " ", self.dim + +class MyVector: + def __init__(self, fx,fy,fz): + self.x=fx + self.y=fy + self.z=fz + +class Mybone: + "information structure for bone generation and posing" + def __init__(self, name,vec,par,head,tail,const): + self.name=name # name of this bone. must be unique within armature + self.vec=vec # edit bone vector it points + self.parent=par # name of parent bone to locate head and form a chain + self.headMark=head # list of 0+ markers where the head of this non-parented bone should be placed + self.tailMark=tail # list of 0+ markers where the tip should be placed + self.const=const # list of 0+ constraint tuples to control posing + self.head=MyVector(0,0,0) #T-pose location + self.tail=MyVector(0,0,0) + def __repr__(self): + return '[Mybone "%s"]' % self.name + + +#=============================# +# functions/modules +#=============================# +def error(str): + Draw.PupMenu('ERROR%t|'+str) + return +def status(str): + Draw.PupMenu('STATUS%t|'+str+"|Continue?") + return +def debug(num,msg): #use log4j or just console here. + if DEBUG >= num: + print 'debug:', (' '*num), msg + #TODO: if level 0, make a text file in Blender file to record major stuff + return + +def names(ob): return ob.name + + +######### +# Cette fonction renvoie la liste des empties +# in : +# out : emp_list (List of Object) la liste des objets de type "Empty" +######### +def getEmpty(name): + obs = [ob for ob in scn.objects if ob.type=="Empty" and ob.name==name] + if len(obs)==0: + return None + elif len(obs)==1: + return obs[0] + else: + error("FATAL ERROR: %i empties %s in file" % (len(obs),ob[0])) +######### +# Cette fonction renvoie un empty +# in : objname : le nom de l'empty recherche +# out : myobj : l'empty cree ou retrouve +######### +def getOrCreateEmpty(objname): + myobj= getEmpty(objname) + if myobj==None: + myobj = scn.objects.new("Empty",objname) + debug(50,'Marker/Empty created %s' % myobj) + return myobj + +def getOrCreateCurve(ipo, curvename): + """ + Retrieve or create a Blender Ipo Curve named C{curvename} in the C{ipo} Ipo + + >>> import mylib + + >>> lIpo = GetOrCreateIPO("Une IPO") + >>> laCurve = getOrCreateCurve(lIpo, "RotX") + + Either an ipo curve named C{curvename} exists before the call then this curve is returned, + Or such a curve doesn't exist before the call .. then it is created into the c{ipo} Ipo and returned + + @type ipo: Blender Ipo + @param ipo: the Ipo in which the curve must be retrieved or created. + @type curvename: string + @param curvename: name of the IPO. + @rtype: Blender Curve + @return: a Blender Curve named C{curvename} in the C{ipo} Ipo + """ + try: + mycurve = ipo.getCurve(curvename) + if mycurve != None: + pass + else: + mycurve = ipo.addCurve(curvename) + except: + mycurve = ipo.addCurve(curvename) + return mycurve + +def eraseIPO (objectname): + object = Blender.Object.Get(objectname) + lIpo = object.getIpo() + if lIpo != None: + nbCurves = lIpo.getNcurves() + for i in range(nbCurves): + nbBezPoints = lIpo.getNBezPoints(i) + for j in range(nbBezPoints): + lIpo.delBezPoint(i) + +def comp_loc(emptyNameList): + myloc=Vector(0,0,0) + for emName in emptyNameList: + myobj = Blender.Object.Get(emName) + for i in range(3): + myloc[i]= myloc[i]+(myobj.loc[i]/len(emptyNameList)) #take the average loc of all marks + return myloc + +def comp_len(head, tail): # computes the length of a bone + headvec=comp_loc(head) + tailvec=comp_loc(tail) + netvec=headvec-tailvec + return netvec.length + +def createHumanCMU(): # human bone structure, makes a node set for CMU MoCap Lab + # order of bones: "spine","chest","neck","head",...face toward you in front view + # pose constraints are tuples of (type,target,influence,other-as-needed) + # constraint stack order is important. for proper bone pointing and orinetation: + # IK, then TT +YZ in world space. then LR XZ to 0 in world space, this points the bone, twists it, but then + # limits the rotation to the sidebar enpty with the Z facing it, and Y pointing along the bone. + nodes=[] # bonename, vector, parent, head targets, tail targets, constraint list + for i in range(23): nodes.append(Mybone("name","vec","par",[],[],[])) + nodes[0]= Mybone("root", "-Y","",["RBWT", "LBWT"],["RFWT", "LFWT", "RBWT", "LBWT"],[("LOC","RBWT",1.0),("LOC","LBWT",0.5),("IK","RFWT",1.0),("IK","LFWT",0.5),("TT","RBWT",1,"+YZ"),("LR","XZ",1)]) + nodes[1]= Mybone("spine","+Z","root",[],["STRN","T10"],[("IK","STRN",1.0),("IK","T10",0.5),("TT","STRN",1,"+YZ"),("LR","XZ",1)]) + nodes[2]= Mybone("chest","+Z","spine",[],["CLAV","C7"],[("IK","CLAV",1.0),("IK","C7",0.5),("TT","CLAV",1,"+YZ"),("LR","XZ",1)]) + nodes[3]= Mybone("neck", "+Z","chest",[],["RBHD","LBHD"],[("IK","RBHD",1.0),("IK","LBHD",0.5),("TT","LBHD",1,"+YZ"),("LR","XZ",1)]) + nodes[4]= Mybone("head" ,"-Y","neck",[],["RFHD","LFHD"],[("IK","RFHD",1.0),("IK","LFHD",0.5),("TT","LFHD",1,"+YZ"),("LR","XZ",1)]) + + nodes[5]= Mybone("shoulder.R","-X","chest",[],["RSHO"],[("IK","RSHO",1.0)]) + nodes[6]= Mybone("toparm.R", "-X","shoulder.R",[],["RELB"],[("IK","RELB",1.0),("TT","RUPA",1,"+YZ"),("LR","XZ",1)]) + nodes[7]= Mybone("lowarm.R", "-X","toparm.R",[],["RWRA","RWRB"],[("IK","RWRA",1.0),("IK","RWRB",0.5),("TT","RFRM",1,"+YZ"),("LR","XZ",1)]) + nodes[8]= Mybone("hand.R", "-X","lowarm.R",[],["RFIN"],[("IK","RFIN",1.0),("TT","RWRA",1,"+YZ"),("LR","XZ",1)]) #missing ,"RTHM" + + nodes[9]= Mybone("hip.R", "-X","root",[],["RFWT","RBWT"],[("IK","RFWT",1.0),("IK","RBWT",0.5)]) + nodes[10]=Mybone("topleg.R","-Z","hip.R",[],["RKNE"],[("IK","RKNE",1),("TT","RTHI",1,"+YZ"),("LR","XZ",1)]) + nodes[11]=Mybone("lowleg.R","-Z","topleg.R",[],["RANK","RHEE"],[("IK","RHEE",1.0),("TT","RSHN",1,"+YZ"),("LR","XZ",1)]) + nodes[12]=Mybone("foot.R", "-Y","lowleg.R",[],["RTOE","RMT5"],[("IK","RTOE",1.0),("IK","RMT5",0.2),("TT","RMT5",1,"+YZ")]) + nodes[13]=Mybone("toes.R", "-Y","foot.R",[],["RTOE"],[("IK","RTOE",1.0)]) + + nodes[14]=Mybone("shoulder.L","+X","chest",[],["LSHO"],[("IK","LSHO",1.0)]) + nodes[15]=Mybone("toparm.L", "+X","shoulder.L",[],["LELB"],[("IK","LELB",1.0),("TT","LUPA",1,"+YZ"),("LR","XZ",1)]) + nodes[16]=Mybone("lowarm.L", "+X","toparm.L",[],["LWRA","LWRB"],[("IK","LWRA",1.0),("IK","LWRB",0.5),("TT","LFRM",1,"+YZ"),("LR","XZ",1)]) + nodes[17]=Mybone("hand.L", "+X","lowarm.L",[],["LFIN"],[("IK","LFIN",1.0),("TT","RWRA",1,"+YZ"),("LR","XZ",1)]) #missing ,"LTHM" + + nodes[18]=Mybone("hip.L", "+X","root",[],["LFWT","LBWT"],[("IK","LFWT",1.0),("IK","LBWT",0.5)]) + nodes[19]=Mybone("topleg.L","-Z","hip.L",[],["LKNE"],[("IK","LKNE",1),("TT","LTHI",1,"+YZ"),("LR","XZ",1)]) + nodes[20]=Mybone("lowleg.L","-Z","topleg.L",[],["LANK","LHEE"],[("IK","LHEE",1.0),("TT","LSHN",1,"+YZ"),("LR","XZ",1)]) + nodes[21]=Mybone("foot.L", "-Y","lowleg.L",[],["LTOE","LMT5"],[("IK","LTOE",1.0),("IK","LMT5",0.2),("TT","LMT5",1,"+YZ"),("LR","XZ",1)]) + nodes[22]=Mybone("toes.L", "-Y","foot.L",[],["LTOE"],[("IK","LTOE",1.0)]) + return nodes + +def createNodes(marker_set): # make a list of bone name, parent, edit head loc, edit tail loc, pose constraints + #ultimately, I want to read in an XML file here that specifies the node trees for various marker sets + if marker_set==HUMAN_CMU: nodes= createHumanCMU() #load up and verify the file has the CMU marker set + elif marker_set==HUMAN_CMU2: nodes= createHumanCMU() + else: nodes=[] + return nodes +def findEntry(item,list): + for i in range(len(list)): + if item==list[i]: break + debug(100,"findEtnry %s is %i in list of %i items" % (item,i,len(list))) + return i +def makeNodes(prefix, markerList, empties, marker_set): #make sure the file has the nodes selected + nodes= createNodes(marker_set) # list has generic marker names; replace them with the actual object names created + #each entry in markerlist has a corresponding entry in empties in the same order + errList=[] + for i in range(len(nodes)): + node= nodes[i] + debug(60,"Adapting node %s to prefix %s" % (node,prefix)) + + #replace generic head markers with actual empty names + for im in range(len(node.headMark)): + marker= node.headMark[im] + mark= prefix+marker + imn= findEntry(mark,markerList) + if imn < len(markerList): + debug(90,"Adapating head marker %s to %s" % (marker,empties[imn].name)) + nodes[i].headMark[im]= empties[imn].name + else: errList.append([node.name,"head location",mark,node,2]) + + #replace generic tail markers with actual empty names + for im in range(len(node.tailMark)): + marker= node.tailMark[im] + mark= prefix+marker + imn= findEntry(mark,markerList) + if imn < len(markerList): + debug(90,"Adapating marker %s to %s" % (marker,empties[imn].name)) + nodes[i].tailMark[im]= empties[imn].name + else: errList.append([node.name,"tail location",mark,node,2]) + + #replace generic constraint markers (if the constraint references a marker) with empty name + for im in range(len(node.const)): + const=node.const[im] + if const[0] in ("LOC","IK","TT"): + marker=const[1] + mark= prefix+marker + imn= findEntry(mark,markerList) + if imn < len(markerList): + debug(90,"Adapating %s constraint marker %s to %s" % (const[0],marker,empties[imn].name)) + if const[0] in ("IK","LR","LOC"): + nodes[i].const[im]=(const[0], empties[imn].name, const[2]) + else: nodes[i].const[im]=(const[0], empties[imn].name, const[2], const[3]) + else: errList.append([node.name,const[0]+" constraint",mark,node,4]) + + if errList!=[]: #we have issues. + for err in errList: + debug(0,"Bone "+err[0]+" specifies "+err[2]+" as "+err[1]+"which was not specified in file.") + #need a popup here to ignore/cleanup node tree, or add the marker(?) or abort + usrOption= 1 + if usrOption==0: #ignore this marker (remove it) + for node in nodes: #find the bone in error + if node.name==err[0]: + print "Before",node + if err[3] in range(2,3): + node[err[3]].remove(err[2]) #find the marker in error and remove it + elif err[3]==4: #find the constraint and remove it + for const in node.const: + if const[1]==err[2]: node.const.remove(const) + print "After",node + elif usrOption==1: #add these markers as static empties, and user will automate them later + #and the bones will be keyed to them, so it will all be good. + #file may have just mis-named the empty, or the location can be derived based on other markers + em= getOrCreateEmpty(err[2]) + em.layers= LAYERS_MARKER + else: abort() #abend + if DEBUG==100: status("Nodes Updated") + return nodes #nodes may be updated + +def makeBones(arm,nodes): + debug(20,"Making %i edit bones" % len(nodes)) + for node in nodes: + bone= Blender.Armature.Editbone() + bone.name= node.name + arm.bones[bone.name]= bone #add it to the armature + debug(50,"Bone added: %s" % bone) + if bone.name <> node.name: + debug(0,"ERROR: duplicate node % name specified" % node.name) + node.name= bone.name #you may not get what you asked for + if node.parent!="": #parent + debug(60,"Bone parent: %s"%node.parent) + bone.parent= arm.bones[node.parent] + bone.options = [Armature.CONNECTED] + #compute head = average of the reference empties + if node.headMark==[]: # no head explicitly stated, must be tail of parent + for parnode in nodes: + if node.parent==parnode.name: break + node.headMark= parnode.tailMark + node.head= parnode.tail + else: node.head= comp_loc(node.headMark) #node head is specified, probably only for root. + + bone.head= node.head + debug(60,"%s bone head: (%0.2f, %0.2f, %0.2f)" % (bone.name,bone.head.x, bone.head.y, bone.head.z)) + mylen=comp_len(node.headMark,node.tailMark) # length of the bone as it was recorded for that person + # for our T position, compute the bone length, add it to the head vector component to get the tail + if node.vec[0]=="-": mylen=-mylen + debug(80,"Bone vector %s length %0.2f" %(node.vec,mylen)) + node.tail= Vector(node.head) + myvec=node.vec[1].lower() + if myvec=="x": node.tail.x+=mylen + elif myvec=="y": node.tail.y+=mylen + elif myvec=="z": node.tail.z+=mylen + else: + debug(0,"%s %s %s %s" % (node.vec,myvec,node.vec[0],node.vec[1])) + error("ERROR IN BONE SPEC ") + bone.tail= node.tail + debug(60,"Bone tail: (%i,%i,%i)" %(bone.tail.x, bone.tail.y, bone.tail.z)) + #Armature created in the T postion, but with bone lengths to match the marker set and subject + #when this is constrained to the markers, the recorded action will be relative to a know Rotation + #so that all recorded actions should be interchangeable. wooot! + #Only have to adjust starting object loc when matching up actions. + return #arm #updated + +def makeConstLoc(pbone,const): + const_new= pbone.constraints.append(Constraint.Type.COPYLOC) + const_new.name = const[0]+"-"+const[1] + const_target=Blender.Object.Get(const[1]) + const_new[BCS.TARGET]= const_target + const_new.influence = const[2] + return + +def makeConstLimRot(pbone,const): + const_new= pbone.constraints.append(Constraint.Type.LIMITROT) + const_new.name = const[0]+"-"+const[1] + for axis in const[1]: + if axis.lower()=="x": const_new[BCS.LIMIT] |= BCS.LIMIT_XROT #set + if axis.lower()=="y": const_new[BCS.LIMIT] |= BCS.LIMIT_YROT #set + if axis.lower()=="z": const_new[BCS.LIMIT] |= BCS.LIMIT_ZROT #set + const_new[BCS.OWNERSPACE]= BCS.SPACE_LOCAL + const_new.influence = const[2] + # fyi, const[Constraint.Settings.LIMIT] &= ~Constraint.Settings.LIMIT_XROT #reset + return + +def makeConstIK(prefix,pbone,const): + #Blender 246 only supports one IK Solver per bone, but we might want many, + # so we need to create a reference empty named after the bone + # that floats between the markers, so the bone can point to it as a singularity + myob= getOrCreateEmpty(IK_PREFIX+prefix+pbone.name) + myob.layers= LAYERS_IK + # note that this empty gets all the IK constraints added on as location constraints + myconst= myob.constraints.append(Constraint.Type.COPYLOC) + myconst.name=const[0]+"-"+const[1] + myconst[Constraint.Settings.TARGET]= Blender.Object.Get(const[1]) + myconst.influence = const[2] + + #point the bone once to the empty via IK + success=False + for myconst in pbone.constraints: + if myconst.type == Constraint.Type.IKSOLVER: success=True + if not(success): #add an IK constraint to the bone to point to the empty + #print pbone + myconst= pbone.constraints.append(Constraint.Type.IKSOLVER) + myconst.name = const[1] + myconst[BCS.TARGET]= myob + myconst.influence = const[2] + #const_new[Constraint.Settings.BONE]= ? + myconst[BCS.CHAINLEN]= 1 + myconst[BCS.USETIP]= True + myconst[BCS.STRETCH]= False + return + +def makeConstTT(pbone,const): + myconst= pbone.constraints.append(Constraint.Type.TRACKTO) + myconst.name=const[0]+"-"+const[1] + debug(70,"%s %s" % (myconst,const[3])) + myob= getEmpty(const[1]) + if myob!= None: + myconst[BCS.TARGET]= myob + myconst.influence = const[2] + #const[3] is the Track and the thrird char is the Up indicator + myconst[BCS.TRACK]= trackto[const[3][0:2].lower()] + myconst[BCS.UP]=trackup[const[3][2].lower()]#up direction + myconst[BCS.OWNERSPACE]= BCS.SPACE_LOCAL + myconst[BCS.TARGETSPACE]= [BCS.SPACE_LOCAL] + if const[3][1]==const[3][2]: debug(0,"WARNING: Track To axis and up axis should not be the same. Constraint is INACTIVE") + else: #marker not found. could be missing from this file, or an error in node spec + error("TrackTo Constraint for %s |specifies unknown marker %s" % (pbone.name,const[1])) + return + +def makePoses(prefix,arm_ob,nodes): # pose this armature object based on node requirements + #this is constraint-based posing, not hard-keyed posing. + #we do constraint-based first so that user can adjust the constraints, possibly smooth/tweak motion + # add additional bones or referneces/constraints, before baking to hard keyframes + + pose= arm_ob.getPose() + debug(0,"Posing %s %s" % (arm_ob, pose)) + for node in nodes: + debug(30, "examining %s" %node) + if len(node.const)>0: #constraints for this bone are desired + pbone = pose.bones[node.name] + debug(40,"Posing bone %s" %pbone) + for const in node.const: + debug(50,"Constraining %s by %s" %(pbone,const)) + if const[0]=="LOC":makeConstLoc(pbone,const) + elif const[0]=="IK": makeConstIK(prefix,pbone,const) + elif const[0]=="LR": makeConstLimRot(pbone,const) + elif const[0]=="TT": makeConstTT(pbone,const) + else: + error("FATAL: constraint %s not supported" %const[0]) + break + debug(10, "Posing complete. Cycling pose and edit mode") + pose.update() + return + +def make_arm(subject,prefix,markerList, emptyList,marker_set): + debug(10,"**************************") + debug(00, "**** Making Armature for %s..." % subject) + debug(10, "**************************") + # copied from bvh import bvh_node_dict2armature; trying to use similar process for further integtration down the road + # Add the new armature, + + nodes= makeNodes(prefix, markerList, emptyList, marker_set) #assume everyone in file uses the same mocap suit + # each person in the file may be different height, so each needs their own new armature to match marker location + +## obs= Blender.Object.Get() +## success=False +## for ob in obs: +## if ob.name==subject: +## success=True +## if success: +## menu="Human Armature already exists for this subject." +## menu+="%t|Create another in this scene" +## menu+="%l|Start a new scene" +## menu+="%l|Use this armature" +## menusel= Draw.PupMenu(menu) + + arm= Blender.Armature.New(subject) #make an armature. + debug(10,"Created Armature %s" % arm) + # Put us into editmode + arm.makeEditable() + arm.drawType = Armature.OCTAHEDRON + makeBones(arm,nodes) + scn = Blender.Scene.GetCurrent() #add it to the current scene. could create new scenes here as yaf + arm_ob= scn.objects.new(arm) #instance it in the scene. this is the new way for 2.46 to instance objects + arm_ob.name= subject #name it something like the person it represents + arm_ob.layers= LAYERS_ARMOB + debug(20,"Instanced Armature %s" % arm_ob) + arm.update() #exit editmode. Arm must be instanced as an object before you can save changes or pose it + Blender.Redraw() # show the world + if DEBUG==100: status("T-Bones made.") + + makePoses(prefix,arm_ob,nodes) #constrain arm_ob with these markers + + scn.update(1) #make everyone behave themselves in the scene, and respect the new constraints + return arm_ob + +def setupAnim(StartFrame, EndFrame, VideoFrameRate): + debug(100, 'VideoFrameRate is %i' %VideoFrameRate) + if VideoFrameRate<1: VideoFrameRate=1 + if VideoFrameRate>120: VideoFrameRate=120 + # set up anim panel for them + context=scn.getRenderingContext() + context.startFrame(StartFrame) + context.endFrame(EndFrame) + context.framesPerSec(int(VideoFrameRate)) + Blender.Set("curframe",StartFrame) + Blender.Redraw() + return + +def makeCloud(Nmarkers,markerList,StartFrame,EndFrame,Markers): + debug(10, "**************************") + debug(00, "*** Making Cloud Formation") + debug(10, "**************************") + empties=[] + ipos=[] + curvesX=[] + curvesY=[] + curvesZ=[] + debug(0, "%i Markers (empty cloud) will be put on layers %s" % (Nmarkers,LAYERS_MARKER)) + # Empty Cloud formation + for i in range(Nmarkers): + debug(100,"%i marker %s"%(i, markerList[i])) + emptyname = markerList[i] # rdw: to use meaningful names from Points parameter + em= getOrCreateEmpty(emptyname) #in this scene + em.layers= LAYERS_MARKER + #make a list of the actual empty + empties.append(em) + #assign it an ipo with the loc xyz curves + lipo = Ipo.New("Object",em.name) + ipos.append(lipo) + curvesX.append(getOrCreateCurve(ipos[i],'LocX')) + curvesY.append(getOrCreateCurve(ipos[i],'LocY')) + curvesZ.append(getOrCreateCurve(ipos[i],'LocZ')) + empties[i].setIpo(ipos[i]) + debug(30,"Cloud of %i empties created." % len(empties)) + NvideoFrames= EndFrame-StartFrame+1 + debug(10, "**************************") + debug(00, "**** Calculating Marker Ipo Curves over %i Frames ..." % NvideoFrames) + debug(10, "**************************") + err= index=0 #number of errors, logical frame + for frame in range(StartFrame,EndFrame+1): + if index==0: start=sys.time() + elif index==100: + tmp=(NvideoFrames-100)*(sys.time()-start)/6000 + debug(0,"%i minutes process time estimated" % tmp) + elif index >100: print index*100/(NvideoFrames-1),"% complete\r", + for i in range(Nmarkers): + if Markers[index][i].z < 0: Markers[index][i].z= -Markers[index][i].z + success=True + if CLEAN: #check for good data + # C3D marker decoding may have coordinates negative (improper sign bit decoding?) + myX= abs(Markers[index][i].x) + myY= abs(Markers[index][i].y) + myZ= Markers[index][i].z + if myX > 10000 or myY > 10000 or myZ > 10000: success=False + if myX <.01 and myY <.01 and myZ <.01: success=False # discontinuity in marker tracking (lost marker) + + if success: + curvesX[i].append((frame, Markers[index][i].x)) #2.46 knot method + curvesY[i].append((frame, Markers[index][i].y)) + curvesZ[i].append((frame, Markers[index][i].z)) + if frame==StartFrame: debug(40, "%s loc frame %i: (%0.2f, %0.2f, %0.2f)" % (markerList[i],frame,Markers[index][i].x,Markers[index][i].y,Markers[index][i].z)) + else: + err+=1 # some files have thousands... + #debug(30,"Point ignored for marker:%s frame %i: (%i, %i, %i)" % (markerList[i],frame,Markers[index][i].x,Markers[index][i].y,Markers[index][i].z)) + index += 1 + debug(70, "%i points ignored across all markers and frames. Recalculating..." % err) + + for i in range(Nmarkers): + curvesX[i].Recalc() + curvesY[i].Recalc() + curvesZ[i].Recalc() + Blender.Set('curframe', StartFrame) + Blender.Redraw() + if DEBUG==100: status("Clound formed") + return empties + +def getNumber(str, length): + if length==2: # unsigned short + return struct.unpack('H',str[0:2])[0], str[2:] + sum = 0 + for i in range(length): + #sum = (sum << 8) + ord(str[i]) for big endian + sum = sum + ord(str[i])*(2**(8*i)) + return sum, str[length:] +def unpackFloat(chunk,proctype): + #print proctype + myvar=chunk[0:4] + if proctype==2: #DEC-VAX + myvar=chunk[2:4]+chunk[0:2] #swap lo=hi word order pair + return struct.unpack('f',myvar[0:4])[0] + +def getFloat(chunk,proctype): + return unpackFloat(chunk, proctype), chunk[4:] +def parseFloat(chunk,ptr,proctype): + return unpackFloat(chunk[ptr:ptr+4], proctype), ptr+4 + + +def load_c3d(FullFileName): +# Input: FullFileName - file (including path) to be read +# +# Variable: +# Markers 3D-marker data [Nmarkers x NvideoFrames x Ndim(=3)] +# VideoFrameRate Frames/sec +# AnalogSignals Analog signals [Nsignals x NanalogSamples ] +# AnalogFrameRate Samples/sec +# Event Event(Nevents).time ..value ..name +# ParameterGroup ParameterGroup(Ngroups).Parameters(Nparameters).data ..etc. +# CameraInfo MarkerRelated CameraInfo [Nmarkers x NvideoFrames] +# ResidualError MarkerRelated ErrorInfo [Nmarkers x NvideoFrames] + + Markers=[]; + VideoFrameRate=120; + AnalogSignals=[]; + AnalogFrameRate=0; + Event=[]; + ParameterGroups=[]; + CameraInfo=[]; + ResidualError=[]; + + debug(10, "*********************") + debug(10, "**** Opening File ***") + debug(10, "*********************") + + #ind=findstr(FullFileName,'\'); + #if ind>0, FileName=FullFileName(ind(length(ind))+1:length(FullFileName)); else FileName=FullFileName; end + debug(0, "FileName = " + FullFileName) + fid=open(FullFileName,'rb'); # native format (PC-intel). ideasman says maybe rU + content = fid.read(); + content_memory = content + #Header section + NrecordFirstParameterblock, content = getNumber(content,1) # Reading record number of parameter section + + key, content = getNumber(content,1) + if key!=80: + error('File: does not comply to the C3D format') + fid.close() + return + #Paramter section + content = content[512*(NrecordFirstParameterblock-1)+1:] # first word ignored + #file format spec says that 3rd byte=NumberofParmaterRecords... but is ignored here. + proctype,content =getNumber(content,1) + proctype = proctype-83 + proctypes= ["unknown","(INTEL-PC)","(DEC-VAX)","(MIPS-SUN/SGI)"] + + if proctype in (1,2): debug(0, "Processor coding %s"%proctypes[proctype]) + elif proctype==3: debug(0,"Program untested with %s"%proctypes[proctype]) + else: + debug(0, "INVALID processor type %i"%proctype) + proctype=1 + debug(0,"OVERRIDE processor type %i"%proctype) + + #if proctype==2, + # fclose(fid); + # fid=fopen(FullFileName,'r','d'); % DEC VAX D floating point and VAX ordering + #end + debug(10, "***********************") + debug(00, "**** Reading Header ***") + debug(10, "***********************") + + # ############################################### + # ## ## + # ## read header ## + # ## ## + # ############################################### + + #%NrecordFirstParameterblock=fread(fid,1,'int8'); % Reading record number of parameter section + #%key1=fread(fid,1,'int8'); % key = 80; + + content = content_memory + #fseek(fid,2,'bof'); + content = content[2:] + + # + Nmarkers, content=getNumber(content, 2) + NanalogSamplesPerVideoFrame, content = getNumber(content, 2) + StartFrame, content = getNumber(content, 2) + EndFrame, content = getNumber(content, 2) + MaxInterpolationGap, content = getNumber(content, 2) + + Scale, content = getFloat(content,proctype) + + NrecordDataBlock, content = getNumber(content, 2) + NanalogFramesPerVideoFrame, content = getNumber(content, 2) + + if NanalogFramesPerVideoFrame > 0: + NanalogChannels=NanalogSamplesPerVideoFrame/NanalogFramesPerVideoFrame + else: + NanalogChannels=0 + + VideoFrameRate, content = getFloat(content,proctype) + + AnalogFrameRate=VideoFrameRate*NanalogFramesPerVideoFrame + NvideoFrames = EndFrame - StartFrame + 1 + + debug(0, "Scale= %0.2f" %Scale) + debug(0, "NanalogFramesPerVideoFrame= %i" %NanalogFramesPerVideoFrame) + debug(0, "Video Frame Rate= %i" %VideoFrameRate) + debug(0, "AnalogFrame Rate= %i"%AnalogFrameRate) + debug(0, "# markers= %i" %Nmarkers) + debug(0, "StartFrame= %i" %StartFrame) + debug(0, "EndFrame= %i" %EndFrame) + debug(0, "# Video Frames= %i" %NvideoFrames) + + if Scale>0: + debug(0, "Marker data is in integer format") + if Scale>(XYZ_LIMIT/32767): + Scale=XYZ_LIMIT/32767.0 + debug(0, "OVERRIDE: Max coordinate is %i, Scale changed to %0.2f" % (XYZ_LIMIT,Scale)) + else: debug(0, "Marker data is in floating point format") + if VideoFrameRate<1 or VideoFrameRate>120: + VideoFrameRate= 120 + debug(0, "OVERRIDE Video Frame Rate= %i" %VideoFrameRate) + if proctype not in (1,2): # Intel, DEC are known good + debug(0, "OVERRIDE|Program not tested with this encoding. Set to Intel") + proctype= 1 + + debug(10, "***********************") + debug(10, "**** Reading Events ...") + debug(10, "***********************") + + content = content_memory + content = content[298:] #bizarre .. ce devrait être 150 selon la doc rdw skips first 299 bytes? + + EventIndicator, content = getNumber(content, 2) + EventTime=[] + EventValue=[] + EventName=[] + + debug(0, "Event Indicator = %i" %EventIndicator) + if EventIndicator==12345: #rdw: somehow, this original code seems fishy, but I cannot deny it. + Nevents, content = getNumber(content, 2) + debug(0, "Nevents= %i" %Nevents) + content = content[2:] + if Nevents>0: + for i in range(Nevents): + letime, content = getFloat(content,proctype) + EventTime.append(letime) + content = content_memory + content = content[188*2:] + for i in range(Nevents): + lavalue, content = getNumber(content, 1) + EventValue.append(lavalue) + content = content_memory + content = content[198*2:] + for i in range(Nevents): + lenom = content[0:4] + content = content[4:] + EventName.append(lenom) + + debug(00, "***************************") + debug(00, "**** Reading Parameters ...") + debug(10, "***************************") + subjects=[] # a name would be nice, but human will do + prefixes=[] # added on to mocap marker names, one for each subject + marker_subjects = [] # hopefully will be specified in the file and known to this program + markerList=[] + ParameterGroups = [] + ParameterNumberIndex = [] + + content = content_memory + content = content[512*(NrecordFirstParameterblock-1):] + + dat1, content = getNumber(content, 1) + key2, content = getNumber(content, 1) + + NparameterRecords, content = getNumber(content, 1) + debug(100, "NparameterRecords=%i"%NparameterRecords) + proctype,content =getNumber(content,1) + proctype = proctype-83 # proctype: 1(INTEL-PC); 2(DEC-VAX); 3(MIPS-SUN/SGI) + + for i in range(NparameterRecords): + leparam = ParameterGroup(None, None, []) + ParameterGroups.append(leparam) + ParameterNumberIndex.append(0) + # + Ncharacters, content = getNumber(content, 1) + if Ncharacters>=128: + Ncharacters = -(2**8)+(Ncharacters) + GroupNumber, content = getNumber(content, 1) + if GroupNumber>=128: + GroupNumber = -(2**8)+(GroupNumber) + debug(80,"GroupNumber = %i, Nchar=%i" %(GroupNumber,Ncharacters)) + + while Ncharacters > 0: + if GroupNumber<0: + GroupNumber=abs(GroupNumber) + GroupName = content[0:Ncharacters] + content = content[Ncharacters:] + #print "Group Number = ", GroupNumber + ParameterGroups[GroupNumber].name = GroupName + #print "ParameterGroupName =", GroupName + offset, content = getNumber(content, 2) + deschars, content = getNumber(content, 1) + GroupDescription = content[0:deschars] + content = content[deschars:] + ParameterGroups[GroupNumber].description = GroupDescription + # + ParameterNumberIndex[GroupNumber]=0 + content = content[offset-3-deschars:] + else: + + ParameterNumberIndex[GroupNumber]=ParameterNumberIndex[GroupNumber]+1 + ParameterNumber=ParameterNumberIndex[GroupNumber] + #print "ParameterNumber=", ParameterNumber + ParameterGroups[GroupNumber].parameter.append(Parameter(None, None, [], [], None)) + ParameterName = content[0:Ncharacters] + content = content[Ncharacters:] + #print "ParameterName = ",ParameterName + if len(ParameterName)>0: + ParameterGroups[GroupNumber].parameter[ParameterNumber-1].name=ParameterName + offset, content = getNumber(content, 2) + filepos = len(content_memory)-len(content) + nextrec = filepos+offset-2 + + type, content=getNumber(content, 1) + if type>=128: + type = -(2**8)+type + ParameterGroups[GroupNumber].parameter[ParameterNumber-1].type=type + + dimnum, content=getNumber(content, 1) + if dimnum == 0: + datalength = abs(type) + else: + mult=1 + dimension=[] + for j in range (dimnum): + ladim, content = getNumber(content, 1) + dimension.append(ladim) + mult=mult*dimension[j] + ParameterGroups[GroupNumber].parameter[ParameterNumber-1].dim.append(dimension[j]) + datalength = abs(type)*mult + + #print "ParameterNumber = ", ParameterNumber, " Group Number = ", GroupNumber + + if type==-1: + data = "" + wordlength=dimension[0] + if dimnum==2 and datalength>0: + for j in range(dimension[1]): + data=string.rstrip(content[0:wordlength]) + content = content[wordlength:] + ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data.append(data) + elif dimnum==1 and datalength>0: + data=content[0:wordlength] + ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data.append(data) # ??? + + myParam=string.rstrip(ParameterName) + myGroup=string.rstrip(GroupName) + msg= "-%s-%s-" % (myGroup,myParam) + if myGroup == "POINT": + if myParam== "LABELS": + # named in form of subject:marker. + # the list "empties" is a corresponding list of actual empty object names that make up the cloud + markerList= ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data + debug(0, "%sLABELS = %i %s" %(msg, len(markerList),markerList)) #list of logical markers from 0 to n corresponding to points + elif myParam== "LABELS2": #more labels + # named in form of subject:marker. + # the list "empties" is a corresponding list of actual empty object names that make up the cloud + momarkList= ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data + markerList+=momarkList + debug(0, "%sLABELS2 = %i %s" %(msg, len(momarkList),momarkList)) #list of logical markers from 0 to n corresponding to points + else: debug(70, "%s UNUSED = %s" %(msg,ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data)) + elif myGroup in ["SUBJECT", "SUBJECTS"]: #info about the actor + if myParam in ["NAME", "NAMES"]: + subjects= ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data + debug(0, "%sNames of Subjects = %s" %(msg, subjects)) # might be useful in naming armatures + for i in range(len(subjects)): + subjects[i]=subjects[i].rstrip() + if subjects[i]=="": subjects[i]="Human" + elif myParam == "LABEL_PREFIXES": + prefixes = ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data + debug(0, "%sMarker Prefixes = %s" %(msg, prefixes)) # to xlate marker name to that in file + for i in range(len(prefixes)): + prefixes[i]=prefixes[i].rstrip() + elif myParam== "MARKER_SETS": + marker_subjects= ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data + debug(0, "%sMarker Set = %s"%(msg, marker_subjects)) # marker set that each subject was wearing + elif myParam== "MODEL_PARAM": + action= ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data + debug(0, "%sModel Paramter = %s"%(msg,action)) # might be a good name for the blender scene + elif myParam== "LABELS": + # named in form of subject:marker. + # the list "empties" is a corresponding list of actual empty object names that make up the cloud + markerList= ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data + debug(0, "%sLABELS = %i %s"%(msg, len(markerList),markerList)) #list of logical markers from 0 to n corresponding to points + else: debug(70, "%sUNUSED = %s"%(msg, ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data)) + else: + debug(70, "%sUNUSED = %s"%(msg, ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data)) + elif type == 1: + debug(100,"Block type %i is largely unsupported and untested."%type) + data = [] + Nparameters=datalength/abs(type) + debug(100, "Nparameters=%i"%Nparameters) + for i in range(Nparameters): + ladata,content = getNumber(content, 1) + data.append(ladata) + ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data=data + #print ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data + + #print "type boolean" + elif type == 2 and datalength>0: + debug(100,"Block type %i is largely unsupported and untested."%type) + data = [] + Nparameters=datalength/abs(type) + debug(100, "Nparameters=%i"%Nparameters) + for i in range(Nparameters): + ladata,content = getNumber(content, 2) + data.append(ladata) + #ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data=data + if dimnum>1: + #???? print "arg je comprends pas" + ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data=data + #???ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data=reshape(data,dimension) + else: + ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data=data + #print ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data + #pass + #print "type integer" + elif type == 4 and datalength>0: + debug(100,"Block type %i is largely unsupported and untested."%type) + data = [] + Nparameters=datalength/abs(type) + debug(100, "Nparameters=%i"%Nparameters) + for i in range(Nparameters): + ladata,content = getFloat(content,proctype) + data.append(ladata) + if dimnum>1: + ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data=data + #print "arg je comprends pas" + #???ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data=reshape(data,dimension) + else: + ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data=data + #print ParameterGroups[GroupNumber].parameter[ParameterNumber-1].data + else: + debug(100,"Block type %i is largely unsupported and untested."%type) + #print "error" + pass + deschars, content= getNumber(content, 1) + if deschars>0: + description = content[0:deschars] + content = content[deschars:] + ParameterGroups[GroupNumber].parameter[ParameterNumber-1].description=description + + content = content_memory + content = content[nextrec:] + + Ncharacters,content = getNumber(content, 1) + if Ncharacters>=128: + Ncharacters = -(2**8)+(Ncharacters) + GroupNumber,content = getNumber(content, 1) + if GroupNumber>=128: + GroupNumber = -(2**8)+(GroupNumber) + debug(80,"GroupNumber = %i, Nchar=%i" %(GroupNumber,Ncharacters)) + + debug(00, "***************************") + debug(00, "**** Examining Parameters ...") + debug(10, "***************************") + + if len(subjects)==0: subjects=["Test"] #well, somebody got mocapped! + for i in range(0, len(subjects)-len(prefixes)): prefixes.append("") + for i in range(0, len(subjects)-len(marker_subjects)): marker_subjects.append(subjects[i]) + + #make a markerlist if they didn't + debug(0, "%i Markers specified, %i marker names supplied" %(Nmarkers,len(markerList))) + if len(markerList)==0: + debug(0, "File missing any POINT LABELS marker list. Making defaults") + #I guess just make cloud of empty.xxx + if len(markerList)<Nmarkers: + for i in range(len(markerList),Nmarkers): markerList.append("mark."+str(i)) + #note that they may supply more markers than Nmarkers, extras are usually null or ignored + #an idea here to winnow down the marker List is to go through the nodes and see if there are markers + # in the list that are not used in constraining the armature, and discard them or set them debug(0, + # so that later on in processing we don't bother saving their location, possibly speeding up processing + # because we can just skip over their data block. + # put this on TODO list since it gets pretty complicated going throuch each marker set and all constraints etc. + + ## ############################################### + ## ## ## + ## ## Initalize Arrays and Allocate Memory + ## ## ## + ## ############################################### + ## Get the coordinate and analog data + # + + content = content_memory + content = content[(NrecordDataBlock-1)*512:] + debug(20,"Allocating memory for %i floats" %NvideoFrames*(Nmarkers*3+2)) + for i in range (NvideoFrames): + Markers.append([]) + ResidualError.append([]) + CameraInfo.append([]) + for j in range (Nmarkers): + Markers[i].append(Marker(0.0,0.0,0.0)) + ResidualError[i].append(0) + CameraInfo[i].append(0) + + #print Markers + # + #if Scale < 0 + # for i=1:NvideoFrames + # for j=1:Nmarkers + # Markers(i,j,1:3)=fread(fid,3,'float32')'; + # a=fix(fread(fid,1,'float32')); + # highbyte=fix(a/256); + # lowbyte=a-highbyte*256; + # CameraInfo(i,j)=highbyte; + # ResidualError(i,j)=lowbyte*abs(Scale); + # end + # waitbar(i/NvideoFrames) + # for j=1:NanalogFramesPerVideoFrame, + # AnalogSignals(j+NanalogFramesPerVideoFrame*(i-1),1:NanalogChannels)=... + # fread(fid,NanalogChannels,'int16')'; + # end + # end + + debug(10, "***************************") + debug(00, "**** Reading DataBlock of %i Frames...." % NvideoFrames) + debug(10, "***************************") + residuals= NanalogFramesPerVideoFrame*NanalogChannels*2 + err=0 #keep track of errors or serious data issues + ptr_read = 0 + + if Scale < 0.0: # 3D Data - 4-byte Floating-point Format + for i in range (NvideoFrames): + if i==0: start=sys.time() + elif i==10: + tmp=(sys.time()-start)*NvideoFrames/600 + debug(0,"%i minutes remaining..." % tmp) + else: print "%i percent complete. On Frame %i Points procesed: %i\r" % (i*100/NvideoFrames,i,i*Nmarkers), + for j in range (Nmarkers): + + x,ptr_read = parseFloat(content, ptr_read, proctype) + y,ptr_read = parseFloat(content, ptr_read, proctype) + z,ptr_read = parseFloat(content, ptr_read, proctype) + myx= x * -Scale + myy= y * -Scale + myz= z * -Scale + + if abs(myx)>XYZ_LIMIT or abs(myy)>XYZ_LIMIT or abs(myz)>XYZ_LIMIT: + err+=1 + if err>100: + debug(0, "Warning: 100 data points for markers seem way out there") + debug(0, "data read: (%i, %i, %i)" %(x,y,z)) + debug(0, "Consider revising Scale %0.2f" % Scale) + debug(0, "which now givs coordinates: (%i, %i, %i)" %(x*Scale,y*Scale,z*Scale)) + err=-0 + if abs(myx)>XYZ_LIMIT: myx= XYZ_LIMIT*myx/abs(myx) #preserve sign + if abs(myy)>XYZ_LIMIT: myy= XYZ_LIMIT*myy/abs(myy) #preserve sign + if abs(myz)>XYZ_LIMIT: myz= XYZ_LIMIT*myz/abs(myz) #preserve sign + Markers[i][j].x = myx + Markers[i][j].y = myy + Markers[i][j].z = myz + + a,ptr_read = parseFloat(content, ptr_read, proctype) + a = int(a) + highbyte = int(a/256) + lowbyte=a-highbyte*256 + CameraInfo[i][j] = highbyte + ResidualError[i][j] = lowbyte*abs(Scale) + #Monitor marker location to ensure data block is being parsed properly + if j==0: debug(90,"Frame %i loc of %s: (%i, %i, %i)" % (i,markerList[j],myx,myy,myz)) + if i==0: debug(50, "Initial loc of %s: (%i, %i, %i)" % (markerList[j],myx,myy,myz)) + + ptr_read+=residuals #skip over the following + #for j in range (NanalogFramesPerVideoFrame): + # for k in range(NanalogChannels): + # val, content = getNumber(content, 2) + # AnalogSignals[j+NanalogFramesPerVideoFrame*(i)][k]=val #??? i-1 + #else + # for i=1:NvideoFrames + # for j=1:Nmarkers + # Markers(i,j,1:3)=fread(fid,3,'int16')'.*Scale; + # ResidualError(i,j)=fread(fid,1,'int8'); + # CameraInfo(i,j)=fread(fid,1,'int8'); + # end + # waitbar(i/NvideoFrames) + # for j=1:NanalogFramesPerVideoFrame, + # AnalogSignals(j+NanalogFramesPerVideoFrame*(i-1),1:NanalogChannels)=... + # fread(fid,NanalogChannels,'int16')'; + # end + # end + #end + + else: #Scale is positive, but should be <1 to scale down, like 0.05 + two16= -2**16 + if len(content) < NvideoFrames*(Nmarkers*(6+2)+residuals): + error("%i bytes is not enough data for |%i frames|%i markers|%i residual" %(len(content),NvideoFrames,Nmarkers,residuals)) + #Note: I really tried to optimize this loop, since it was taking hours to process + for i in range(NvideoFrames): + if i==0: start=sys.time() + elif i==10: + tmp=(sys.time()-start)*NvideoFrames/600 + debug(0,"%i minutes remaining..." % tmp) + else: print "%i percent complete. On Frame %i Points procesed: %i\r" % (i*100/NvideoFrames,i,i*Nmarkers), + + for j in range(Nmarkers): + #x, content = getNumber(content,2) + # this is old skool signed int, not but not a short. + x = ord(content[ptr_read+0]) + (ord(content[ptr_read+1])<<8) + if x>32768: x+=two16 + y = ord(content[ptr_read+2]) + (ord(content[ptr_read+3])<<8) + if y>32768: y+=two16 + z = ord(content[ptr_read+4]) + (ord(content[ptr_read+5])<<8) + if z>32768: z+=two16 + +## +## x = ord(content[ptr_read]) + ord(content[ptr_read+1])*(2**8) +## ptr_read+=2 +## if x > 32768: +## x=-(2**16)+(x) +## #y, content = getNumber(content,2) +## y = ord(content[ptr_read]) + ord(content[ptr_read+1])*(2**8) +## ptr_read+=2 +## if y > 32768: +## y=-(2**16)+(y) +## #z, content = getNumber(content,2) +## z = ord(content[ptr_read]) + ord(content[ptr_read+1])*(2**8) +## ptr_read+=2 +## if z > 32768: +## z=-(2**16)+(z) +## +## print "(%i=%i, %i=%i, %i=%i)" %(x,myx,y,myy,z,myz) + + # for integers, I changed Scale above to avoid getting impossible numbers + Markers[i][j].x = x*Scale + Markers[i][j].y = y*Scale + Markers[i][j].z = z*Scale + +## ResidualError[i][j], content = getNumber(content, 1) +## CameraInfo[i][j], content = getNumber(content, 1) + #try to improve performance by: + ResidualError[i][j]= ord(content[ptr_read+6]) + CameraInfo[i][j]= ord(content[ptr_read+7]) + + content= content[ptr_read+8:] + ptr_read=0 + + if j==0: debug(100,"Frame %i loc of %s: %s" % (i,markerList[j],Markers[i][j])) + if i==0: debug(50, "Initial loc of %s: (%s)" % (markerList[j],Markers[i][j])) + + #for j in range (NanalogFramesPerVideoFrame): + # for k in range(NanalogChannels): + # val, content = getNumber(content, 2) + #AnalogSignals(j+NanalogFramesPerVideoFrame*(i-1),1:NanalogChannels)=val + ptr_read= residuals # skip over the above + print "\ndone with file." + fid.close() + + cloud= makeCloud(Nmarkers,markerList,StartFrame,EndFrame,Markers) + + setupAnim(StartFrame, EndFrame,VideoFrameRate) + + debug(10, "**************************") + debug(00, "**** Making %i Armatures" % len(subjects)) + debug(10, "**************************") + for i in range(len(subjects)): + marker_set= marker_subjects[i] + success=False + if len(marker_set)>0: + for trymark in MARKER_SETS: + if trymark[0:len(marker_set)]==marker_set: + marker_set=trymark + success=True + if success: + debug(0, "Armature for %s will be put on layers %s" % (subjects[i],LAYERS_ARMOB)) + debug(0, " based on an markers beginning with %s" % prefixes[i]) + ob= make_arm(subjects[i],prefixes[i],markerList,cloud,marker_set) + else: + debug(00, "Presently, this program can automatically create a constrained armature for marker sets %s" % MARKER_SETS) + debug(00, "%s uses an unknown marker set %s" % (subjects[i],marker_set)) + debug(10, "Have a nice day! If you figure out an armature node system for this cloud, please add it to the program.") + + debug(10, "**************************") + debug(00, "**** Conclusion") + minmax=[0,0,0,0,0,0] + for i in range(NvideoFrames): + for j in range(Nmarkers): + if minmax[0]>Markers[i][j].x: minmax[0]=Markers[i][j].x + if minmax[1]>Markers[i][j].y: minmax[1]=Markers[i][j].y + if minmax[2]>Markers[i][j].z: minmax[2]=Markers[i][j].z + if minmax[3]<Markers[i][j].x: minmax[3]=Markers[i][j].x + if minmax[4]<Markers[i][j].y: minmax[4]=Markers[i][j].y + if minmax[5]<Markers[i][j].z: minmax[5]=Markers[i][j].z + debug(0,"Markers move in 3D space from (%i,%i,%i) to (%i,%i,%i). "%(minmax[0],minmax[1],minmax[2],minmax[3],minmax[4],minmax[5])) + debug(0,"Set your 3D View Properties Clip End and zoom out your display.") +def my_callback(filename): + # processing options UI goes here, eventually + Window.WaitCursor(1) + t = sys.time() + load_c3d(filename) + # Timing the script is a good way to be aware on any speed hits when scripting + debug(0, '%s file processed in %.2f sec.' % (filename,sys.time()-t)) + Window.WaitCursor(0) + +def processFile(): + # select file and pass a handle to the processor + Blender.Window.FileSelector(my_callback, "Import C3D") # makes a window a file selector and processes it + #processing contiues while file is being worked + +def main(): + # Display the GUI + + # Run the function + processFile() + + #Close files, display stats, cleanup, advice on next steps + +# This lets you import the script without running it +if __name__ == '__main__': + debug(00, "------------------------------------") + debug(00, '%s %s script began at %.0f' % (__script__,__version__,sys.time())) + main() + + + |