OSDN Git Service

fix IK.
[meshio/meshio.git] / swig / blender24 / vmd_import.py
1 #!BPY
2 # coding: utf-8
3 """ 
4 Name: 'MikuMikuDance motion and shape (.vmd)...'
5 Blender: 248
6 Group: 'Import'
7 Tooltip: 'Import motion from MikuMikuDance motion file (.vmd)'
8 """
9 __author__= 'ousttrue'
10 __url__ = ["http://gunload.web.fc2.com/blender/"]
11 __version__= '0.6 2010/05/06'
12 __bpydoc__= '''\
13 VMD Importer
14
15 This script imports a vmd file into Blender.
16
17 0.1 2009/11/23
18 0.2 2009/12/09 implement shape key
19 0.3 2010/03/05 use english name
20 0.4 2010/04/05 fix slerp
21 0.5 2010/04/16 add progress
22 0.6 2010/05/06 C extension.
23 0.7 2010/05/16 modify C extension interface.
24 '''
25 import Blender
26 import os
27 import sys
28 import math
29
30 # extension
31 from meshio import vmd, englishmap
32
33
34 FS_ENCODING=sys.getfilesystemencoding()
35 if os.path.exists(os.path.dirname(sys.argv[0])+"/utf8"):
36     INTERNAL_ENCODING='utf-8'
37 else:
38     INTERNAL_ENCODING=FS_ENCODING
39
40
41 class ProgressBar(object):
42     def __init__(self, base):
43         print "#### %s ####" % base
44         self.base=base
45         self.start=Blender.sys.time() 
46         self.set('<start>', 0)
47
48     def advance(self, message, progress):
49         self.progress+=float(progress)
50         self._print(message)
51
52     def set(self, message, progress):
53         self.progress=float(progress)
54         self._print(message)
55
56     def _print(self, message):
57         print message
58         message="%s: %s" % (self.base, message)
59         if message.__class__ is unicode:
60             message=message.encode(INTERNAL_ENCODING)
61         try:
62             # ?
63             Blender.Window.DrawProgressBar(self.progress, message)
64         except AttributeError, error:
65             #print error
66             #print type(self.progress), self.progress, type(message), message
67             pass
68
69     def finish(self):
70         self.progress=1.0
71         message='finished in %.2f sec' % (Blender.sys.time()-self.start)
72         self.set(message, 1.0)
73
74 def progress_start(base):
75     global progressBar
76     progressBar=ProgressBar(base)
77
78 def progress_finish():
79     global progressBar
80     progressBar.finish()
81
82 def progress_print(message, progress=0.01):
83     global progressBar
84     progressBar.advance(message, progress)
85
86 def progress_set(message, progress):
87     global progressBar
88     progressBar.set(message, progress)
89
90
91 EPSILON=1e-5
92 THRESHOLD=-0.85
93
94
95 def ToDegree(x):
96     return x/math.pi * 180.0
97
98
99 def clampDegree(d):
100     return d % 360
101
102
103 def multQuat(l, r):
104     q=Blender.Mathutils.Quaternion(l.w*r.w-(l.x*r.x+l.y*r.y+l.z*r.z), 0, 0, 0)
105     q.x=l.w*r.x+r.w*l.x+l.y*r.z-l.z*r.y
106     q.y=l.w*r.y+r.w*l.y+l.z*r.x-l.x*r.z
107     q.z=l.w*r.z+r.w*l.z+l.x*r.y-l.y*r.x
108     return q
109
110
111 def import_motion_key(l, o, progressCount):
112     print 'import_motion_key: %s' % o.name
113     act = o.getAction()
114     if not act: # Add a pose action if we dont have one
115         act = Armature.NLA.NewAction()
116         act.setActive(o)
117     
118     armature = o.data
119     pose = o.getPose()
120     not_in_map={}
121     not_found={}
122     counter=0
123     last_frame=0
124     for n in l.boneKeys:
125         keyFrames=l.getBoneKeyFrameList(n)
126         boneName=englishmap.getEnglishBoneName(n).encode(INTERNAL_ENCODING)
127         try:
128             poseBone=pose.bones[boneName]
129             bone=armature.bones[boneName]
130             # rot
131             armRotate=bone.matrix['ARMATURESPACE'].rotationPart()
132             # quat
133             armRotateQuaternion=armRotate.toQuat()
134
135             # inv
136             armRotateInv=Blender.Mathutils.Matrix(armRotate).transpose()
137             # quat
138             armRotateInvQuaternion=armRotateInv.toQuat()
139
140             reverseFlag=False
141             lastQ=None
142
143             for i in xrange(len(keyFrames.list)):
144                 key=keyFrames.getKey(i)
145                 ####################
146                 # rotation
147                 ####################
148                 if lastQ and lastQ.dot(key.q)<0:
149                     reverseFlag=not reverseFlag
150                 lastQ=key.q
151
152                 # convert left-handed y-up to right-handed z-up
153                 if reverseFlag:
154                     # reverse quaternion for slerp
155                     q=Blender.Mathutils.Quaternion(-key.q.w, 0, 0, 0)
156                     q.x=key.q.x
157                     q.y=key.q.z
158                     q.z=key.q.y
159                 else:
160                     q=Blender.Mathutils.Quaternion(key.q.w, 0, 0, 0)
161                     q.x=-key.q.x
162                     q.y=-key.q.z
163                     q.z=-key.q.y
164
165                 poseBone.quat=(
166                         multQuat(armRotateInvQuaternion, 
167                             multQuat(q, armRotateQuaternion)))
168
169                 ####################
170                 # location
171                 ####################
172                 poseBone.loc = Blender.Mathutils.Vector(
173                         float(key.pos.x), float(key.pos.z), float(key.pos.y))
174
175                 # insert
176                 poseBone.insertKey(o, keyFrames.getFrame(i), 
177                         [Blender.Object.Pose.LOC, Blender.Object.Pose.ROT],
178                         1)
179                 last_frame=max(last_frame, keyFrames.getFrame(i))
180
181                 counter+=1
182                 if counter % progressCount==0:
183                     progress_print("")
184
185         except KeyError, msg:
186             not_found[boneName]=True
187             continue
188             
189     print "bone not exists"
190     for name in not_found.keys():
191         print name
192
193     return last_frame
194
195
196 def IPO_CURVE_get_or_create(ipo, name):
197     for c in ipo:
198         if c.name == name:
199             return c
200     return ipo.addCurve(name)
201
202
203 def import_shape_key(l, mesh, progressCount):
204     print 'import_shape_key: %s' % mesh.name
205     key = mesh.getData().key
206     if key is None:
207         Blender.Draw.PupMenu('selecting mesh not has a Key')
208         return
209     # get or create IPO  
210     ipo = key.getIpo()
211     if ipo == None:
212         ipo = Blender.Ipo.New("Key", "ShapeKey")
213         key.ipo = ipo
214
215     # insert shape keys
216     counter=0
217     last_frame=0
218     for n in l.morphKeys:
219         keyFrames=l.getMorphKeyFrameList(n)
220         if n=='base':
221             continue
222         name=englishmap.getEnglishSkinName(n).encode(INTERNAL_ENCODING)
223         try:
224             curve=IPO_CURVE_get_or_create(ipo, name)
225         except NameError, msg:
226             print NameError, msg
227             print n, name
228             continue
229         curve.interpolation = Blender.IpoCurve.InterpTypes.LINEAR
230         for i in xrange(len(keyFrames.list)):
231             key=keyFrames.getKey(i)
232             frame=keyFrames.getFrame(i)
233             curve[frame]=key.weight
234             last_frame=max(last_frame, frame)
235
236             counter+=1
237             if counter % progressCount==0:
238                 progress_print("")
239
240     return last_frame
241
242
243 def run(filename):
244     filename=filename.decode(INTERNAL_ENCODING)
245
246     # progress
247     progress_start('vmd_import')
248     print(INTERNAL_ENCODING, FS_ENCODING)
249
250     # load vmd
251     progress_set('load %s' % filename, 0.0)
252     l=vmd.IO()
253     if not l.read(filename.encode(FS_ENCODING)):
254         print "failt to load", filename
255         return
256     progress_set('loaded %s' % filename, 1.0)
257
258     scene=Blender.Scene.GetCurrent()
259
260     # for progress
261     armtureCount=0
262     shapeCount=0
263     for o in scene.objects.selected:
264         if o.type=='Armature':
265             armtureCount+=1
266         elif o.type=='Mesh':
267             shapeCount+=1
268     #keyCount=armtureCount*l.boneMap.Size()+shapeCount*l.morphMap.size()
269     #progressCount=int(keyCount/100)
270     progressCount=1000
271
272     # import
273     last_frame=0
274     for o in scene.objects.selected:
275         if o.type=='Armature':
276             last_frame=max(last_frame, import_motion_key(l, o, progressCount))
277         elif o.type=='Mesh':
278             last_frame=max(last_frame, import_shape_key(l, o, progressCount))
279
280     # set end frame
281     scene.getRenderingContext().eFrame = last_frame
282     print last_frame
283
284     progress_finish()
285
286
287 if __name__=="__main__":
288     if 0<len([o for o in Blender.Scene.GetCurrent().objects.selected if 
289         o.type=='Armature' or o.type=='Mesh']):
290         Blender.Window.FileSelector(
291                 run, 
292                 'Import VMD motion', 
293                 Blender.sys.makename(ext='.vmd'))
294     else:
295         Blender.Draw.PupMenu('select target armature and mesh objects.')
296