Tooltip: 'Import PMD file for MikuMikuDance.'
"""
__author__= ["ousttrue"]
-__version__= "1.2"
+__version__= "2.0"
__url__=()
__bpydoc__="""
pmd Importer
1.4 20100623: fix constraint name.
1.5 20100626: refactoring.
1.6 20100629: sphere map.
+1.7 20100703: implement bone group.
+1.8 20100710: implement toon texture.
+1.9 20100718: keep model name, comment.
+2.0 20100724: update for Blender2.53.
+2.1 20100731: add full python module.
"""
+bl_addon_info = {
+ 'category': 'Import/Export',
+ 'name': 'Import: MikuMikuDance Model Format (.pmd)',
+ 'author': 'ousttrue',
+ 'version': '2.0',
+ 'blender': (2, 5, 3),
+ 'location': 'File > Import',
+ 'description': 'Import from the MikuMikuDance Model Format (.pmd)',
+ 'warning': '', # used for warning icon and text in addons panel
+ 'wiki_url': 'http://sourceforge.jp/projects/meshio/wiki/FrontPage',
+ }
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'
CONSTRAINT_ROT_MAX='const_rot_max'
CONSTRAINT_SPRING_POS='const_spring_pos'
CONSTRAINT_SPRING_ROT='const_spring_rot'
+TOON_TEXTURE_OBJECT='ToonTextures'
###############################################################################
import sys
import math
-# C extension
-from meshio import pmd, englishmap
+try:
+ # C extension
+ from meshio import pmd, englishmap
+except ImportError:
+ # full python
+ from pymeshio import englishmap
+ from pymeshio import mmd as pmd
+ pmd.IO=pmd.PMDLoader
def isBlender24():
return sys.version_info[0]<3
def createPmdMaterial(m, index):
material=Blender.Material.New()
- #material.setRef(1)
- #material.diffuseSize = 3.14/2
- #material.setDiffuseSmooth(0)
- #material.setSpecSize(0)
- #material.setSpec(0)
- # shader
- # diffuse
+ # fresnelが無いw
material.setDiffuseShader(Blender.Material.Shaders.DIFFUSE_TOON)
material.setRGBCol([m.diffuse.r, m.diffuse.g, m.diffuse.b])
material.setAlpha(m.diffuse.a)
elif n.startswith("ankle_"):
b.lockYRot=True
- def setSphereMap(material, index, blende_type=None):
- pass
+ def setSphereMap(material, index, blend_type='MULTIPLY'):
+ slot=material.textures[index]
+ slot.mapto=Blender.Texture.MapTo.NOR
+ slot.mapping=Blender.Texture.Mappings.SPHERE
+ if blend_type=='MULTIPLY':
+ slot.blendmode=Blender.Texture.BlendModes.MULTIPLY
+ elif blend_type=='ADD':
+ slot.blendmode=Blender.Texture.BlendModes.ADD
else:
# for 2.5
import bpy
- from bpy.props import *
import mathutils
# wrapper
#b.ik_dof_y=False
pass
- def setSphereMap(material, index, blend_type=None):
+ def setSphereMap(material, index, blend_type='MULTIPLY'):
slot=material.texture_slots[index]
- slot.texture_coordinates='REFLECTION'
+ slot.texture_coordinates='NORMAL'
slot.mapping='SPHERE'
- if blend_type:
- slot.blend_type=blend_type
+ slot.blend_type=blend_type
###############################################################################
def VtoV(v):
return bl.createVector(v.x, v.y, v.z)
+
def convert_coord(pos):
"""
Left handed y-up to Right handed z-up
print('invalid bone index', index)
return l.bones[0].getName()
+
+def get_group_name(g):
+ group_name=englishmap.getEnglishBoneGroupName(g.getName().strip())
+ if not group_name:
+ group_name=g.getName().strip()
+ return group_name
+
+
+def __importToonTextures(io, tex_dir):
+ mesh, meshObject=bl.mesh.create(TOON_TEXTURE_OBJECT)
+ material=bl.material.create(TOON_TEXTURE_OBJECT)
+ bl.mesh.addMaterial(mesh, material)
+ for i in range(10):
+ t=io.getToonTexture(i)
+ path=os.path.join(tex_dir, t.getName())
+ texture, image=bl.texture.create(path)
+ bl.material.addTexture(material, texture, False)
+ return meshObject, material
+
+
def __importShape(obj, l, vertex_map):
if len(l.morph_list)==0:
return
bone=bl.armature.createBone(armature, name)
if parent and (b.tail_index==0 or 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)
bone.parent=parent
else:
print('diffurence with parent.tail and head', name)
- bl.bone.setConnected(bone)
+ if b.type!=9:
+ bl.bone.setConnected(bone)
# armature layer 2
bl.bone.setLayerMask(bone, [0, 1])
else:
__build(armature, c, b, bone)
-def __importArmature(scene, l):
- # build bone
+def __importArmature(l):
armature, armature_object=bl.armature.create()
+
+ # build bone
bl.armature.makeEditable(armature_object)
for b in l.bones:
if not b.parent:
__build(armature, b, None, None)
bl.armature.update(armature)
- bl.exitEditMode()
+ bl.enterObjectMode()
# IK constraint
pose = bl.object.getPose(armature_object)
bl.armature.makeEditable(armature_object)
bl.armature.update(armature)
- bl.exitEditMode()
+ bl.enterObjectMode()
+
+ if isBlender24():
+ pass
+ else:
+ # create bone group
+ for i, g in enumerate(l.bone_group_list):
+ name=get_group_name(g)
+ bl.object.createBoneGroup(armature_object, name, "THEME%02d" % (i+1))
+
+ # assign bone to group
+ for b_index, g_index in l.bone_display_list:
+ # bone
+ b=l.bones[b_index]
+ bone_name=englishmap.getEnglishBoneName(b.getName())
+ if not bone_name:
+ bone_name=b.getName()
+ # group
+ g=l.bone_group_list[g_index-1]
+ group_name=get_group_name(g)
+
+ # assign
+ pose.bones[bone_name].bone_group=pose.bone_groups[group_name]
+
+ bl.enterObjectMode()
return armature_object
def __import16MaerialAndMesh(meshObject, l,
- material_order, face_map, tex_dir):
+ material_order, face_map, tex_dir, toon_material):
mesh=bl.object.getData(meshObject)
############################################################
material=createPmdMaterial(m, material_index)
+ # main texture
texture_name=m.getTexture()
if texture_name!='':
for i, t in enumerate(texture_name.split('*')):
texture, image=bl.texture.create(path)
textureMap[texture_name]=texture
imageMap[material_index]=image
- bl.material.addTexture(material, texture)
+ texture_index=bl.material.addTexture(material, texture)
if t.endswith('sph'):
# sphere map
- setSphereMap(material, i)
+ setSphereMap(material, texture_index)
elif t.endswith('spa'):
# sphere map
- setSphereMap(material, i, 'ADD')
+ setSphereMap(material, texture_index, 'ADD')
+
+ # toon texture
+ toon_index=bl.material.addTexture(
+ material,
+ bl.material.getTexture(
+ toon_material,
+ 0 if m.toon_index==0xFF else m.toon_index
+ ),
+ False)
bl.mesh.addMaterial(mesh, material)
+
index+=1
############################################################
return vertex_map
-def __importMesh(scene, io, tex_dir):
+def __importMaterialAndMesh(io, tex_dir, toon_material):
"""
@param l[in] mmd.PMDLoader
@param filename[in]
# shapeキーで使われる順に並べなおしたマテリアル16個分の
# メッシュを作成する
vertex_map=__import16MaerialAndMesh(
- meshObject, io, material16, face_map, tex_dir)
+ meshObject, io, material16, face_map, tex_dir, toon_material)
# crete shape key
__importShape(meshObject, io, vertex_map)
return mesh_objects
-def __importConstraints(scene, io):
+def __importConstraints(io):
if isBlender24():
return
print("create constraint")
container=bl.object.createEmpty('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,
+ True, False, False, False, False, False, False, False, False, False,
+ False, False, False, False, False, False, False, False, False, False,
]
material=bl.material.create('constraint')
material.diffuse_color=(1, 0, 0)
location=(c.pos.x, c.pos.z, c.pos.y),
layer=layer
)
- meshObject=scene.objects.active
+ meshObject=bl.object.getActive()
constraintMeshes.append(meshObject)
mesh=bl.object.getData(meshObject)
bl.mesh.addMaterial(mesh, material)
return container
-def __importRigidBodies(scene, io):
+def __importRigidBodies(io):
if isBlender24():
return
print("create rigid bodies")
container=bl.object.createEmpty('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,
+ True, False, False, False, False, False, False, False, False, False,
+ False, False, False, False, False, False, False, False, False, False,
]
material=bl.material.create('rigidBody')
rigidMeshes=[]
- for rigid in io.rigidbodies:
+ for i, rigid in enumerate(io.rigidbodies):
if rigid.boneIndex==0xFFFF:
# no reference bone
bone=io.bones[0]
else:
assert(False)
- meshObject=scene.objects.active
+ meshObject=bl.object.getActive()
mesh=bl.object.getData(meshObject)
rigidMeshes.append(meshObject)
bl.mesh.addMaterial(mesh, material)
- meshObject.name=rigid.getName()
+ meshObject.name='r_%d' % i
+ meshObject[RIGID_NAME]=rigid.getName()
#meshObject.draw_transparent=True
#meshObject.draw_wire=True
meshObject.max_draw_type='WIRE'
return container
-def __execute(filename, scene):
+def _execute(filename):
"""
load pmd file to context.
"""
if len(model_name)==0:
model_name=io.getName()
root=bl.object.createEmpty(model_name)
+ root[MMD_MB_NAME]=io.getName()
+ root[MMD_MB_COMMENT]=io.getComment()
+ root[MMD_COMMENT]=io.getEnglishComment()
+
+ # toon textures
+ tex_dir=os.path.dirname(filename)
+ toonTextures, toonMaterial=__importToonTextures(io, tex_dir)
+ bl.object.makeParent(root, toonTextures)
# import mesh
- mesh_objects=__importMesh(scene, io, os.path.dirname(filename))
+ mesh_objects=__importMaterialAndMesh(io, tex_dir, toonMaterial)
for o in mesh_objects:
bl.object.makeParent(root, o)
# import armature
- armature_object=__importArmature(scene, io)
+ armature_object=__importArmature(io)
if armature_object:
bl.object.makeParent(root, armature_object)
armature = bl.object.getData(armature_object)
poseBoneLimit(n, b)
# import rigid bodies
- rigidBodies=__importRigidBodies(scene, io)
+ rigidBodies=__importRigidBodies(io)
if rigidBodies:
bl.object.makeParent(root, rigidBodies)
# import constraints
- constraints=__importConstraints(scene, io)
+ constraints=__importConstraints(io)
if constraints:
bl.object.makeParent(root, constraints)
if isBlender24():
# for 2.4
def execute_24(filename):
- scene=bpy.data.scenes.active
- bl.initialize('pmd_import', scene)
- __execute(
- filename.decode(bl.INTERNAL_ENCODING),
- scene)
+ bl.initialize('pmd_import', bpy.data.scenes.active)
+ _execute(filename.decode(bl.INTERNAL_ENCODING))
bl.finalize()
Blender.Window.FileSelector(
Blender.sys.makename(ext='.pmd'))
else:
- # for 2.5
- def execute_25(filename, scene):
- bl.initialize('pmd_import', scene)
- __execute(filename, scene)
- bl.finalize()
-
# import operator
class IMPORT_OT_pmd(bpy.types.Operator):
bl_idname = "import_scene.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 importing 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.")
+ filepath = bpy.props.StringProperty()
+ filename = bpy.props.StringProperty()
+ directory = bpy.props.StringProperty()
def execute(self, context):
- execute_25(self.properties.path, context.scene)
+ bl.initialize('pmd_import', context.scene)
+ _execute(self.properties.filepath)
+ bl.finalize()
return 'FINISHED'
def invoke(self, context, event):
# register menu
def menu_func(self, context):
self.layout.operator(IMPORT_OT_pmd.bl_idname,
- text="MikuMikuDance model (.pmd)")
+ text="MikuMikuDance model (.pmd)",
+ icon='PLUGIN'
+ )
def register():
bpy.types.register(IMPORT_OT_pmd)