OSDN Git Service

add import_anim_vmd.py.
[meshio/meshio.git] / swig / blender25 / import_anim_vmd.py
1 # coding: utf-8
2
3 __author__= ['ousttrue']
4 __url__ = ("")
5 __version__= '20100515 0.1:'
6 __bpydoc__= '''\
7 vmd Importer
8
9 This script imports a vmd into Blender for editing.
10 '''
11
12 import bpy
13 from bpy.props import *
14 import mathutils
15 import sys
16 import os
17 import math
18 from meshio import vmd, englishmap
19
20
21 EPSILON=1e-5
22 THRESHOLD=-0.85
23
24
25 def ToDegree(x):
26     return x/math.pi * 180.0
27
28
29 def clampDegree(d):
30     return d % 360
31
32
33 def multQuat(l, r):
34     q=mathutils.Quaternion((0, 0, 0), l.w*r.w-(l.x*r.x+l.y*r.y+l.z*r.z))
35     q.x=l.w*r.x+r.w*l.x+l.y*r.z-l.z*r.y
36     q.y=l.w*r.y+r.w*l.y+l.z*r.x-l.x*r.z
37     q.z=l.w*r.z+r.w*l.z+l.x*r.y-l.y*r.x
38     return q
39
40
41 def import_motion_key(l, o):
42     print('import_motion_key: %s' % o.name)
43     
44     armature = o.data
45     pose = o.pose
46     not_in_map={}
47     not_found={}
48     counter=0
49     last_frame=0
50     for n in l.boneKeys:
51         keyFrames=l.getBoneKeyFrameList(n)
52         boneName=englishmap.getEnglishBoneName(n)
53         try:
54             poseBone=pose.bones[boneName]
55             bone=armature.bones[boneName]
56             # rot
57             armRotate=bone.matrix_local.rotation_part()
58             # quat
59             armRotateQuaternion=armRotate.to_quat()
60             if armRotateQuaternion.w<0:
61                 armRotateQuaternion.w=-armRotateQuaternion.w
62                 armRotateQuaternion.x=-armRotateQuaternion.x
63                 armRotateQuaternion.y=-armRotateQuaternion.y
64                 armRotateQuaternion.z=-armRotateQuaternion.z
65
66             # inv
67             armRotateInv=mathutils.Matrix(armRotate).transpose()
68             # quat
69             armRotateInvQuaternion=armRotateInv.to_quat()
70             if armRotateInvQuaternion.w<0:
71                 armRotateInvQuaternion.w=-armRotateInvQuaternion.w
72                 armRotateInvQuaternion.x=-armRotateInvQuaternion.x
73                 armRotateInvQuaternion.y=-armRotateInvQuaternion.y
74                 armRotateInvQuaternion.z=-armRotateInvQuaternion.z
75
76             reverseFlag=False
77             lastQ=None
78
79             for i in range(len(keyFrames.list)):
80                 key=keyFrames.getKey(i)
81                 ####################
82                 # rotation
83                 ####################
84                 if lastQ and lastQ.dot(key.q)<0:
85                     reverseFlag=not reverseFlag
86                 lastQ=key.q
87
88                 # convert left-handed y-up to right-handed z-up
89                 if reverseFlag:
90                     # reverse quaternion for slerp
91                     q=mathutils.Quaternion((0, 0, 0), -key.q.w)
92                     q.x=key.q.x
93                     q.y=key.q.z
94                     q.z=key.q.y
95                 else:
96                     q=mathutils.Quaternion((0, 0, 0), key.q.w)
97                     q.x=-key.q.x
98                     q.y=-key.q.z
99                     q.z=-key.q.y
100
101                 poseBone.rotation_quaternion=multQuat(
102                         armRotateInvQuaternion, 
103                         multQuat(q, armRotateQuaternion))
104
105                 ####################
106                 # location
107                 ####################
108                 poseBone.location = mathutils.Vector(
109                         (float(key.pos.x), float(key.pos.z), float(key.pos.y)))
110
111                 # insert
112                 poseBone.keyframe_insert('rotation_quaternion', -1, keyFrames.getFrame(i))
113                 poseBone.keyframe_insert('location', -1, keyFrames.getFrame(i))
114                 last_frame=max(last_frame, keyFrames.getFrame(i))
115
116                 counter+=1
117
118         except KeyError as msg:
119             not_found[boneName]=True
120             continue
121             
122     print("bone not exists")
123     for name in not_found.keys():
124         print(name)
125
126     return last_frame
127
128
129 def IPO_CURVE_get_or_create(ipo, name):
130     for c in ipo:
131         if c.name == name:
132             return c
133     return ipo.addCurve(name)
134
135
136 def import_shape_key(l, mesh):
137     print('import_shape_key: %s' % mesh.name)
138     return 0
139     # ToDo
140     key = mesh.getData().key
141     if key is None:
142         Draw.PupMenu('selecting mesh not has a Key')
143         return
144     # get or create IPO  
145     ipo = key.getIpo()
146     if ipo == None:
147         ipo = Blender.Ipo.New("Key", "ShapeKey")
148         key.ipo = ipo
149
150     # insert shape keys
151     counter=0
152     last_frame=0
153     for n in l.morphKeys:
154         keyFrames=l.getMorphKeyFrameList(n)
155         if n=='base':
156             continue
157         name=englishmap.getEnglishSkinName(n)
158         try:
159             curve=IPO_CURVE_get_or_create(ipo, name)
160         except NameError as msg:
161             print(NameError, msg)
162             print(n, name)
163             continue
164         curve.interpolation = Blender.IpoCurve.InterpTypes.LINEAR
165         for i in xrange(len(keyFrames.list)):
166             key=keyFrames.getKey(i)
167             frame=keyFrames.getFrame(i)
168             curve[frame]=key.weight
169             last_frame=max(last_frame, frame)
170
171             counter+=1
172
173     return last_frame
174
175
176 def load(filename, context):
177     """
178     load vmd file to context.
179     """
180     io=vmd.IO()
181     if not io.read(filename):
182         print("fail to read", filename)
183         return
184
185     scene=context.scene
186
187     # import
188     last_frame=0
189     for o in scene.objects:
190         if o.selected:
191             if o.data.__class__ is bpy.types.Armature:
192                 last_frame=max(
193                         last_frame, import_motion_key(io, o))
194             elif o.data.__class__ is bpy.types.Mesh:
195                 last_frame=max(
196                         last_frame, import_shape_key(io, o))
197
198     # set end frame
199     scene.frame_end = last_frame
200     print("last frame: %d" % last_frame)
201
202     # redraw
203     scene.update()
204
205     print("finised")
206
207
208 ###############################################################################
209 # import operator
210 ###############################################################################
211 class IMPORT_OT_vmd(bpy.types.Operator):
212     bl_idname = "import_anim.vmd"
213     bl_label = 'Import VMD'
214
215     # List of operator properties, the attributes will be assigned
216     # to the class instance from the operator settings before calling.
217     path = StringProperty(
218             name="File Path", 
219             description="File path used for importing the VMD file", 
220             maxlen= 1024, default= "")
221     filename = StringProperty(
222             name="File Name", 
223             description="Name of the file.")
224     directory = StringProperty(
225             name="Directory", 
226             description="Directory of the file.")
227
228     def execute(self, context):
229         load(self.properties.path, context)
230         return {'FINISHED'}
231
232     def invoke(self, context, event):
233         wm = context.manager
234         wm.add_fileselect(self)
235         return {'RUNNING_MODAL'}
236
237
238 ###############################################################################
239 # register menu
240 ###############################################################################
241 def menu_func(self, context):
242     self.layout.operator(IMPORT_OT_vmd.bl_idname, 
243             text="MikuMikuDance motion (.vmd)")
244
245 def register():
246     bpy.types.register(IMPORT_OT_vmd)
247     bpy.types.INFO_MT_file_import.append(menu_func)
248
249 def unregister():
250     bpy.types.unregister(IMPORT_OT_vmd)
251     bpy.types.INFO_MT_file_import.remove(menu_func)
252
253
254 if __name__=="__main__":
255     register()
256