OSDN Git Service

update version
[meshio/pymeshio.git] / blender25-meshio / export_pmd.py
index a9fea63..f3ad899 100644 (file)
@@ -14,22 +14,23 @@ pmd Importer
 
 This script exports a pmd model.
 
-0.1 20100318: first implementation.
-0.2 20100519: refactoring. use C extension.
-1.0 20100530: implement basic features.
-1.1 20100612: integrate 2.4 and 2.5.
-1.2 20100616: implement rigid body.
-1.3 20100619: fix rigid body, bone weight.
-1.4 20100626: refactoring.
-1.5 20100629: sphere map.
-1.6 20100710: toon texture & bone group.
-1.7 20100711: separate vertex with normal or uv.
-2.0 20100724: update for Blender2.53.
-2.1 20100731: add full python module.
-2.2 20101005: update for Blender2.54.
-2.3 20101228: update for Blender2.55.
-2.4 20110429: update for Blender2.57b.
-2.5 20110522: implement RigidBody and Constraint.
+20100318: first implementation.
+20100519: refactoring. use C extension.
+20100530: implement basic features.
+20100612: integrate 2.4 and 2.5.
+20100616: implement rigid body.
+20100619: fix rigid body, bone weight.
+20100626: refactoring.
+20100629: sphere map.
+20100710: toon texture & bone group.
+20100711: separate vertex with normal or uv.
+20100724: update for Blender2.53.
+20100731: add full python module.
+20101005: update for Blender2.54.
+20101228: update for Blender2.55.
+20110429: update for Blender2.57b.
+20110522: implement RigidBody and Constraint.
+20111002: update for pymeshio-2.1.0
 """
 
 bl_addon_info = {
@@ -45,49 +46,19 @@ bl_addon_info = {
         'tracker_url': 'http://sourceforge.jp/ticket/newticket.php?group_id=5081',
         }
 
-MMD_SHAPE_GROUP_NAME='_MMD_SHAPE'
-MMD_MB_NAME='mb_name'
-MMD_MB_COMMENT='mb_comment'
-MMD_COMMENT='comment'
-BASE_SHAPE_NAME='Basis'
-RIGID_NAME='rigid_name'
-RIGID_SHAPE_TYPE='rigid_shape_type'
-RIGID_PROCESS_TYPE='rigid_process_type'
-RIGID_BONE_NAME='rigid_bone_name'
-#RIGID_LOCATION='rigid_loation'
-RIGID_GROUP='ribid_group'
-RIGID_INTERSECTION_GROUP='rigid_intersection_group'
-RIGID_WEIGHT='rigid_weight'
-RIGID_LINEAR_DAMPING='rigid_linear_damping'
-RIGID_ANGULAR_DAMPING='rigid_angular_damping'
-RIGID_RESTITUTION='rigid_restitution'
-RIGID_FRICTION='rigid_friction'
-CONSTRAINT_NAME='constraint_name'
-CONSTRAINT_A='const_a'
-CONSTRAINT_B='const_b'
-CONSTRAINT_POS_MIN='const_pos_min'
-CONSTRAINT_POS_MAX='const_pos_max'
-CONSTRAINT_ROT_MIN='const_rot_min'
-CONSTRAINT_ROT_MAX='const_rot_max'
-CONSTRAINT_SPRING_POS='const_spring_pos'
-CONSTRAINT_SPRING_ROT='const_spring_rot'
-TOON_TEXTURE_OBJECT='ToonTextures'
-
 
 ###############################################################################
 # import
 ###############################################################################
 import os
 import sys
+import io
+
 
-try:
-    # C extension
-    from meshio import pmd, englishmap
-    print('use meshio C module')
-except ImportError:
-    # full python
-    from .pymeshio import englishmap
-    from .pymeshio import pmd
+from .pymeshio import englishmap
+from .pymeshio import common
+from .pymeshio import pmd
+from .pymeshio.pmd import writer
 
 
 # for 2.5
@@ -99,26 +70,6 @@ from . import bl25 as bl
 
 xrange=range
 
-def setMaterialParams(material, m):
-    # diffuse
-    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
-    # specular
-    material.shinness=0 if m.specular_toon_size<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]
-    # ambient
-    material.ambient.r=m.mirror_color[0]
-    material.ambient.g=m.mirror_color[1]
-    material.ambient.b=m.mirror_color[2]
-    # flag
-    material.flag=1 if m.subsurface_scattering.use else 0
-    # toon
-    material.toon_index=7
-
 def toCP932(s):
     return s.encode('cp932')
 
@@ -304,6 +255,29 @@ class IKSolver(object):
         self.weight=weight
 
 
+class SSS(object):
+    def __init__(self):
+        self.use=1
+
+
+class DefaultMatrial(object):
+    def __init__(self):
+        self.name='default'
+        # diffuse
+        self.diffuse_color=[1, 1, 1]
+        self.alpha=1
+        # specular
+        self.specular_toon_size=0
+        self.specular_hardness=5
+        self.specular_color=[1, 1, 1]
+        # ambient
+        self.mirror_color=[1, 1, 1]
+        # flag
+        self.subsurface_scattering=SSS()
+        # texture
+        self.texture_slots=[]
+
+
 class OneSkinMesh(object):
     __slots__=['vertexArray', 'morphList', 'rigidbodies', 'constraints', ]
     def __init__(self):
@@ -358,7 +332,11 @@ class OneSkinMesh(object):
                 for g in v.groups:
                     setWeight(i, obj.vertex_groups[g.group].name, g.weight)
             else:
-                setWeight(i, obj.vertex_groups[0].name, 1)
+                try:
+                    setWeight(i, obj.vertex_groups[0].name, 1)
+                except:
+                    # no vertex_groups
+                    pass
 
         # 合計値が1になるようにする
         for i in xrange(len(mesh.vertices)):
@@ -375,10 +353,14 @@ class OneSkinMesh(object):
         return weightMap, secondWeightMap
 
     def __processFaces(self, obj_name, mesh, weightMap, secondWeightMap):
+        default_material=DefaultMatrial()
         # 各面の処理
         for i, face in enumerate(mesh.faces):
             faceVertexCount=bl.face.getVertexCount(face)
-            material=mesh.materials[bl.face.getMaterialIndex(face)]
+            try:
+                material=mesh.materials[bl.face.getMaterialIndex(face)]
+            except IndexError as e:
+                material=default_material
             v=[mesh.vertices[index] for index in bl.face.getVertices(face)]
             uv=bl.mesh.getFaceUV(
                     mesh, i, face, bl.face.getVertexCount(face))
@@ -461,9 +443,9 @@ class OneSkinMesh(object):
                         )
 
     def __mesh(self, obj):
-        if RIGID_SHAPE_TYPE in obj:
+        if bl.RIGID_SHAPE_TYPE in obj:
             return
-        if CONSTRAINT_A in obj:
+        if bl.CONSTRAINT_A in obj:
             return
 
         bl.message("export: %s" % obj.name)
@@ -519,12 +501,12 @@ class OneSkinMesh(object):
         baseMorph=None
 
         # shape keys
-        vg=bl.object.getVertexGroup(obj, MMD_SHAPE_GROUP_NAME)
+        vg=bl.object.getVertexGroup(obj, bl.MMD_SHAPE_GROUP_NAME)
 
         # base
         used=set()
         for b in bl.object.getShapeKeys(obj):
-            if b.name==BASE_SHAPE_NAME:
+            if b.name==bl.BASE_SHAPE_NAME:
                 baseMorph=self.__getOrCreateMorph('base', 0)
                 basis=b
 
@@ -552,7 +534,7 @@ class OneSkinMesh(object):
 
         # shape keys
         for b in bl.object.getShapeKeys(obj):
-            if b.name==BASE_SHAPE_NAME:
+            if b.name==bl.BASE_SHAPE_NAME:
                 continue
 
             #print(b.name)
@@ -585,12 +567,12 @@ class OneSkinMesh(object):
         self.morphList.sort(key=getIndex)
 
     def __rigidbody(self, obj):
-        if not RIGID_SHAPE_TYPE in obj:
+        if not bl.RIGID_SHAPE_TYPE in obj:
             return
         self.rigidbodies.append(obj)
 
     def __constraint(self, obj):
-        if not CONSTRAINT_A in obj:
+        if not bl.CONSTRAINT_A in obj:
             return
         self.constraints.append(obj)
 
@@ -804,7 +786,7 @@ class BoneBuilder(object):
 
     def __boneByName(self, name):
         return self.boneMap[name]
-                    
+
     def __getBone(self, parent, b):
         if len(b.children)==0:
             parent.type=7
@@ -856,9 +838,9 @@ class PmdExporter(object):
         root=object_node_map[bl.object.getActive()]
         o=root.o
         self.englishName=o.name
-        self.englishComment=o[MMD_COMMENT] if MMD_COMMENT in o else 'blender export\n'
-        self.name=o[MMD_MB_NAME] if MMD_MB_NAME in o else 'Blenderエクスポート'
-        self.comment=o[MMD_MB_COMMENT] if MMD_MB_COMMENT in o else 'Blnderエクスポート\n'
+        self.englishComment=o[bl.MMD_COMMENT] if bl.MMD_COMMENT in o else 'blender export\n'
+        self.name=o[bl.MMD_MB_NAME] if bl.MMD_MB_NAME in o else 'Blenderエクスポート'
+        self.comment=o[bl.MMD_MB_COMMENT] if bl.MMD_MB_COMMENT in o else 'Blnderエクスポート\n'
 
         # ワンスキンメッシュを作る
         self.oneSkinMesh=OneSkinMesh()
@@ -892,39 +874,34 @@ class PmdExporter(object):
             self.__createOneSkinMesh(child)
 
     def write(self, path):
-        io=pmd.IO()
-        io.name=self.name
-        io.comment=self.comment
-        io.version=1.0
+        model=pmd.Model(1.0)
+        model.name=self.name.encode('cp932')
+        model.comment=self.comment.encode('cp932')
 
         # 頂点
-        for pos, attribute, b0, b1, weight in self.oneSkinMesh.vertexArray.zip():
+        model.vertices=[pmd.Vertex(
+            # convert right-handed z-up to left-handed y-up
+            common.Vector3(pos[0], pos[2], pos[1]), 
             # convert right-handed z-up to left-handed y-up
-            v=io.addVertex()
-            v.pos.x=pos[0]
-            v.pos.y=pos[2]
-            v.pos.z=pos[1]
-            v.normal.x=attribute.nx
-            v.normal.y=attribute.ny
-            v.normal.z=attribute.nz
-            v.uv.x=attribute.u
-            v.uv.y=1.0-attribute.v # reverse vertical
-            v.bone0=self.skeleton.indexByName(b0)
-            v.bone1=self.skeleton.indexByName(b1)
-            v.weight0=int(100*weight)
-            v.edge_flag=0 # edge flag, 0: enable edge, 1: not edge
+            common.Vector3(attribute.nx, attribute.nz, attribute.ny),
+            # reverse vertical
+            common.Vector2(attribute.u, 1.0-attribute.v),
+            self.skeleton.indexByName(b0),
+            self.skeleton.indexByName(b1),
+            int(100*weight),
+            # edge flag, 0: enable edge, 1: not edge
+            0 
+            )
+            for pos, attribute, b0, b1, weight in self.oneSkinMesh.vertexArray.zip()]
 
         # 面とマテリアル
         vertexCount=self.oneSkinMesh.getVertexCount()
         for material_name, indices in self.oneSkinMesh.vertexArray.each():
             #print('material:', material_name)
-            m=bl.material.get(material_name)
-            # マテリアル
-            material=io.addMaterial()
-            setMaterialParams(material, m)
-
-            material.vertex_count=len(indices)
-            material.toon_index=0
+            try:
+                m=bl.material.get(material_name)
+            except KeyError as e:
+                m=DefaultMatrial()
             def get_texture_name(texture):
                 pos=texture.replace("\\", "/").rfind("/")
                 if pos==-1:
@@ -934,23 +911,38 @@ class PmdExporter(object):
             textures=[get_texture_name(path)
                 for path in bl.material.eachEnalbeTexturePath(m)]
             print(textures)
-            if len(textures)>0:
-                material.texture='*'.join(textures)
-            else:
-                material.texture=""
+            # マテリアル
+            model.materials.append(pmd.Material(
+                    # diffuse_color
+                    common.RGB(m.diffuse_color[0], m.diffuse_color[1], m.diffuse_color[2]),
+                    m.alpha,
+                    # specular_factor
+                    0 if m.specular_toon_size<1e-5 else m.specular_hardness*10,
+                    # specular_color
+                    common.RGB(m.specular_color[0], m.specular_color[1], m.specular_color[2]),
+                    # ambient_color
+                    common.RGB(m.mirror_color[0], m.mirror_color[1], m.mirror_color[2]),
+                    # flag
+                    1 if m.subsurface_scattering.use else 0,
+                    # toon
+                    0,
+                    # vertex_count
+                    len(indices),
+                    # texture
+                    ('*'.join(textures) if len(textures)>0 else "").encode('cp932')
+                    ))
             # 面
             for i in indices:
                 assert(i<vertexCount)
             for i in xrange(0, len(indices), 3):
                 # reverse triangle
-                io.indices.append(indices[i])
-                io.indices.append(indices[i+1])
-                io.indices.append(indices[i+2])
+                model.indices.append(indices[i])
+                model.indices.append(indices[i+1])
+                model.indices.append(indices[i+2])
 
         # bones
         boneNameMap={}
         for i, b in enumerate(self.skeleton.bones):
-            bone=io.addBone()
 
             # name
             boneNameMap[b.name]=i
@@ -958,11 +950,13 @@ class PmdExporter(object):
             if not v:
                 v=[b.name, b.name]
             assert(v)
-            bone.name=v[1]
+            bone=pmd.Bone(v[1].encode('cp932'))
 
             # english name
             bone_english_name=toCP932(b.name)
-            assert(len(bone_english_name)<20)
+            if len(bone_english_name)>=20:
+                print(bone_english_name)
+                #assert(len(bone_english_name)<20)
             bone.english_name=bone_english_name
 
             if len(v)>=3:
@@ -981,10 +975,12 @@ class PmdExporter(object):
             bone.pos.x=b.pos[0] if not near(b.pos[0], 0) else 0
             bone.pos.y=b.pos[2] if not near(b.pos[2], 0) else 0
             bone.pos.z=b.pos[1] if not near(b.pos[1], 0) else 0
+            
+            model.bones.append(bone)
 
         # IK
         for ik in self.skeleton.ik_list:
-            solver=io.addIK()
+            solver=pmd.IK()
             solver.index=self.skeleton.getIndex(ik.target)
             solver.target=self.skeleton.getIndex(ik.effector)
             solver.length=ik.length
@@ -994,18 +990,17 @@ class PmdExporter(object):
                 b=self.skeleton.bones[b.parent_index]
             solver.iterations=ik.iterations
             solver.weight=ik.weight
+            model.ik_list.append(solver)
 
         # 表情
         for i, m in enumerate(self.oneSkinMesh.morphList):
-            # morph
-            morph=io.addMorph()
-
             v=englishmap.getUnicodeSkinName(m.name)
             if not v:
                 v=[m.name, m.name, 0]
             assert(v)
-            morph.name=v[1]
-            morph.english_name=m.name
+            # morph
+            morph=pmd.Morph(v[1].encode("cp932"))
+            morph.english_name=m.name.encode("cp932")
             m.type=v[2]
             morph.type=v[2]
             for index, offset in m.offsets:
@@ -1017,28 +1012,28 @@ class PmdExporter(object):
         # type==0はbase
         for i, m in enumerate(self.oneSkinMesh.morphList):
             if m.type==3:
-                io.face_list.append(i)
+                model.morph_indices.append(i)
         for i, m in enumerate(self.oneSkinMesh.morphList):
             if m.type==2:
-                io.face_list.append(i)
+                model.morph_indices.append(i)
         for i, m in enumerate(self.oneSkinMesh.morphList):
             if m.type==1:
-                io.face_list.append(i)
+                model.morph_indices.append(i)
         for i, m in enumerate(self.oneSkinMesh.morphList):
             if m.type==4:
-                io.face_list.append(i)
+                model.morph_indices.append(i)
 
         # ボーングループ
         for g in self.skeleton.bone_groups:
-            boneDisplayName=io.addBoneGroup()
-            # name
             name=englishmap.getUnicodeBoneGroupName(g[0])
             if not name:
                 name=g[0]
-            boneDisplayName.name=name+'\n'
-            # english
             englishName=g[0]
-            boneDisplayName.english_name=englishName+'\n'
+
+            model.bone_group_list.append(pmd.BoneGroup(
+                    (name+'\n').encode('cp932'),
+                    (englishName+'\n').encode('cp932')
+                    ))
 
         # ボーングループメンバー
         for i, b in enumerate(self.skeleton.bones):
@@ -1046,19 +1041,17 @@ class PmdExporter(object):
                continue
             if b.type in [6, 7]:
                continue
-            io.addBoneDisplay(i, self.skeleton.getBoneGroup(b))
-
-        #assert(len(io.bones)==len(io.bone_display_list)+1)
+            model.bone_display_list.append((i, self.skeleton.getBoneGroup(b)))
 
         # English
-        io.english_name=self.englishName
-        io.english_comment=self.englishComment
+        model.english_name=self.englishName.encode('cp932')
+        model.english_comment=self.englishComment.encode('cp932')
 
         # toon
         toonMeshObject=None
         for o in bl.object.each():
             try:
-                if o.name.startswith(TOON_TEXTURE_OBJECT):
+                if o.name.startswith(bl.TOON_TEXTURE_OBJECT):
                     toonMeshObject=o
             except:
                 p(o.name)
@@ -1069,95 +1062,100 @@ class PmdExporter(object):
             for i in range(10):
                 t=bl.material.getTexture(toonMaterial, i)
                 if t:
-                    io.toon_textures[i]="%s" % t.name
+                    model.toon_textures[i]=("%s" % t.name).encode('cp932')
                 else:
-                    io.toon_textures[i]="toon%02d.bmp" % (i+1)
+                    model.toon_textures[i]=("toon%02d.bmp" % (i+1)).encode('cp932')
         else:
             for i in range(10):
-                io.toon_textures[i]="toon%02d.bmp" % (i+1)
+                model.toon_textures[i]=("toon%02d.bmp" % (i+1)).encode('cp932')
 
         # rigid body
         rigidNameMap={}
         for i, obj in enumerate(self.oneSkinMesh.rigidbodies):
-            name=obj[RIGID_NAME] if RIGID_NAME in obj else obj.name
-            #print(name)
-            rigidBody=pmd.RigidBody(name)
+            name=obj[bl.RIGID_NAME] if bl.RIGID_NAME in obj else obj.name
+            print(name)
             rigidNameMap[name]=i
-            boneIndex=boneNameMap[obj[RIGID_BONE_NAME]]
+            boneIndex=boneNameMap[obj[bl.RIGID_BONE_NAME]]
             if boneIndex==0:
                 boneIndex=0xFFFF
                 bone=self.skeleton.bones[0]
             else:
                 bone=self.skeleton.bones[boneIndex]
-            rigidBody.boneIndex=boneIndex
-            #rigidBody.position.x=obj[RIGID_LOCATION][0]
-            #rigidBody.position.y=obj[RIGID_LOCATION][1]
-            #rigidBody.position.z=obj[RIGID_LOCATION][2]
-            rigidBody.position.x=obj.location.x-bone.pos[0]
-            rigidBody.position.y=obj.location.z-bone.pos[2]
-            rigidBody.position.z=obj.location.y-bone.pos[1]
-            rigidBody.rotation.x=-obj.rotation_euler[0]
-            rigidBody.rotation.y=-obj.rotation_euler[2]
-            rigidBody.rotation.z=-obj.rotation_euler[1]
-            rigidBody.processType=obj[RIGID_PROCESS_TYPE]
-            rigidBody.group=obj[RIGID_GROUP]
-            rigidBody.target=obj[RIGID_INTERSECTION_GROUP]
-            rigidBody.weight=obj[RIGID_WEIGHT]
-            rigidBody.linearDamping=obj[RIGID_LINEAR_DAMPING]
-            rigidBody.angularDamping=obj[RIGID_ANGULAR_DAMPING]
-            rigidBody.restitution=obj[RIGID_RESTITUTION]
-            rigidBody.friction=obj[RIGID_FRICTION]
-            if obj[RIGID_SHAPE_TYPE]==0:
-                rigidBody.shapeType=pmd.SHAPE_SPHERE
-                rigidBody.w=obj.scale[0]
-                rigidBody.d=0
-                rigidBody.h=0
-            elif obj[RIGID_SHAPE_TYPE]==1:
-                rigidBody.shapeType=pmd.SHAPE_BOX
-                rigidBody.w=obj.scale[0]
-                rigidBody.d=obj.scale[1]
-                rigidBody.h=obj.scale[2]
-            elif obj[RIGID_SHAPE_TYPE]==2:
-                rigidBody.shapeType=pmd.SHAPE_CAPSULE
-                rigidBody.w=obj.scale[0]
-                rigidBody.h=obj.scale[2]
-                rigidBody.d=0
-            io.rigidbodies.append(rigidBody)
+            rigidBody=pmd.RigidBody(
+                    name.encode('cp932'), 
+                    boneIndex,
+                    shape_position=common.Vector3(
+                        obj.location.x-bone.pos[0],
+                        obj.location.z-bone.pos[2],
+                        obj.location.y-bone.pos[1]),
+                    shape_rotation=common.Vector3(
+                        -obj.rotation_euler[0],
+                        -obj.rotation_euler[2],
+                        -obj.rotation_euler[1]),
+                    collision_group=obj[bl.RIGID_GROUP],
+                    no_collision_group=obj[bl.RIGID_INTERSECTION_GROUP],
+                    mode=obj[bl.RIGID_PROCESS_TYPE],
+                    mass=obj[bl.RIGID_WEIGHT],
+                    linear_damping=obj[bl.RIGID_LINEAR_DAMPING],
+                    angular_damping=obj[bl.RIGID_ANGULAR_DAMPING],
+                    restitution=obj[bl.RIGID_RESTITUTION],
+                    friction=obj[bl.RIGID_FRICTION])
+            if obj[bl.RIGID_SHAPE_TYPE]==0:
+                rigidBody.shape_type=pmd.SHAPE_SPHERE
+                rigidBody.shape_size=common.Vector3(obj.scale[0], 0, 0)
+            elif obj[bl.RIGID_SHAPE_TYPE]==1:
+                rigidBody.shape_type=pmd.SHAPE_BOX
+                rigidBody.shape_size=common.Vector3(obj.scale[0], obj.scale[1], obj.scale[2])
+            elif obj[bl.RIGID_SHAPE_TYPE]==2:
+                rigidBody.shape_type=pmd.SHAPE_CAPSULE
+                rigidBody.shape_size=common.Vector3(obj.scale[0], obj.scale[2], 0)
+            model.rigidbodies.append(rigidBody)
 
         # constraint
-        for obj in self.oneSkinMesh.constraints:
-            constraint=pmd.Constraint(obj[CONSTRAINT_NAME])
-            constraint.rigidA=rigidNameMap[obj[CONSTRAINT_A]]
-            constraint.rigidB=rigidNameMap[obj[CONSTRAINT_B]]
-            constraint.pos.x=obj.location[0]
-            constraint.pos.y=obj.location[2]
-            constraint.pos.z=obj.location[1]
-            constraint.rot.x=-obj.rotation_euler[0]
-            constraint.rot.y=-obj.rotation_euler[2]
-            constraint.rot.z=-obj.rotation_euler[1]
-            constraint.constraintPosMin.x=obj[CONSTRAINT_POS_MIN][0]
-            constraint.constraintPosMin.y=obj[CONSTRAINT_POS_MIN][1]
-            constraint.constraintPosMin.z=obj[CONSTRAINT_POS_MIN][2]
-            constraint.constraintPosMax.x=obj[CONSTRAINT_POS_MAX][0]
-            constraint.constraintPosMax.y=obj[CONSTRAINT_POS_MAX][1]
-            constraint.constraintPosMax.z=obj[CONSTRAINT_POS_MAX][2]
-            constraint.constraintRotMin.x=obj[CONSTRAINT_ROT_MIN][0]
-            constraint.constraintRotMin.y=obj[CONSTRAINT_ROT_MIN][1]
-            constraint.constraintRotMin.z=obj[CONSTRAINT_ROT_MIN][2]
-            constraint.constraintRotMax.x=obj[CONSTRAINT_ROT_MAX][0]
-            constraint.constraintRotMax.y=obj[CONSTRAINT_ROT_MAX][1]
-            constraint.constraintRotMax.z=obj[CONSTRAINT_ROT_MAX][2]
-            constraint.springPos.x=obj[CONSTRAINT_SPRING_POS][0]
-            constraint.springPos.y=obj[CONSTRAINT_SPRING_POS][1]
-            constraint.springPos.z=obj[CONSTRAINT_SPRING_POS][2]
-            constraint.springRot.x=obj[CONSTRAINT_SPRING_ROT][0]
-            constraint.springRot.y=obj[CONSTRAINT_SPRING_ROT][1]
-            constraint.springRot.z=obj[CONSTRAINT_SPRING_ROT][2]
-            io.constraints.append(constraint)
+        model.joints=[pmd.Joint(
+            name=obj[bl.CONSTRAINT_NAME].encode('cp932'),
+            rigidbody_index_a=rigidNameMap[obj[bl.CONSTRAINT_A]],
+            rigidbody_index_b=rigidNameMap[obj[bl.CONSTRAINT_B]],
+            position=common.Vector3(
+                obj.location[0], 
+                obj.location[2], 
+                obj.location[1]),
+            rotation=common.Vector3(
+                -obj.rotation_euler[0], 
+                -obj.rotation_euler[2], 
+                -obj.rotation_euler[1]),
+            translation_limit_min=common.Vector3(
+                obj[bl.CONSTRAINT_POS_MIN][0],
+                obj[bl.CONSTRAINT_POS_MIN][1],
+                obj[bl.CONSTRAINT_POS_MIN][2]
+                ),
+            translation_limit_max=common.Vector3(
+                obj[bl.CONSTRAINT_POS_MAX][0],
+                obj[bl.CONSTRAINT_POS_MAX][1],
+                obj[bl.CONSTRAINT_POS_MAX][2]
+                ),
+            rotation_limit_min=common.Vector3(
+                obj[bl.CONSTRAINT_ROT_MIN][0],
+                obj[bl.CONSTRAINT_ROT_MIN][1],
+                obj[bl.CONSTRAINT_ROT_MIN][2]),
+            rotation_limit_max=common.Vector3(
+                obj[bl.CONSTRAINT_ROT_MAX][0],
+                obj[bl.CONSTRAINT_ROT_MAX][1],
+                obj[bl.CONSTRAINT_ROT_MAX][2]),
+            spring_constant_translation=common.Vector3(
+                obj[bl.CONSTRAINT_SPRING_POS][0],
+                obj[bl.CONSTRAINT_SPRING_POS][1],
+                obj[bl.CONSTRAINT_SPRING_POS][2]),
+            spring_constant_rotation=common.Vector3(
+                obj[bl.CONSTRAINT_SPRING_ROT][0],
+                obj[bl.CONSTRAINT_SPRING_ROT][1],
+                obj[bl.CONSTRAINT_SPRING_ROT][2])
+            )
+            for obj in self.oneSkinMesh.constraints]
 
         # 書き込み
         bl.message('write: %s' % path)
-        return io.write(path)
+        return writer.write(io.open(path, 'wb'), model)
 
 
 def _execute(filepath=''):