OSDN Git Service

f8b3a545631e90c635fc4f1283789922aac166ef
[meshio/pymeshio.git] / blender26-meshio / exporter / oneskinmesh.py
1 # coding: utf-8
2 import bpy
3 from . import vertexarray
4 from .. import bl
5 from ..pymeshio import englishmap
6
7
8 class Morph(object):
9     __slots__=['name', 'type', 'offsets']
10     def __init__(self, name, type):
11         self.name=name
12         self.type=type
13         self.offsets=[]
14
15     def add(self, index, offset):
16         self.offsets.append((index, offset))
17
18     def sort(self):
19         self.offsets.sort(key=lambda e: e[0])
20
21     def __str__(self):
22         return "<Morph %s>" % self.name
23
24
25 class SSS(object):
26     def __init__(self):
27         self.use=1
28
29
30 class DefaultMatrial(object):
31     def __init__(self):
32         self.name='default'
33         # diffuse
34         self.diffuse_color=[1, 1, 1]
35         self.alpha=1
36         # specular
37         self.specular_toon_size=0
38         self.specular_hardness=5
39         self.specular_color=[1, 1, 1]
40         # ambient
41         self.mirror_color=[1, 1, 1]
42         # flag
43         self.subsurface_scattering=SSS()
44         # texture
45         self.texture_slots=[]
46
47
48 class OneSkinMesh(object):
49     __slots__=['vertexArray', 'morphList', 'rigidbodies', 'constraints', 'armatureObj']
50     def __init__(self):
51         self.vertexArray=vertexarray.VertexArray()
52         self.morphList=[]
53         self.rigidbodies=[]
54         self.constraints=[]
55         self.armatureObj=None
56
57     def __str__(self):
58         return "<OneSkinMesh %s, morph:%d>" % (
59                 self.vertexArray,
60                 len(self.morphList))
61
62     def build(self, node):
63         ############################################################
64         # search armature modifier
65         ############################################################
66         for m in node.o.modifiers:
67             if bl.modifier.isType(m, 'ARMATURE'):
68                 armatureObj=bl.modifier.getArmatureObject(m)
69                 if not self.armatureObj:
70                     self.armatureObj=armatureObj
71                 elif self.armatureObj!=armatureObj:
72                     print("warning! found multiple armature. ignored.", 
73                             armatureObj.name)
74
75         if node.o.type.upper()=='MESH':
76             self.addMesh(node.o)
77
78         for child in node.children:
79             self.build(child)
80
81     def addMesh(self, obj):
82         if not bl.object.isVisible(obj):
83             return
84         self.__mesh(obj)
85         self.__skin(obj)
86         self.__rigidbody(obj)
87         self.__constraint(obj)
88
89     def __getWeightMap(self, obj, mesh):
90         # bone weight
91         weightMap={}
92         secondWeightMap={}
93         def setWeight(i, name, w):
94             if w>0:
95                 if i in weightMap:
96                     if i in secondWeightMap:
97                         # 上位2つのweightを採用する
98                         if w<secondWeightMap[i][1]:
99                             pass
100                         elif w<weightMap[i][1]:
101                             # 2つ目を入れ替え
102                             secondWeightMap[i]=(name, w)
103                         else:
104                             # 1つ目を入れ替え
105                             weightMap[i]=(name, w)
106                     else:
107                         if w>weightMap[i][1]:
108                             # 多い方をweightMapに
109                             secondWeightMap[i]=weightMap[i]
110                             weightMap[i]=(name, w)
111                         else:
112                             secondWeightMap[i]=(name, w)
113                 else:
114                     weightMap[i]=(name, w)
115
116         # ToDo bone weightと関係ないvertex groupを除外する
117         for i, v in enumerate(mesh.vertices):
118             if len(v.groups)>0:
119                 for g in v.groups:
120                     setWeight(i, obj.vertex_groups[g.group].name, g.weight)
121             else:
122                 try:
123                     setWeight(i, obj.vertex_groups[0].name, 1)
124                 except:
125                     # no vertex_groups
126                     pass
127
128         # 合計値が1になるようにする
129         for i in range(len(mesh.vertices)):
130             if i in secondWeightMap:
131                 secondWeightMap[i]=(secondWeightMap[i][0], 1.0-weightMap[i][1])
132             elif i in weightMap:
133                 weightMap[i]=(weightMap[i][0], 1.0)
134                 secondWeightMap[i]=("", 0)
135             else:
136                 print("no weight vertex")
137                 weightMap[i]=("", 0)
138                 secondWeightMap[i]=("", 0)
139
140         return weightMap, secondWeightMap
141
142     def __processFaces(self, obj_name, mesh, weightMap, secondWeightMap):
143         default_material=DefaultMatrial()
144         # 各面の処理
145         for i, face in enumerate(mesh.faces):
146             faceVertexCount=bl.face.getVertexCount(face)
147             try:
148                 material=mesh.materials[bl.face.getMaterialIndex(face)]
149             except IndexError as e:
150                 material=default_material
151             v=[mesh.vertices[index] for index in bl.face.getVertices(face)]
152             uv=bl.mesh.getFaceUV(
153                     mesh, i, face, bl.face.getVertexCount(face))
154             # flip triangle
155             if faceVertexCount==3:
156                 # triangle
157                 self.vertexArray.addTriangle(
158                         obj_name, material.name,
159                         v[2].index, 
160                         v[1].index, 
161                         v[0].index,
162                         v[2].co, 
163                         v[1].co, 
164                         v[0].co,
165                         bl.vertex.getNormal(v[2]), 
166                         bl.vertex.getNormal(v[1]), 
167                         bl.vertex.getNormal(v[0]),
168                         uv[2], 
169                         uv[1], 
170                         uv[0],
171                         weightMap[v[2].index][0],
172                         weightMap[v[1].index][0],
173                         weightMap[v[0].index][0],
174                         secondWeightMap[v[2].index][0],
175                         secondWeightMap[v[1].index][0],
176                         secondWeightMap[v[0].index][0],
177                         weightMap[v[2].index][1],
178                         weightMap[v[1].index][1],
179                         weightMap[v[0].index][1]
180                         )
181             elif faceVertexCount==4:
182                 # quadrangle
183                 self.vertexArray.addTriangle(
184                         obj_name, material.name,
185                         v[2].index, 
186                         v[1].index, 
187                         v[0].index,
188                         v[2].co, 
189                         v[1].co, 
190                         v[0].co,
191                         bl.vertex.getNormal(v[2]), 
192                         bl.vertex.getNormal(v[1]), 
193                         bl.vertex.getNormal(v[0]), 
194                         uv[2], 
195                         uv[1], 
196                         uv[0],
197                         weightMap[v[2].index][0],
198                         weightMap[v[1].index][0],
199                         weightMap[v[0].index][0],
200                         secondWeightMap[v[2].index][0],
201                         secondWeightMap[v[1].index][0],
202                         secondWeightMap[v[0].index][0],
203                         weightMap[v[2].index][1],
204                         weightMap[v[1].index][1],
205                         weightMap[v[0].index][1]
206                         )
207                 self.vertexArray.addTriangle(
208                         obj_name, material.name,
209                         v[0].index, 
210                         v[3].index, 
211                         v[2].index,
212                         v[0].co, 
213                         v[3].co, 
214                         v[2].co,
215                         bl.vertex.getNormal(v[0]), 
216                         bl.vertex.getNormal(v[3]), 
217                         bl.vertex.getNormal(v[2]), 
218                         uv[0], 
219                         uv[3], 
220                         uv[2],
221                         weightMap[v[0].index][0],
222                         weightMap[v[3].index][0],
223                         weightMap[v[2].index][0],
224                         secondWeightMap[v[0].index][0],
225                         secondWeightMap[v[3].index][0],
226                         secondWeightMap[v[2].index][0],
227                         weightMap[v[0].index][1],
228                         weightMap[v[3].index][1],
229                         weightMap[v[2].index][1]
230                         )
231
232     def __mesh(self, obj):
233         if bl.RIGID_SHAPE_TYPE in obj:
234             return
235         if bl.CONSTRAINT_A in obj:
236             return
237
238         bl.message("export: %s" % obj.name)
239
240         # メッシュのコピーを生成してオブジェクトの行列を適用する
241         copyMesh, copyObj=bl.object.duplicate(obj)
242         if len(copyMesh.vertices)>0:
243             # apply transform
244             """
245             try:
246                 # svn 36722
247                 copyObj.scale=obj.scale
248                 bpy.ops.object.transform_apply(scale=True)
249                 copyObj.rotation_euler=obj.rotation_euler
250                 bpy.ops.object.transform_apply(rotation=True)
251                 copyObj.location=obj.location
252                 bpy.ops.object.transform_apply(location=True)
253             except AttributeError as e:
254                 # 2.57b
255                 copyObj.scale=obj.scale
256                 bpy.ops.object.scale_apply()
257                 copyObj.rotation_euler=obj.rotation_euler
258                 bpy.ops.object.rotation_apply()
259                 copyObj.location=obj.location
260                 bpy.ops.object.location_apply()
261             """
262             copyMesh.transform(obj.matrix_world)
263
264             # apply modifier
265             for m in [m for m in copyObj.modifiers]:
266                 if m.type=='SOLIDFY':
267                     continue
268                 elif m.type=='ARMATURE':
269                     continue
270                 elif m.type=='MIRROR':
271                     bpy.ops.object.modifier_apply(modifier=m.name)
272                 else:
273                     print(m.type)
274
275             weightMap, secondWeightMap=self.__getWeightMap(copyObj, copyMesh)
276             self.__processFaces(obj.name, copyMesh, weightMap, secondWeightMap)
277         bl.object.delete(copyObj)
278
279     def createEmptyBasicSkin(self):
280         self.__getOrCreateMorph('base', 0)
281
282     def __skin(self, obj):
283         if not bl.object.hasShapeKey(obj):
284             return
285
286         indexRelativeMap={}
287         blenderMesh=bl.object.getData(obj)
288         baseMorph=None
289
290         # shape keys
291         vg=bl.object.getVertexGroup(obj, bl.MMD_SHAPE_GROUP_NAME)
292
293         # base
294         used=set()
295         for b in bl.object.getShapeKeys(obj):
296             if b.name==bl.BASE_SHAPE_NAME:
297                 baseMorph=self.__getOrCreateMorph('base', 0)
298                 basis=b
299
300                 relativeIndex=0
301                 for index in vg:
302                     v=bl.shapekey.getByIndex(b, index)
303                     pos=[v[0], v[1], v[2]]
304
305                     indices=self.vertexArray.getMappedIndex(obj.name, index)
306                     for attribute, i in indices.items():
307                         if i in used:
308                             continue
309                         used.add(i)
310
311                         baseMorph.add(i, pos)
312                         indexRelativeMap[i]=relativeIndex
313                         relativeIndex+=1
314
315                 break
316         assert(basis)
317         #print(basis.name, len(baseMorph.offsets))
318
319         if len(baseMorph.offsets)==0:
320             return
321
322         # shape keys
323         for b in bl.object.getShapeKeys(obj):
324             if b.name==bl.BASE_SHAPE_NAME:
325                 continue
326
327             #print(b.name)
328             morph=self.__getOrCreateMorph(b.name, 4)
329             used=set()
330             for index, src, dst in zip(
331                     range(len(blenderMesh.vertices)),
332                     bl.shapekey.get(basis),
333                     bl.shapekey.get(b)):
334                 offset=[dst[0]-src[0], dst[1]-src[1], dst[2]-src[2]]
335                 if offset[0]==0 and offset[1]==0 and offset[2]==0:
336                     continue
337                 if index in vg:
338                     indices=self.vertexArray.getMappedIndex(obj.name, index)
339                     for attribute, i in indices.items():
340                         if i in used:
341                             continue
342                         used.add(i) 
343                         morph.add(indexRelativeMap[i], offset)
344             assert(len(morph.offsets)<len(baseMorph.offsets))
345
346         # sort skinmap
347         original=self.morphList[:]
348         def getIndex(morph):
349             for i, v in enumerate(englishmap.skinMap):
350                 if v[0]==morph.name:
351                     return i
352             #print(morph)
353             return len(englishmap.skinMap)
354         self.morphList.sort(key=getIndex)
355
356     def __rigidbody(self, obj):
357         if not bl.RIGID_SHAPE_TYPE in obj:
358             return
359         self.rigidbodies.append(obj)
360
361     def __constraint(self, obj):
362         if not bl.CONSTRAINT_A in obj:
363             return
364         self.constraints.append(obj)
365
366     def __getOrCreateMorph(self, name, type):
367         for m in self.morphList:
368             if m.name==name:
369                 return m
370         m=Morph(name, type)
371         self.morphList.append(m)
372         return m
373
374     def getVertexCount(self):
375         return len(self.vertexArray.positions)
376
377
378