OSDN Git Service

separate vertex with uv or normal.
[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         try:
127             boneName=englishmap.getEnglishBoneName(n).encode(INTERNAL_ENCODING)
128         except:
129             print(n)
130             assert(False)
131         try:
132             poseBone=pose.bones[boneName]
133             bone=armature.bones[boneName]
134             # rot
135             armRotate=bone.matrix['ARMATURESPACE'].rotationPart()
136             # quat
137             armRotateQuaternion=armRotate.toQuat()
138
139             # inv
140             armRotateInv=Blender.Mathutils.Matrix(armRotate).transpose()
141             # quat
142             armRotateInvQuaternion=armRotateInv.toQuat()
143
144             reverseFlag=False
145             lastQ=None
146
147             for i in xrange(len(keyFrames.list)):
148                 key=keyFrames.getKey(i)
149                 ####################
150                 # rotation
151                 ####################
152                 if lastQ and lastQ.dot(key.q)<0:
153                     reverseFlag=not reverseFlag
154                 lastQ=key.q
155
156                 # convert left-handed y-up to right-handed z-up
157                 if reverseFlag:
158                     # reverse quaternion for slerp
159                     q=Blender.Mathutils.Quaternion(-key.q.w, 0, 0, 0)
160                     q.x=key.q.x
161                     q.y=key.q.z
162                     q.z=key.q.y
163                 else:
164                     q=Blender.Mathutils.Quaternion(key.q.w, 0, 0, 0)
165                     q.x=-key.q.x
166                     q.y=-key.q.z
167                     q.z=-key.q.y
168
169                 poseBone.quat=(
170                         multQuat(armRotateInvQuaternion, 
171                             multQuat(q, armRotateQuaternion)))
172
173                 ####################
174                 # location
175                 ####################
176                 poseBone.loc = Blender.Mathutils.Vector(
177                         float(key.pos.x), float(key.pos.z), float(key.pos.y))
178
179                 # insert
180                 poseBone.insertKey(o, keyFrames.getFrame(i), 
181                         [Blender.Object.Pose.LOC, Blender.Object.Pose.ROT],
182                         1)
183                 last_frame=max(last_frame, keyFrames.getFrame(i))
184
185                 counter+=1
186                 if counter % progressCount==0:
187                     progress_print("")
188
189         except KeyError, msg:
190             not_found[boneName]=True
191             continue
192             
193     print "bone not exists"
194     for name in not_found.keys():
195         print name
196
197     return last_frame
198
199
200 def IPO_CURVE_get_or_create(ipo, name):
201     for c in ipo:
202         if c.name == name:
203             return c
204     return ipo.addCurve(name)
205
206
207 def import_shape_key(l, mesh, progressCount):
208     print 'import_shape_key: %s' % mesh.name
209     key = mesh.getData().key
210     if key is None:
211         Blender.Draw.PupMenu('selecting mesh not has a Key')
212         return
213     # get or create IPO  
214     ipo = key.getIpo()
215     if ipo == None:
216         ipo = Blender.Ipo.New("Key", "ShapeKey")
217         key.ipo = ipo
218
219     # insert shape keys
220     counter=0
221     last_frame=0
222     for n in l.morphKeys:
223         keyFrames=l.getMorphKeyFrameList(n)
224         if n=='base':
225             continue
226         name=englishmap.getEnglishSkinName(n).encode(INTERNAL_ENCODING)
227         try:
228             curve=IPO_CURVE_get_or_create(ipo, name)
229         except NameError, msg:
230             print NameError, msg
231             print n, name
232             continue
233         curve.interpolation = Blender.IpoCurve.InterpTypes.LINEAR
234         for i in xrange(len(keyFrames.list)):
235             key=keyFrames.getKey(i)
236             frame=keyFrames.getFrame(i)
237             curve[frame]=key.weight
238             last_frame=max(last_frame, frame)
239
240             counter+=1
241             if counter % progressCount==0:
242                 progress_print("")
243
244     return last_frame
245
246
247 def run(filename):
248     filename=filename.decode(INTERNAL_ENCODING)
249
250     # progress
251     progress_start('vmd_import')
252     print(INTERNAL_ENCODING, FS_ENCODING)
253
254     # load vmd
255     progress_set('load %s' % filename, 0.0)
256     l=vmd.IO()
257     if not l.read(filename.encode(FS_ENCODING)):
258         print "failt to load", filename
259         return
260     progress_set('loaded %s' % filename, 1.0)
261
262     scene=Blender.Scene.GetCurrent()
263
264     # for progress
265     armtureCount=0
266     shapeCount=0
267     for o in scene.objects.selected:
268         if o.type=='Armature':
269             armtureCount+=1
270         elif o.type=='Mesh':
271             shapeCount+=1
272     #keyCount=armtureCount*l.boneMap.Size()+shapeCount*l.morphMap.size()
273     #progressCount=int(keyCount/100)
274     progressCount=1000
275
276     # import
277     last_frame=0
278     for o in scene.objects.selected:
279         if o.type=='Armature':
280             last_frame=max(last_frame, import_motion_key(l, o, progressCount))
281         elif o.type=='Mesh':
282             last_frame=max(last_frame, import_shape_key(l, o, progressCount))
283
284     # set end frame
285     scene.getRenderingContext().eFrame = last_frame
286     print last_frame
287
288     progress_finish()
289
290
291 if __name__=="__main__":
292     if 0<len([o for o in Blender.Scene.GetCurrent().objects.selected if 
293         o.type=='Armature' or o.type=='Mesh']):
294         Blender.Window.FileSelector(
295                 run, 
296                 'Import VMD motion', 
297                 Blender.sys.makename(ext='.vmd'))
298     else:
299         Blender.Draw.PupMenu('select target armature and mesh objects.')
300