OSDN Git Service

implementing export_pmx...
[meshio/pymeshio.git] / blender26-meshio / exporter / bonebuilder.py
1 # coding: utf-8
2 from .. import bl
3 from ..pymeshio import englishmap
4
5
6 class IKSolver(object):
7     __slots__=['target', 'effector', 'length', 'iterations', 'weight']
8     def __init__(self, target, effector, length, iterations, weight):
9         self.target=target
10         self.effector=effector
11         self.length=length
12         self.iterations=iterations
13         self.weight=weight
14
15
16 class Bone(object):
17     __slots__=['index', 'name', 'ik_index',
18             'pos', 'tail', 'parent_index', 'tail_index', 'type', 'isConnect']
19     def __init__(self, name, pos, tail, isConnect):
20         self.index=-1
21         self.name=name
22         self.pos=pos
23         self.tail=tail
24         self.parent_index=None
25         self.tail_index=None
26         self.type=0
27         self.isConnect=isConnect
28         self.ik_index=0
29
30     def __eq__(self, rhs):
31         return self.index==rhs.index
32
33     def __str__(self):
34         return "<Bone %s %d>" % (self.name, self.type)
35
36
37 class BoneBuilder(object):
38     __slots__=['bones', 'boneMap', 'ik_list', 'bone_groups',]
39     def __init__(self):
40         self.bones=[]
41         self.boneMap={}
42         self.ik_list=[]
43         self.bone_groups=[]
44
45     def getBoneGroup(self, bone):
46         for i, g in enumerate(self.bone_groups):
47             for b in g[1]:
48                 if b==bone.name:
49                     return i+1
50         print('no gorup', bone)
51         return 0
52
53     def build(self, armatureObj):
54         if not armatureObj:
55             return
56
57         bl.message("build skeleton")
58         armature=bl.object.getData(armatureObj)
59
60         ####################
61         # bone group
62         ####################
63         for g in bl.object.boneGroups(armatureObj):
64             self.bone_groups.append((g.name, []))
65
66         ####################
67         # get bones
68         ####################
69         for b in armature.bones.values():
70             if not b.parent:
71                 # root bone
72                 bone=Bone(b.name, 
73                         bl.bone.getHeadLocal(b),
74                         bl.bone.getTailLocal(b),
75                         False)
76                 self.__addBone(bone)
77                 self.__getBone(bone, b)
78
79         for b in armature.bones.values():
80             if not b.parent:
81                 self.__checkConnection(b, None)
82
83         ####################
84         # get IK
85         ####################
86         pose = bl.object.getPose(armatureObj)
87         for b in pose.bones.values():
88             ####################
89             # assing bone group
90             ####################
91             self.__assignBoneGroup(b, b.bone_group)
92             for c in b.constraints:
93                 if bl.constraint.isIKSolver(c):
94                     ####################
95                     # IK target
96                     ####################
97                     target=self.__boneByName(bl.constraint.ikTarget(c))
98                     target.type=2
99
100                     ####################
101                     # IK effector
102                     ####################
103                     # IK 接続先
104                     link=self.__boneByName(b.name)
105                     link.type=6
106
107                     # IK chain
108                     e=b.parent
109                     chainLength=bl.constraint.ikChainLen(c)
110                     for i in range(chainLength):
111                         # IK影響下
112                         chainBone=self.__boneByName(e.name)
113                         chainBone.type=4
114                         chainBone.ik_index=target.index
115                         e=e.parent
116                     self.ik_list.append(
117                             IKSolver(target, link, chainLength, 
118                                 int(bl.constraint.ikItration(c) * 0.1), 
119                                 bl.constraint.ikRotationWeight(c)
120                                 ))
121
122         ####################
123
124         # boneのsort
125         self._sortBy()
126         self._fix()
127         # IKのsort
128         def getIndex(ik):
129             for i, v in enumerate(englishmap.boneMap):
130                 if v[0]==ik.target.name:
131                     return i
132             return len(englishmap.boneMap)
133         self.ik_list.sort(key=getIndex)
134
135     def __assignBoneGroup(self, poseBone, boneGroup):
136         if boneGroup:
137             for g in self.bone_groups:
138                 if g[0]==boneGroup.name:
139                     g[1].append(poseBone.name)
140
141     def __checkConnection(self, b, p):
142         if bl.bone.isConnected(b):
143             parent=self.__boneByName(p.name)
144             parent.isConnect=True
145
146         for c in b.children:
147             self.__checkConnection(c, b)
148
149     def _sortBy(self):
150         """
151         boneMap順に並べ替える
152         """
153         boneMap=englishmap.boneMap
154         original=self.bones[:]
155         def getIndex(bone):
156             for i, k_v in enumerate(boneMap):
157                 if k_v[0]==bone.name:
158                     return i
159             print(bone)
160             return len(boneMap)
161
162         self.bones.sort(key=getIndex)
163
164         sortMap={}
165         for i, b in enumerate(self.bones):
166             src=original.index(b)
167             sortMap[src]=i
168         for b in self.bones:
169             b.index=sortMap[b.index]
170             if b.parent_index:
171                 b.parent_index=sortMap[b.parent_index]
172             if b.tail_index:
173                 b.tail_index=sortMap[b.tail_index]
174             if b.ik_index>0:
175                 b.ik_index=sortMap[b.ik_index]
176
177     def _fix(self):
178         """
179         調整
180         """
181         for b in self.bones:
182             # parent index
183             if b.parent_index==None:
184                 b.parent_index=-1
185             else:
186                 if b.type==6 or b.type==7:
187                     # fix tail bone
188                     parent=self.bones[b.parent_index]
189                     #print('parnet', parent.name)
190                     parent.tail_index=b.index
191
192         for b in self.bones:
193             if b.tail_index==None:
194                 b.tail_index=0
195             elif b.type==9:
196                 b.tail_index==0
197
198     def getIndex(self, bone):
199         for i, b in enumerate(self.bones):
200             if b==bone:
201                 return i
202         assert(false)
203
204     def indexByName(self, name):
205         if name=='':
206             return 0
207         else:
208             try:
209                 return self.getIndex(self.__boneByName(name))
210             except:
211                 return 0
212
213     def __boneByName(self, name):
214         return self.boneMap[name]
215
216     def __getBone(self, parent, b):
217         if len(b.children)==0:
218             parent.type=7
219             return
220
221         for i, c in enumerate(b.children):
222             bone=Bone(c.name, 
223                     bl.bone.getHeadLocal(c),
224                     bl.bone.getTailLocal(c),
225                     bl.bone.isConnected(c))
226             self.__addBone(bone)
227             if parent:
228                 bone.parent_index=parent.index
229                 #if i==0:
230                 if bone.isConnect or (not parent.tail_index and parent.tail==bone.pos):
231                     parent.tail_index=bone.index
232             self.__getBone(bone, c)
233
234     def __addBone(self, bone):
235         bone.index=len(self.bones)
236         self.bones.append(bone)
237         self.boneMap[bone.name]=bone
238