Tooltip: 'Import PMD file for MikuMikuDance.'
"""
__author__= ["ousttrue"]
-__version__= "1.2"
+__version__= "1.8"
__url__=()
__bpydoc__="""
pmd Importer
This script imports a pmd into Blender for editing.
-0.1: 20091126: first implement.
-0.2: 20091209: implement IK.
-0.3: 20091210: implement morph target.
-0.4: 20100305: use english name.
-0.5: 20100408: cleanup not used vertices.
-0.6: 20100416: fix fornt face. texture load fail safe. add progress.
-0.7: 20100506: C extension.
-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.
-1.3: 20100619: fix for various models.
-1.4: 20100623: fix constraint name.
-1.5: 20100626: refactoring.
+0.1 20091126: first implement.
+0.2 20091209: implement IK.
+0.3 20091210: implement morph target.
+0.4 20100305: use english name.
+0.5 20100408: cleanup not used vertices.
+0.6 20100416: fix fornt face. texture load fail safe. add progress.
+0.7 20100506: C extension.
+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.
+1.3 20100619: fix for various models.
+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.
"""
MMD_SHAPE_GROUP_NAME='_MMD_SHAPE'
#material.setSpecSize(0)
#material.setSpec(0)
# shader
- material.setDiffuseShader(Blender.Material.Shaders.DIFFUSE_TOON)
- material.setSpecShader(Blender.Material.Shaders.SPEC_TOON)
# diffuse
+ material.setDiffuseShader(Blender.Material.Shaders.DIFFUSE_TOON)
material.setRGBCol([m.diffuse.r, m.diffuse.g, m.diffuse.b])
material.setAlpha(m.diffuse.a)
# specular
+ material.setSpecShader(Blender.Material.Shaders.SPEC_TOON)
material.setSpec(m.shinness*0.1)
material.setSpecCol([m.specular.r, m.specular.g, m.specular.b])
# ambient
elif n.startswith("ankle_"):
b.lockYRot=True
+ def setSphereMap(material, index, blende_type=None):
+ pass
+
else:
# for 2.5
import bpy
def createPmdMaterial(m, index):
material = bpy.data.materials.new("Material")
- # set shader
- material.diffuse_shader='FRESNEL'
- material.specular_shader='TOON'
# diffuse
+ material.diffuse_shader='FRESNEL'
material.diffuse_color=([m.diffuse.r, m.diffuse.g, m.diffuse.b])
material.alpha=m.diffuse.a
# specular
- material.specular_hardness=int(m.shinness)
+ material.specular_shader='TOON'
material.specular_color=([m.specular.r, m.specular.g, m.specular.b])
+ material.specular_toon_size=int(m.shinness)
# ambient
material.mirror_color=([m.ambient.r, m.ambient.g, m.ambient.b])
# flag
material.subsurface_scattering.enabled=True if m.flag==1 else False
- # name
+ # other
material.name="m_%02d" % index
+ material.preview_render_type='FLAT'
+ material.transparency=True
return material
def poseBoneLimit(n, b):
#b.ik_dof_y=False
pass
+ def setSphereMap(material, index, blend_type='MULTIPLY'):
+ slot=material.texture_slots[index]
+ slot.texture_coordinates='NORMAL'
+ slot.mapping='SPHERE'
+ 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
return (pos.x, pos.z, pos.y)
-def convert_uv(uv):
- return (uv.x, 1.0 - uv.y)
-
-
def to_radian(degree):
return math.pi * degree / 180
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('ToonTextures')
+ material=bl.material.create('ToonTextures')
+ 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
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)
############################################################
break
material=createPmdMaterial(m, material_index)
+ toon_index=bl.material.addTexture(
+ material,
+ bl.material.getTexture(
+ toon_material,
+ 0 if m.toon_index==0xFF else m.toon_index
+ ).texture,
+ False)
texture_name=m.getTexture()
if texture_name!='':
- if texture_name in textureMap:
- texture=textureMap[texture_name]
- else:
- try:
- texture, image=bl.texture.create(
- os.path.join(tex_dir, texture_name))
+ for i, t in enumerate(texture_name.split('*')):
+ if t in textureMap:
+ texture=textureMap[t]
+ else:
+ path=os.path.join(tex_dir, t)
+ texture, image=bl.texture.create(path)
textureMap[texture_name]=texture
imageMap[material_index]=image
- except:
- continue
- bl.material.addTexture(material, texture)
+ texture_index=bl.material.addTexture(material, texture)
+ if t.endswith('sph'):
+ # sphere map
+ setSphereMap(material, texture_index)
+ elif t.endswith('spa'):
+ # sphere map
+ setSphereMap(material, texture_index, 'ADD')
+
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]
if io.indices[i] in shape_key_used_vertices:
return True
- # shapeキーで使われるマテリアルを記録する
- shape_key_materials=set()
+ material_with_shape=set()
+
# 各マテリアルの開始頂点インデックスを記録する
face_map={}
face_count=0
for i, m in enumerate(io.materials):
face_map[i]=face_count
if isMaterialUsedInShape(face_count, m):
- shape_key_materials.add(i)
+ material_with_shape.add(i)
face_count+=m.vertex_count
- # list化
- material_order=list(shape_key_materials)
+ # shapeキーで使われる頂点のあるマテリアル
+ material_with_shape=list(material_with_shape)
+ material_with_shape.sort()
- # shapeキーに使われていないマテリアルを後ろに追加
+ # shapeキーに使われていないマテリアル
+ material_without_shape=[]
for i in range(len(io.materials)):
- if not i in material_order:
- material_order.append(i)
+ if not i in material_with_shape:
+ material_without_shape.append(i)
- # ã\83\9eã\83\86ã\83ªã\82¢ã\83«16å\80\8bã\81\94ã\81¨ã\81«å\88\86å\89²ã\81\97ã\81\9fã\83¡ã\83\83ã\82·ã\83¥ã\82\92ä½\9cæ\88\90ã\81\99ã\82\8b
- material_offset=0
- mesh_objects=[]
- while material_offset<len(io.materials):
- mesh, meshObject=bl.mesh.create('mesh')
- # create object
- mesh_objects.append(meshObject)
+ # ã\83¡ã\83\83ã\82·ã\83¥ã\81®ç\94\9fæ\88\90
+ def __splitList(l, length):
+ for i in range(0, len(l), length):
+ yield l[i:i+length]
+
+ def __importMeshAndShape(material16, name):
+ mesh, meshObject=bl.mesh.create(name)
# activate object
bl.object.deselectAll()
# shapeキーで使われる順に並べなおしたマテリアル16個分の
# メッシュを作成する
vertex_map=__import16MaerialAndMesh(
- meshObject, io,
- material_order[material_offset:material_offset+16],
- face_map, tex_dir)
+ meshObject, io, material16, face_map, tex_dir, toon_material)
# crete shape key
__importShape(meshObject, io, vertex_map)
mesh.update()
- material_offset+=16
-
+ return meshObject
+
+ mesh_objects=[__importMeshAndShape(material16, 'with_shape')
+ for material16 in __splitList(material_with_shape, 16)]
+
+ mesh_objects+=[__importMeshAndShape(material16, 'mesh')
+ for material16 in __splitList(material_without_shape, 16)]
+
return mesh_objects
-def __importConstraints(scene, io):
+def __importConstraints(io):
if isBlender24():
return
print("create constraint")
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")
else:
assert(False)
- meshObject=scene.objects.active
+ meshObject=bl.object.getActive()
mesh=bl.object.getData(meshObject)
rigidMeshes.append(meshObject)
bl.mesh.addMaterial(mesh, material)
return container
-def __execute(filename, scene):
+def _execute(filename):
"""
load pmd file to context.
"""
model_name=io.getName()
root=bl.object.createEmpty(model_name)
+ # 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"
description="Directory of the file.")
def execute(self, context):
- execute_25(self.properties.path, context.scene)
+ bl.initialize('pmd_import', context.scene)
+ _execute(self.properties.path)
+ bl.finalize()
return 'FINISHED'
def invoke(self, context, event):