From: ousttrue Date: Sun, 13 Jun 2010 04:36:24 +0000 (+0900) Subject: integrate pmd_import for blender25. X-Git-Url: http://git.osdn.jp/view?a=commitdiff_plain;h=2cef52b4ee664d7136509bddf974464e3cc2c758;p=meshio%2Fmeshio.git integrate pmd_import for blender25. --- diff --git a/swig/blender/bl24.py b/swig/blender/bl24.py index d699a64..1442b10 100644 --- a/swig/blender/bl24.py +++ b/swig/blender/bl24.py @@ -608,6 +608,9 @@ def objectDuplicate(scene, obj): dumy.setMatrix(obj.matrixWorld) return mesh, dumy +def objectDelete(scene, obj): + scene.objects.unlink(obj) + def faceVertexCount(face): return len(face.v) @@ -770,4 +773,31 @@ def objectActivateShapeKey(o, index): def shapeKeyAssign(shapeKey, index, pos): shapeKey.data[index]=pos +def objectIsVisible(obj): + return obj.restrictDisplay + +def meshVertexGroupNames(meshObject): + return meshObject.getData(mesh=True).getVertGroupNames() + +def faceNormal(face): + return face.no + +def meshFaceUv(mesh, i, face): + return face.uv + +def armatureModifierGetObject(m): + return m[Blender.Modifier.Settings.OBJECT] + +def objectHasShapeKey(o): + return o.getData(mesh=True).key + +def objectShapeKeys(o): + return o.getData(mesh=True).key.blocks + +def meshVertexGroup(meshObject, name): + for index in meshObject.getData(mesh=True).getVertsFromGroup(name): + yield index + +def materialGet(scene, material_name): + return Blender.Material.Get(material_name) diff --git a/swig/blender/bl25.py b/swig/blender/bl25.py index 24b1d8b..1415e41 100644 --- a/swig/blender/bl25.py +++ b/swig/blender/bl25.py @@ -75,6 +75,7 @@ def createPmdMaterial(m): material.specular_hardness=int(m.shinness) material.specular_color=([m.specular.r, m.specular.g, m.specular.b]) material.mirror_color=([m.ambient.r, m.ambient.g, m.ambient.b]) + material.subsurface_scattering.enabled=True if m.flag==1 else False # temporary material.emit=1.0 return material @@ -225,6 +226,9 @@ def objectDuplicate(scene, obj): bpy.ops.object.location_apply() return dumy.data, dumy +def objectDelete(scene, obj): + scene.objects.unlink(obj) + def faceVertexCount(face): return len(face.verts) @@ -393,3 +397,34 @@ def objectActivateShapeKey(o, index): def shapeKeyAssign(shapeKey, index, pos): shapeKey.data[index].co=pos +def objectIsVisible(obj): + return obj.restrict_view + +def meshVertexGroupNames(meshObject): + for g in meshObject.vertex_groups: + yield g.name + +def faceNormal(face): + return face.normal + +def meshFaceUv(mesh, i, face): + return mesh.uv_textures[0].data[i].uv + +def armatureModifierGetObject(m): + return m.object + +def objectHasShapeKey(o): + return o.data.shape_keys + +def objectShapeKeys(o): + return o.data.shape_keys.keys + +def meshVertexGroup(meshObject, name): + for i, v in enumerate(meshObject.data.verts): + for g in v.groups: + if meshObject.vertex_groups[g.group].name==name: + yield(i) + +def materialGet(scene, material_name): + return bpy.data.materials[material_name] + diff --git a/swig/blender/pmd_export.py b/swig/blender/pmd_export.py index 9c0d9b5..2690b82 100644 --- a/swig/blender/pmd_export.py +++ b/swig/blender/pmd_export.py @@ -153,7 +153,7 @@ class VertexArray(object): # append... self.vertices.append((pos.x, pos.y, pos.z)) self.normals.append((normal.x, normal.y, normal.z)) - self.uvs.append((uv.x, uv.y)) + self.uvs.append((uv[0], uv[1])) self.b0.append(b0) self.b1.append(b1) self.weight.append(weight0) @@ -200,7 +200,10 @@ class Morph(object): self.offsets.append((index, offset)) def sort(self): - self.offsets.sort(lambda l, r: l[0]-r[0]) + if isBlender24(): + self.offsets.sort(lambda l, r: l[0]-r[0]) + else: + self.offsets.sort(key=lambda e: e[0]) def __str__(self): return "" % self.name @@ -216,10 +219,11 @@ class IKSolver(object): class OneSkinMesh(object): - __slots__=['vertexArray', 'morphList'] - def __init__(self): + __slots__=['scene', 'vertexArray', 'morphList'] + def __init__(self, scene): self.vertexArray=VertexArray() self.morphList=[] + self.scene=scene def __str__(self): return "" % ( @@ -227,7 +231,7 @@ class OneSkinMesh(object): len(self.morphList)) def addMesh(self, obj): - if obj.restrictDisplay: + if bl.objectIsVisible(obj): # 非表示 return @@ -236,32 +240,40 @@ class OneSkinMesh(object): ############################################################ # bone weight ############################################################ - mesh=obj.getData(mesh=True) + mesh=bl.objectGetData(obj) weightMap={} secondWeightMap={} - for name in mesh.getVertGroupNames(): - for i, w in mesh.getVertsFromGroup(name, 1): - if w>0: - if i in weightMap: - if i in secondWeightMap: - # 上位2つのweightを採用する - if w0: + if i in weightMap: + if i in secondWeightMap: + # 上位2つのweightを採用する + if wweightMap[i][1]: - # 多い方をweightMapに - secondWeightMap[i]=weightMap[i] - weightMap[i]=(name, w) - else: - secondWeightMap[i]=(name, w) + # 1つ目を入れ替え + weightMap[i]=(name, w) else: - weightMap[i]=(name, w) + if w>weightMap[i][1]: + # 多い方をweightMapに + secondWeightMap[i]=weightMap[i] + weightMap[i]=(name, w) + else: + secondWeightMap[i]=(name, w) + else: + weightMap[i]=(name, w) + + if isBlender24(): + for name in bl.meshVertexGroupNames(obj): + for i, w in mesh.getVertsFromGroup(name, 1): + setWeight(i, name, w) + else: + for i, v in enumerate(mesh.verts): + for g in v.groups: + setWeight(i, obj.vertex_groups[g.group].name, g.weight) # 合計値が1になるようにする for i in xrange(len(mesh.verts)): @@ -272,106 +284,102 @@ class OneSkinMesh(object): weightMap[i]=(weightMap[i][0], 1.0) secondWeightMap[i]=("", 0) else: - print "no weight vertex" + print("no weight vertex") weightMap[i]=("", 0) secondWeightMap[i]=("", 0) - ############################################################ - # faces - # 新たにメッシュを生成する + # メッシュのコピーを生成してオブジェクトの行列を適用する ############################################################ - mesh=Blender.Mesh.New() - # not applied modifiers - mesh.getFromObject(obj.name, 1) - # apply object transform - mesh.transform(obj.getMatrix()) - if len(mesh.verts)==0: + copyMesh, copyObj=bl.objectDuplicate(self.scene, obj) + if len(copyMesh.verts)==0: return - for face in mesh.faces: - faceVertexCount=len(face.v) - material=mesh.materials[face.mat] + for i, face in enumerate(copyMesh.faces): + faceVertexCount=bl.faceVertexCount(face) + material=copyMesh.materials[bl.faceMaterialIndex(face)] + v=[copyMesh.verts[index] for index in bl.faceVertices(face)] + uv=bl.meshFaceUv(copyMesh, i, face) if faceVertexCount==3: - v0=face.v[0] - v1=face.v[1] - v2=face.v[2] # triangle self.vertexArray.addTriangle( material.name, - v0.index, v1.index, v2.index, - v0.co, v1.co, v2.co, + v[0].index, v[1].index, v[2].index, + v[0].co, v[1].co, v[2].co, # ToDo vertex normal #v0.no, v1.no, v2.no, - face.no, face.no, face.no, - face.uv[0], face.uv[1], face.uv[2], - weightMap[v0.index][0], - weightMap[v1.index][0], - weightMap[v2.index][0], - secondWeightMap[v0.index][0], - secondWeightMap[v1.index][0], - secondWeightMap[v2.index][0], - weightMap[v0.index][1], - weightMap[v1.index][1], - weightMap[v2.index][1] + bl.faceNormal(face), + bl.faceNormal(face), + bl.faceNormal(face), + uv[0], uv[1], uv[2], + weightMap[v[0].index][0], + weightMap[v[1].index][0], + weightMap[v[2].index][0], + secondWeightMap[v[0].index][0], + secondWeightMap[v[1].index][0], + secondWeightMap[v[2].index][0], + weightMap[v[0].index][1], + weightMap[v[1].index][1], + weightMap[v[2].index][1] ) elif faceVertexCount==4: - v0=face.v[0] - v1=face.v[1] - v2=face.v[2] - v3=face.v[3] # quadrangle self.vertexArray.addTriangle( material.name, - v0.index, v1.index, v2.index, - v0.co, v1.co, v2.co, + v[0].index, v[1].index, v[2].index, + v[0].co, v[1].co, v[2].co, #v0.no, v1.no, v2.no, - face.no, face.no, face.no, - face.uv[0], face.uv[1], face.uv[2], - weightMap[v0.index][0], - weightMap[v1.index][0], - weightMap[v2.index][0], - secondWeightMap[v0.index][0], - secondWeightMap[v1.index][0], - secondWeightMap[v2.index][0], - weightMap[v0.index][1], - weightMap[v1.index][1], - weightMap[v2.index][1] + bl.faceNormal(face), + bl.faceNormal(face), + bl.faceNormal(face), + uv[0], uv[1], uv[2], + weightMap[v[0].index][0], + weightMap[v[1].index][0], + weightMap[v[2].index][0], + secondWeightMap[v[0].index][0], + secondWeightMap[v[1].index][0], + secondWeightMap[v[2].index][0], + weightMap[v[0].index][1], + weightMap[v[1].index][1], + weightMap[v[2].index][1] ) self.vertexArray.addTriangle( material.name, - v2.index, v3.index, v0.index, - v2.co, v3.co, v0.co, + v[2].index, v[3].index, v[0].index, + v[2].co, v[3].co, v[0].co, #v2.no, v3.no, v0.no, - face.no, face.no, face.no, - face.uv[2], face.uv[3], face.uv[0], - weightMap[v2.index][0], - weightMap[v3.index][0], - weightMap[v0.index][0], - secondWeightMap[v2.index][0], - secondWeightMap[v3.index][0], - secondWeightMap[v0.index][0], - weightMap[v2.index][1], - weightMap[v3.index][1], - weightMap[v0.index][1] + bl.faceNormal(face), + bl.faceNormal(face), + bl.faceNormal(face), + uv[2], uv[3], uv[0], + weightMap[v[2].index][0], + weightMap[v[3].index][0], + weightMap[v[0].index][0], + secondWeightMap[v[2].index][0], + secondWeightMap[v[3].index][0], + secondWeightMap[v[0].index][0], + weightMap[v[2].index][1], + weightMap[v[3].index][1], + weightMap[v[0].index][1] ) + bl.objectDelete(self.scene, copyObj) ############################################################ # skin ############################################################ - # base indexRelativeMap={} - blenderMesh=obj.getData(mesh=True) + blenderMesh=bl.objectGetData(obj) baseMorph=None - if blenderMesh.key: - for b in blenderMesh.key.blocks: + if bl.objectHasShapeKey(obj): + # base + for b in bl.objectShapeKeys(obj): if b.name=='Basis': print(b.name) baseMorph=self.__getOrCreateMorph('base', 0) relativeIndex=0 basis=b - for index in blenderMesh.getVertsFromGroup( - MMD_SHAPE_GROUP_NAME): + + for index in bl.meshVertexGroup(obj, MMD_SHAPE_GROUP_NAME): v=b.data[index] pos=[v[0], v[1], v[2]] indices=self.vertexArray.getMappedIndices(index) @@ -379,39 +387,44 @@ class OneSkinMesh(object): baseMorph.add(i, pos) indexRelativeMap[i]=relativeIndex relativeIndex+=1 + break - print(len(baseMorph.offsets)) - baseMorph.sort() assert(basis) - # shape keys - vg=obj.getData(mesh=True).getVertsFromGroup( - MMD_SHAPE_GROUP_NAME) - for b in obj.getData(mesh=True).key.blocks: - if b.name=='Basis': - continue + if(len(baseMorph.offsets)>0): + baseMorph.sort() - print(b.name) - morph=self.__getOrCreateMorph(b.name, 4) - for index, src, dst in zip( - xrange(len(blenderMesh.verts)), - basis.data, - b.data): - offset=[dst[0]-src[0], dst[1]-src[1], dst[2]-src[2]] - if index in vg: - indices=self.vertexArray.getMappedIndices(index) - for i in indices: - morph.add(indexRelativeMap[i], offset) - assert(len(morph.offsets)==len(baseMorph.offsets)) - - # sort skinmap - original=self.morphList[:] - def getIndex(morph): - for i, v in enumerate(englishmap.skinMap): - if v[0]==morph.name: - return i - print(morph) - self.morphList.sort(lambda l, r: getIndex(l)-getIndex(r)) + # shape keys + vg=obj.getData(mesh=True).getVertsFromGroup( + MMD_SHAPE_GROUP_NAME) + for b in obj.getData(mesh=True).key.blocks: + if b.name=='Basis': + continue + + print(b.name) + morph=self.__getOrCreateMorph(b.name, 4) + for index, src, dst in zip( + xrange(len(blenderMesh.verts)), + basis.data, + b.data): + offset=[dst[0]-src[0], dst[1]-src[1], dst[2]-src[2]] + if index in vg: + indices=self.vertexArray.getMappedIndices(index) + for i in indices: + morph.add(indexRelativeMap[i], offset) + assert(len(morph.offsets)==len(baseMorph.offsets)) + + # sort skinmap + original=self.morphList[:] + def getIndex(morph): + for i, v in enumerate(englishmap.skinMap): + if v[0]==morph.name: + return i + print(morph) + if isBlender24(): + self.morphList.sort(lambda l, r: getIndex(l)-getIndex(r)) + else: + self.morphList.sort(key=getIndex) def __getOrCreateMorph(self, name, type): for m in self.morphList: @@ -536,7 +549,11 @@ class BoneBuilder(object): return i print(bone) - self.bones.sort(lambda l, r: getIndex(l)-getIndex(r)) + if isBlender24(): + self.bones.sort(lambda l, r: getIndex(l)-getIndex(r)) + else: + self.bones.sort(key=getIndex) + sortMap={} for i, b in enumerate(self.bones): src=original.index(b) @@ -586,10 +603,10 @@ class BoneBuilder(object): class PmdExporter(object): - def __init__(self): + def setup(self, scene): self.armatureObj=None + self.scene=scene - def setup(self, scene): # 木構造を構築する object_node_map={} for o in scene.objects: @@ -601,7 +618,7 @@ class PmdExporter(object): root=object_node_map[scene.objects.active] # ワンスキンメッシュを作る - self.oneSkinMesh=OneSkinMesh() + self.oneSkinMesh=OneSkinMesh(scene) self.__createOneSkinMesh(root) print(self.oneSkinMesh) self.name=root.o.name @@ -615,7 +632,10 @@ class PmdExporter(object): if v[0]==ik.target.name: return i return len(englishmap.boneMap) - self.builder.ik_list.sort(lambda l, r: getIndex(l)-getIndex(r)) + if isBlender24(): + self.builder.ik_list.sort(lambda l, r: getIndex(l)-getIndex(r)) + else: + self.builder.ik_list.sort(key=getIndex) def __createOneSkinMesh(self, node): ############################################################ @@ -623,13 +643,13 @@ class PmdExporter(object): ############################################################ for m in node.o.modifiers: if m.name=="Armature": - armatureObj=m[Blender.Modifier.Settings.OBJECT] + armatureObj=bl.armatureModifierGetObject(m) if not self.armatureObj: self.armatureObj=armatureObj elif self.armatureObj!=armatureObj: - print "warning! found multiple armature. ignored.", armatureObj.name + print("warning! found multiple armature. ignored.", armatureObj.name) - if node.o.getType()=='Mesh': + if node.o.type.upper()=='MESH': self.oneSkinMesh.addMesh(node.o) for child in node.children: @@ -660,24 +680,39 @@ class PmdExporter(object): # 面とマテリアル vertexCount=self.oneSkinMesh.getVertexCount() - for m, indices in self.oneSkinMesh.vertexArray.indexArrays.items(): - m=Blender.Material.Get(m) + for material_name, indices in self.oneSkinMesh.vertexArray.indexArrays.items(): + m=bl.materialGet(self.scene, material_name) # マテリアル material=io.addMaterial() - material.diffuse.r=m.R - material.diffuse.g=m.G - material.diffuse.b=m.B - material.diffuse.a=m.alpha - material.sinness=0 if m.spec<1e-5 else m.spec*10 - material.specular.r=m.specR - material.specular.g=m.specG - material.specular.b=m.specB - material.ambient.r=m.mirR - material.ambient.g=m.mirG - material.ambient.b=m.mirB + if isBlender24(): + material.diffuse.r=m.R + material.diffuse.g=m.G + material.diffuse.b=m.B + material.diffuse.a=m.alpha + material.sinness=0 if m.spec<1e-5 else m.spec*10 + material.specular.r=m.specR + material.specular.g=m.specG + material.specular.b=m.specB + material.ambient.r=m.mirR + material.ambient.g=m.mirG + material.ambient.b=m.mirB + material.flag=1 if m.enableSSS else 0 + else: + material.diffuse.r=m.diffuse_color[0] + material.diffuse.g=m.diffuse_color[1] + material.diffuse.b=m.diffuse_color[2] + material.diffuse.a=m.alpha + material.sinness=0 if m.specular_hardness<1e-5 else m.specular_hardness*10 + material.specular.r=m.specular_color[0] + material.specular.g=m.specular_color[1] + material.specular.b=m.specular_color[2] + material.ambient.r=m.mirror_color[0] + material.ambient.g=m.mirror_color[1] + material.ambient.b=m.mirror_color[2] + material.flag=1 if m.subsurface_scattering.enabled else 0 + material.vertex_count=len(indices) material.toon_index=0 - material.flag=1 if m.enableSSS else 0 # ToDo material.texture="" # 面 @@ -698,7 +733,7 @@ class PmdExporter(object): if b.name.endswith("_t"): if b.name.startswith("arm twist1_") or b.name.startswith("arm twist2_"): # skip - print "skip %s" % b.name + print("skip %s" % b.name) continue bone=io.addBone() @@ -790,8 +825,13 @@ class PmdExporter(object): # ボーン表示枠 def createBoneDisplayName(name, english): boneDisplayName=io.addBoneDisplayName() - boneDisplayName.name=name.decode('utf-8').encode('cp932') - boneDisplayName.english_name=english + if isBlender24(): + boneDisplayName.name=name.decode('utf-8').encode('cp932') + boneDisplayName.english_name=english + else: + # ToDo + boneDisplayName.name=english + boneDisplayName.english_name=english boneDisplayName=createBoneDisplayName("IK\n", "IK\n") boneDisplayName=createBoneDisplayName("体(上)\n", "Body[u]\n") boneDisplayName=createBoneDisplayName("髪\n", "Hair\n") @@ -814,7 +854,7 @@ class PmdExporter(object): io.getToonTexture(i).name="toon%02d.bmp\n" % i # 書き込み - return io.write(path.encode(bl.FS_ENCODING)) + return io.write(path) def getBoneDisplayGroup(bone): @@ -877,7 +917,7 @@ def __execute(filename, scene): if isBlender24(): - # 24 + # for 2.4 def execute_24(filename): filename=filename.decode(bl.INTERNAL_ENCODING) print("pmd exporter: %s" % filename) @@ -888,7 +928,7 @@ if isBlender24(): scene = bpy.data.scenes.active __execute(filename, scene) - print 'finished in %.2f seconds' % (Blender.sys.time()-t) + print('finished in %.2f seconds' % (Blender.sys.time()-t)) Blender.Redraw() Blender.Window.WaitCursor(0) @@ -898,6 +938,65 @@ if isBlender24(): Blender.sys.makename(ext='.pmd')) else: - # 25 - pass + # for 2.5 + def execute_25(*args): + __execute(*args) + + # operator + class EXPORT_OT_pmd(bpy.types.Operator): + '''Save a Metasequoia PMD file.''' + bl_idname = "export_scene.pmd" + bl_label = 'Export PMD' + + # List of operator properties, the attributes will be assigned + # to the class instance from the operator settings before calling. + + path = StringProperty( + name="File Path", + description="File path used for exporting the PMD file", + maxlen= 1024, + default= "" + ) + filename = StringProperty( + name="File Name", + description="Name of the file.") + directory = StringProperty( + name="Directory", + description="Directory of the file.") + + check_existing = BoolProperty( + name="Check Existing", + description="Check and warn on overwriting existing files", + default=True, + options=set('HIDDEN')) + + def execute(self, context): + execute_25( + self.properties.path, + context.scene + ) + return 'FINISHED' + + def invoke(self, context, event): + wm=context.manager + wm.add_fileselect(self) + return 'RUNNING_MODAL' + + # register menu + def menu_func(self, context): + default_path=bpy.data.filename.replace(".blend", ".pmd") + self.layout.operator( + EXPORT_OT_pmd.bl_idname, + text="Miku Miku Dance Model(.pmd)").path=default_path + + def register(): + bpy.types.register(EXPORT_OT_pmd) + bpy.types.INFO_MT_file_export.append(menu_func) + + def unregister(): + bpy.types.unregister(EXPORT_OT_pmd) + bpy.types.INFO_MT_file_export.remove(menu_func) + + if __name__ == "__main__": + register()