OSDN Git Service

fix bone structure.
[meshio/meshio.git] / swig / blender / pmd_import.py
index 408e84b..3f7b33b 100644 (file)
@@ -7,7 +7,7 @@
  Tooltip: 'Import PMD file for MikuMikuDance.'
 """
 __author__= ["ousttrue"]
-__version__= "1.1"
+__version__= "1.2"
 __url__=()
 __bpydoc__="""
 pmd Importer
@@ -24,10 +24,30 @@ This script imports a pmd into Blender for editing.
 0.8: 20100521: add shape_key group.
 1.0: 20100530: add invisilbe bone tail(armature layer 2).
 1.1: 20100608: integrate 2.4 and 2.5.
+1.2: 20100616: implement rigid body.
 """
 
 MMD_SHAPE_GROUP_NAME='_MMD_SHAPE'
 BASE_SHAPE_NAME='Basis'
+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_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'
 
 
 ###############################################################################
@@ -35,7 +55,6 @@ BASE_SHAPE_NAME='Basis'
 ###############################################################################
 import os
 import sys
-import re
 import math
 
 # C extension
@@ -64,26 +83,6 @@ else:
     xrange=range
 
 ###############################################################################
-# progress bar
-###############################################################################
-def progress_start(base):
-    global progressBar
-    progressBar=bl.ProgressBar(base)
-
-def progress_finish():
-    global progressBar
-    progressBar.finish()
-
-def progress_print(message, progress=0.05):
-    global progressBar
-    progressBar.advance(message, progress)
-
-def progress_set(message, progress):
-    global progressBar
-    progressBar.set(message, progress)
-
-
-###############################################################################
 def convert_coord(pos):
     """
     Left handed y-up to Right handed z-up
@@ -184,7 +183,7 @@ def __importShape(obj, l, vertex_map):
 
             for index, offset in zip(s.indices, s.pos_list):
                 try:
-                    vertex_index=base.indices[index]
+                    vertex_index=vertex_map[base.indices[index]]
                     bl.shapeKeyAssign(new_shape_key, vertex_index,
                             mesh.verts[vertex_index].co+
                             bl.createVector(*convert_coord(offset)))
@@ -206,13 +205,13 @@ def __importShape(obj, l, vertex_map):
 def __build(armature, b, p, parent):
     name=englishmap.getEnglishBoneName(b.getName())
     if not name:
-        name=b.getName().encode(bl.INTERNAL_ENCODING)
+        name=b.getName()
 
     bone=bl.createArmatureBone(armature, name)
 
     if b.tail_index==0:
-        # 先端
-        assert(b.type==6 or b.type==7)
+        # 先端ボーン
+        assert(b.type==6 or b.type==7 or b.type==9)
         bone.head = bl.createVector(*convert_coord(b.pos))
         bone.tail=bone.head+bl.createVector(0, 1, 0)
         assert(parent)
@@ -228,6 +227,7 @@ def __build(armature, b, p, parent):
         # armature layer 2
         bl.boneLayerMask(bone, [0, 1])
     else:
+        # 通常ボーン
         bone.head = bl.createVector(*convert_coord(b.pos))
         bone.tail = bl.createVector(*convert_coord(b.tail))
         if parent:
@@ -257,6 +257,8 @@ def __importArmature(scene, l):
     for ik in l.ik_list:
         target=l.bones[ik.target]
         name = englishmap.getEnglishBoneName(target.getName())
+        if not name:
+            name=target.getName()
         p_bone = pose.bones[name]
         if not p_bone:
             print('not found', name)
@@ -286,7 +288,7 @@ def __import16MaerialAndMesh(meshObject, l,
     ############################################################
     # material
     ############################################################
-    progress_print('create materials')
+    bl.progress_print('create materials')
     mesh_material_map={}
     textureMap={}
     imageMap={}
@@ -302,9 +304,6 @@ def __import16MaerialAndMesh(meshObject, l,
         material=bl.createPmdMaterial(m)
 
         texture_name=m.getTexture()
-        #tex_file=re.compile('\*.*.spa$').sub('', m.getTexture())
-        #tex_path = os.path.join(tex_dir, tex_file).encode(
-        #        bl.INTERNAL_ENCODING)
         if texture_name!='':
             if texture_name in textureMap:
                 texture=textureMap[texture_name]
@@ -323,7 +322,7 @@ def __import16MaerialAndMesh(meshObject, l,
     ############################################################
     # vertex
     ############################################################
-    progress_print('create vertices')
+    bl.progress_print('create vertices')
     # create vertices
     vertices=[]
     if isBlender24():
@@ -336,7 +335,7 @@ def __import16MaerialAndMesh(meshObject, l,
     ############################################################
     # face
     ############################################################
-    progress_print('create faces')
+    bl.progress_print('create faces')
     # create faces
     mesh_face_indices=[]
     mesh_face_materials=[]
@@ -463,7 +462,7 @@ def __import16MaerialAndMesh(meshObject, l,
     ############################################################
     # clean up not used vertices
     ############################################################
-    progress_print('clean up vertices not used')
+    bl.progress_print('clean up vertices not used')
     remove_vertices=[]
     vertex_map={}
     for i, v in enumerate(l.each_vertex()):
@@ -474,7 +473,7 @@ def __import16MaerialAndMesh(meshObject, l,
 
     bl.meshVertsDelete(mesh, remove_vertices)
 
-    progress_print('%s created' % mesh.name)
+    bl.progress_print('%s created' % mesh.name)
     return vertex_map
 
 
@@ -547,13 +546,13 @@ def __importMesh(scene, io, tex_dir):
                 face_map, tex_dir)
 
         # enter Edit Mode
-        bl.enterEditMode()
+        #bl.enterEditMode()
 
         # crete shape key
         __importShape(meshObject, io, vertex_map)
 
         # exit Edit Mode
-        bl.exitEditMode()
+        #bl.exitEditMode()
 
         mesh.update()
         material_offset+=16
@@ -561,22 +560,155 @@ def __importMesh(scene, io, tex_dir):
     return mesh_objects
 
 
+def __importConstraints(scene, io):
+    if isBlender24():
+        return
+    print("create constrains")
+    container=bl.createEmptyObject(scene, 'Constraints')
+    layer=[
+            True, False, False, False, False, False, False, False,
+            False, False, False, False, False, False, False, False,
+            False, False, False, False, False, False, False, False,
+            False, False, False, False, False, False, False, False,
+            ]
+    material=bl.createMaterial('constraint')
+    material.diffuse_color=(1, 0, 0)
+    constraintMeshes=[]
+    for c in io.constraints:
+        bpy.ops.mesh.primitive_uv_sphere_add(
+                segments=8,
+                rings=4,
+                size=0.1,
+                location=(c.pos.x, c.pos.z, c.pos.y),
+                layer=layer
+                )
+        meshObject=scene.objects.active
+        constraintMeshes.append(meshObject)
+        mesh=bl.objectGetData(meshObject)
+        bl.meshAddMaterial(mesh, material)
+        meshObject.name='c'+c.getName()
+        #meshObject.draw_transparent=True
+        #meshObject.draw_wire=True
+        meshObject.max_draw_type='SOLID'
+        rot=c.rot
+        meshObject.rotation_euler=(-rot.x, -rot.z, -rot.y)
+
+        meshObject[CONSTRAINT_A]=io.rigidbodies[c.rigidA].getName()
+        meshObject[CONSTRAINT_B]=io.rigidbodies[c.rigidB].getName()
+        meshObject[CONSTRAINT_POS_MIN]=bl.VtoV(c.constraintPosMin)
+        meshObject[CONSTRAINT_POS_MAX]=bl.VtoV(c.constraintPosMax)
+        meshObject[CONSTRAINT_ROT_MIN]=bl.VtoV(c.constraintRotMin)
+        meshObject[CONSTRAINT_ROT_MAX]=bl.VtoV(c.constraintRotMax)
+        meshObject[CONSTRAINT_SPRING_POS]=bl.VtoV(c.springPos)
+        meshObject[CONSTRAINT_SPRING_ROT]=bl.VtoV(c.springRot)
+
+    for meshObject in reversed(constraintMeshes):
+        bl.objectMakeParent(container, meshObject)
+
+    return container
+
+
+def __importRigidBodies(scene, io):
+    if isBlender24():
+        return
+    print("create rigid bodies")
+
+    container=bl.createEmptyObject(scene, 'RigidBodies')
+    layer=[
+            True, False, False, False, False, False, False, False,
+            False, False, False, False, False, False, False, False,
+            False, False, False, False, False, False, False, False,
+            False, False, False, False, False, False, False, False,
+            ]
+    material=bl.createMaterial('rigidBody')
+    rigidMeshes=[]
+    for rigid in io.rigidbodies:
+        if rigid.boneIndex==0xFFFF:
+            # no reference bone
+            bone=io.bones[0]
+        else:
+            bone=io.bones[rigid.boneIndex]
+        pos=bone.pos+rigid.position
+
+        if rigid.shapeType==pmd.SHAPE_SPHERE:
+            bpy.ops.mesh.primitive_ico_sphere_add(
+                    location=(pos.x, pos.z, pos.y),
+                    layer=layer
+                    )
+            bpy.ops.transform.resize(
+                    value=(rigid.w, rigid.w, rigid.w))
+        elif rigid.shapeType==pmd.SHAPE_BOX:
+            bpy.ops.mesh.primitive_cube_add(
+                    location=(pos.x, pos.z, pos.y),
+                    layer=layer
+                    )
+            bpy.ops.transform.resize(
+                    value=(rigid.w, rigid.d, rigid.h))
+        elif rigid.shapeType==pmd.SHAPE_CAPSULE:
+            bpy.ops.mesh.primitive_tube_add(
+                    location=(pos.x, pos.z, pos.y),
+                    layer=layer
+                    )
+            bpy.ops.transform.resize(
+                    value=(rigid.w, rigid.w, rigid.h))
+        else:
+            assert(False)
+
+        meshObject=scene.objects.active
+        mesh=bl.objectGetData(meshObject)
+        rigidMeshes.append(meshObject)
+        bl.meshAddMaterial(mesh, material)
+        meshObject.name=rigid.getName()
+        #meshObject.draw_transparent=True
+        #meshObject.draw_wire=True
+        meshObject.max_draw_type='WIRE'
+        rot=rigid.rotation
+        meshObject.rotation_euler=(-rot.x, -rot.z, -rot.y)
+
+        # custom properties
+        meshObject[RIGID_SHAPE_TYPE]=rigid.shapeType
+        meshObject[RIGID_PROCESS_TYPE]=rigid.processType
+
+        bone_name = englishmap.getEnglishBoneName(bone.getName())
+        if not bone_name:
+            bone_name=bone.getName()
+        meshObject[RIGID_BONE_NAME]=bone_name
+
+        #meshObject[RIGID_LOCATION]=bl.VtoV(rigid.location)
+        meshObject[RIGID_GROUP]=rigid.group
+        meshObject[RIGID_INTERSECTION_GROUP]=rigid.target
+        meshObject[RIGID_WEIGHT]=rigid.weight
+        meshObject[RIGID_LINEAR_DAMPING]=rigid.linearDamping
+        meshObject[RIGID_ANGULAR_DAMPING]=rigid.angularDamping
+        meshObject[RIGID_RESTITUTION]=rigid.restitution
+        meshObject[RIGID_FRICTION]=rigid.friction
+
+    for meshObject in reversed(rigidMeshes):
+        bl.objectMakeParent(container, meshObject)
+
+    return container
+
+
 def __execute(filename, scene):
     """
     load pmd file to context.
     """
+    bl.progress_start('pmd_import')
+
     # load pmd
-    progress_set('load %s' % filename, 0.0)
+    bl.progress_set('load %s' % filename, 0.0)
 
     io=pmd.IO()
     if not io.read(filename):
         print("fail to load %s" % filename)
         return
-    progress_set('loaded %s' % filename, 0.1)
+    bl.progress_set('loaded %s' % filename, 0.1)
 
     # create root object
-    root=bl.createEmptyObject(scene, 
-            io.english_name if len(io.english_name)>0 else io.getName().encode(bl.INTERNAL_ENCODING))
+    model_name=io.getEnglishName()
+    if len(model_name)==0:
+        model_name=io.getName()
+    root=bl.createEmptyObject(scene, model_name)
 
     # import mesh
     mesh_objects=__importMesh(scene, io, os.path.dirname(filename))
@@ -597,12 +729,18 @@ def __execute(filename, scene):
         for n, b in bl.objectGetPose(armature_object).bones.items():
             bl.poseBoneLimit(n, b)
 
-    # select objects
-    bl.objectSelect(root)
-    for o in mesh_objects:
-        bl.objectSelect(o)
-    bl.objectSelect(armature_object)
+    # import rigid bodies
+    rigidBodies=__importRigidBodies(scene, io)
+    if rigidBodies:
+        bl.objectMakeParent(root, rigidBodies)
+
+    # import constraints
+    constraints=__importConstraints(scene, io)
+    if constraints:
+        bl.objectMakeParent(root, constraints)
+
+    bl.objectActivate(scene, root)
+    bl.progress_finish()
 
 if isBlender24():
     # for 2.4
@@ -618,11 +756,9 @@ if isBlender24():
         if mode_edit: 
             Blender.Window.EditMode(0)
             
-        progress_start('pmd_import')
         scene = bpy.data.scenes.active
         __execute(filename, scene)
         scene.update(0)
-        progress_finish()
 
         # restore edit mode
         if mode_edit: 
@@ -637,9 +773,7 @@ if isBlender24():
 else:
     # for 2.5
     def execute_25(*args):
-        progress_start('pmd_import')
         __execute(*args)
-        progress_finish()
 
     # import operator
     class IMPORT_OT_pmd(bpy.types.Operator):