[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [15319] trunk/blender/release/scripts/ c3d_import.py: [#14392] C3D Import

Campbell Barton ideasman42 at gmail.com
Sun Jun 22 23:48:02 CEST 2008


Revision: 15319
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=15319
Author:   campbellbarton
Date:     2008-06-22 23:48:02 +0200 (Sun, 22 Jun 2008)

Log Message:
-----------
[#14392] C3D Import
c3d importer for motion capture data
This could do with some improvements but for now its acceptable.
- Note, could people please not mix tabs and spaces.


-Text copied from the patch submission-
The c3d_import with 2.46 was able to import a mocap cloud for some c3d files. I have improved it:
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

see also http://wiki.blender.org/index.php/Tutorials%5CMoCap-Section_3 for how this program gets the mocap data into
Blender and creates an armature, like the BVH script does.

I'd like someone to test and verify, and if accepted, replace the current c3d_import.py

--- See patch url for example files http://projects.blender.org/tracker/index.php?func=detail&aid=14392&group_id=9&atid=127

Added Paths:
-----------
    trunk/blender/release/scripts/c3d_import.py

Added: trunk/blender/release/scripts/c3d_import.py
===================================================================
--- trunk/blender/release/scripts/c3d_import.py	                        (rev 0)
+++ trunk/blender/release/scripts/c3d_import.py	2008-06-22 21:48:02 UTC (rev 15319)
@@ -0,0 +1,1237 @@
+#!BPY
+
+"""
+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 at yahoo.com)"
+__version__ = "0.8"
+__url__ = ["Communicate problems and errors, BlenderArtists.org, Python forum"]
+__email__= ["rogerwickes at 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
+"""
+
+#----------------------------------------------
+# (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]
+CLEAN=True # Should program ignore markers at (0,0,0) and beyond the outer limits?
+
+scn = Blender.Scene.GetCurrent()
+# Why on earth would you rename a scene when importing data??? - Campbell
+# scn.name="MoCap" #may want this enterable or derived based on motion being analyzed
+#TODO: ultimately, a library of motions to append from means you need good naming of things
+
+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)
+		myobj.layers= LAYERS_MARKER
+		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)])
+	

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list