Tooltip: 'Import PMD file for MikuMikuDance.'
"""
__author__= ["ousttrue"]
-__version__= "0.7"
+__version__= "1.0"
__url__=()
__bpydoc__="""
0.1: 20091126
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).
"""
import Blender
from Blender import Mathutils
INTERNAL_ENCODING=FS_ENCODING
+MMD_SHAPE_GROUP_NAME='_MMD_SHAPE'
+
+
+###############################################################################
+# ProgressBar
+###############################################################################
class ProgressBar(object):
def __init__(self, base):
print "#### %s ####" % base
print message
message="%s: %s" % (self.base, message)
if message.__class__ is unicode:
- message=message.encode(INTERNAL_ENCODING)
+ message=message.encode(FS_ENCODING)
Blender.Window.DrawProgressBar(self.progress, message)
def finish(self):
progressBar.set(message, progress)
+###############################################################################
+# functions
+###############################################################################
def convert_coord(pos):
"""
Left handed y-up to Right handed z-up
shape_key_materials.add(i)
face_count+=m.vertex_count
- # shapeキーで使われるマテリアルを前に並べるインデックスマップを作る
- material_map={}
- used_index=0
- not_used_index=len(shape_key_materials)
- for i, m in enumerate(l.materials):
- if i in shape_key_materials:
- material_map[i]=used_index
- used_index+=1
- else:
- material_map[i]=not_used_index
- not_used_index+=1
+ # list化
+ material_order=list(shape_key_materials)
+
+ # shapeキーに使われていないマテリアルを後ろに追加
+ for i in range(len(l.materials)):
+ if not i in material_order:
+ material_order.append(i)
# マテリアル16個ごとに分割したメッシュを作成する
- material_index=0
+ material_offset=0
mesh_objects=[]
- while material_index<len(l.materials):
+ while material_offset<len(l.materials):
# create mesh
mesh = Blender.Mesh.New()
mesh.vertexUV = 1
# メッシュを作成する
vertex_map=import16MaerialAndMesh(
mesh, l,
- material_index, material_map, face_map, tex_dir)
+ material_order[material_offset:material_offset+16],
+ face_map, tex_dir)
# crete shape key
- importShape(mesh, l, vertex_map)
+ importShape(obj, l, vertex_map)
mesh.update()
- material_index+=16
+ material_offset+=16
return mesh_objects
-def import16MaerialAndMesh(mesh, l,
- material_offset, material_map, face_map, tex_dir):
+def import16MaerialAndMesh(mesh, l, material_order, face_map, tex_dir):
############################################################
# material
############################################################
mesh_material_map={}
materials=[]
index=0
- for i in xrange(material_offset, material_offset+16):
+ for material_index in material_order:
try:
- material_index=material_map[i]
m=l.materials[material_index]
mesh_material_map[material_index]=index
except KeyError:
material=createMaterial()
material.setRGBCol([m.diffuse.r, m.diffuse.g, m.diffuse.b])
material.setAlpha(m.diffuse.a)
- material.setHardness(int(m.shinness))
+ material.setSpec(m.shinness*0.1)
material.setSpecCol([m.specular.r, m.specular.g, m.specular.b])
material.setMirCol([m.ambient.r, m.ambient.g, m.ambient.b])
+ material.enableSSS=True if m.flag==1 else False
# set texture
if m.getTexture()!='':
tex_file=re.compile('\*.*.spa$').sub('', m.getTexture())
mesh_face_indices=[]
mesh_face_materials=[]
used_vertices=set()
- for i in xrange(material_offset, material_offset+16):
- try:
- material_index=material_map[i]
- except KeyError:
- break
+
+ def degenerate(i0, i1, i2):
+ return i0==i1 or i1==i2 or i2==i0
+
+ for material_index in material_order:
face_offset=face_map[material_index]
m=l.materials[material_index]
material_faces=l.indices[face_offset:face_offset+m.vertex_count]
i0=material_faces[j]
i1=material_faces[j+1]
i2=material_faces[j+2]
- mesh_face_indices.append([i0, i1, i2])
+ triangle=[i0, i1, i2]
+ if degenerate(*triangle):
+ continue
+ mesh_face_indices.append(triangle)
mesh_face_materials.append(material_index)
used_vertices.add(i0)
used_vertices.add(i1)
used_vertices.add(i2)
+
mesh.faces.extend(mesh_face_indices, ignoreDups=True)
- assert(len(mesh.faces)==len(mesh_face_indices))
# face params
used_map={}
return vertex_map
-def build_bone(armature, b, parent=None):
- if b.tail_index==0:
- return
+class Builder(object):
+ def __init__(self):
+ self.boneMap={}
+
+ def build(self, armature, bones):
+ for b in bones:
+ if not b.parent:
+ self.__build(armature, b, None, None)
+ armature.update()
+
+ def __build(self, armature, b, p, parent):
+ name=englishmap.getEnglishBoneName(b.getName())
+ if not name:
+ name=b.getName().encode(INTERNAL_ENCODING)
+ self.boneMap[name]=b
+
+ bone=Blender.Armature.Editbone()
+ bone.name=name
+ armature.bones[name]=bone
+
+ if b.tail_index==0:
+ # 先端
+ assert(b.type==6 or b.type==7)
+ bone.head = Mathutils.Vector(*convert_coord(b.pos))
+ bone.tail=bone.head+Mathutils.Vector(0, 1, 0)
+ assert(parent)
+ bone.parent=parent
+ if bone.name=="center_t":
+ # センターボーンは(0, 1, 0)の方向を向いていないと具合が悪い
+ parent.tail=parent.head+Mathutils.Vector(0, 1, 0)
+ bone.head=parent.tail
+ bone.tail=bone.head+Mathutils.Vector(0, 1, 0)
+ else:
+ assert(parent.tail==bone.head)
+ bone.options=[Blender.Armature.CONNECTED]
+ # armature layer 2
+ bone.layerMask = (1<<1)
+ else:
+ bone.head = Mathutils.Vector(*convert_coord(b.pos))
+ bone.tail = Mathutils.Vector(*convert_coord(b.tail))
+ if parent:
+ bone.parent=parent
+ if parent.tail==bone.head:
+ bone.options=[Blender.Armature.CONNECTED]
- bone = Blender.Armature.Editbone()
- name=englishmap.getEnglishBoneName(b.getName())
- bone.name = name if name else b.getName().encode(
- INTERNAL_ENCODING)
- armature.bones[bone.name] = bone
- if parent:
- bone.head = Mathutils.Vector(*convert_coord(b.pos))
- bone.parent=parent
- options=[]
- if parent.tail==bone.head:
- options.append(Blender.Armature.CONNECTED)
- bone.options=options
- bone.tail = Mathutils.Vector(*convert_coord(b.tail))
if bone.head==bone.tail:
- bone.tail=bone.head-Mathutils.Vector(0, 1, 0)
- elif b.__class__ is pmd.BONE_IK:
- bone.head = Mathutils.Vector(*convert_coord(b.pos))
- bone.tail = Mathutils.Vector(*convert_coord(b.tail))
- else:
- # center
- tail=Mathutils.Vector(*convert_coord(b.pos))
- bone.tail = tail
- bone.head = tail-Mathutils.Vector(0, 1, 0)
+ bone.tail=bone.head+Mathutils.Vector(0, 1, 0)
- for child in b.children:
- build_bone(armature, child, bone)
+ for c in b.children:
+ self.__build(armature, c, b, bone)
def importArmature(scene, l):
armature_object.drawMode | Blender.Object.DrawModes.XRAY)
# armature settings
armature.drawType = Blender.Armature.OCTAHEDRON
+ armature.drawNames=True
armature.envelopes = False
armature.vertexGroups = True
armature.mirrorEdit = True
# create armature
armature.makeEditable()
- for b in l.bones:
- if not b.parent:
- build_bone(armature, b)
- armature.update()
+
+ ############################################################
+ # build bone
+ ############################################################
+ builder=Builder()
+ builder.build(armature, l.bones)
############################################################
# IK
for ik in l.ik_list:
# IKtarget->parent(=IK).name
target=l.bones[ik.target]
- parent=l.bones[target.parent_index]
- name = englishmap.getEnglishBoneName(parent.getName())
+ name = englishmap.getEnglishBoneName(target.getName())
p_bone = pose.bones[name]
if not p_bone:
print 'not found', name
if len(ik.children) >= 16:
print 'over MAX_CHAINLEN', ik, len(ik.children)
continue
- ik_const = p_bone.constraints.append(Blender.Constraint.Type.IKSOLVER)
- ik_const[cSetting.CHAINLEN] = len(ik.children)
- ik_const[cSetting.TARGET] = armature_object
- ik_const[cSetting.BONE] = englishmap.getEnglishBoneName(
+ # IK solver
+ ik_solver = p_bone.constraints.append(Blender.Constraint.Type.IKSOLVER)
+ ik_solver[cSetting.CHAINLEN]=len(ik.children)
+ ik_solver[cSetting.TARGET]=armature_object
+ ik_solver[cSetting.USETIP]=False
+
+ effector_name=englishmap.getEnglishBoneName(
l.bones[ik.index].getName())
- lrot_const = p_bone.constraints.append(Blender.Constraint.Type.LIMITROT)
- lrot_const.influence = ik.weight
- lrot_const[cSetting.OWNERSPACE] = cSetting.SPACE_LOCAL
- lrot_const[cSetting.LIMIT] = (cSetting.LIMIT_XROT | cSetting.LIMIT_ZROT)
- lrot_const[cSetting.XMIN] = ik.iterations
- lrot_const[cSetting.XMAX] = 180
- lrot_const[cSetting.ZMIN] = 180 - ik.iterations
- lrot_const[cSetting.ZMAX] = 0
+ if not effector_name:
+ effector_name=l.bones[ik.index].getName()
+
+ ik_solver[cSetting.BONE]=effector_name
+ #ik_solver.influence=ik.weight
+ # not used. place folder when export.
+ ik_solver[cSetting.ROTWEIGHT]=ik.weight
+ ik_solver[cSetting.ITERATIONS]=ik.iterations * 10
armature.makeEditable()
armature.update()
return armature_object
-def importShape(mesh, l, vertex_map):
+def importShape(obj, l, vertex_map):
if len(l.morph_list)==0:
return
- # base
+ obj.pinShape=True
+ mesh=obj.getData(mesh=True)
+
+ # find base
base=None
for s in l.morph_list:
- if s.type!=0:
- continue
- base=s
- break
+ if s.type==0:
+ base=s
+
+ # create vertex group
+ mesh.addVertGroup(MMD_SHAPE_GROUP_NAME)
+ indices=[]
+ hasShape=False
+ for i in s.indices:
+ if i in vertex_map:
+ hasShape=True
+ indices.append(vertex_map[i])
+ mesh.assignVertsToGroup(MMD_SHAPE_GROUP_NAME, indices, 0,
+ Blender.Mesh.AssignModes.ADD)
+ if not hasShape:
+ return
+
+ # create base key
+ mesh.insertKey()
+ assert(len(mesh.key.blocks)==1)
+ baseShapeIndex=0
+ baseShapeBlock=mesh.key.blocks[baseShapeIndex]
+ baseShapeBlock.name='Basis'
+ obj.activeShape=baseShapeIndex
+ mesh.update()
+ break
+
assert(base)
- mesh.insertKey()
- baseblock=mesh.key.blocks[-1]
- ipo=Blender.Ipo.New('Key', 'pmd')
- mesh.key.ipo=ipo
# each skin
for s in l.morph_list:
if s.name==base.name:
continue
- name=englishmap.getEnglishSkinName(s.getName())
- if not name:
- name=s.getName().encode(INTERNAL_ENCODING)
+
for index, offset in zip(s.indices, s.pos_list):
try:
vertex_index=vertex_map[base.indices[index]]
v[1]+=offset[1]
v[2]+=offset[2]
except IndexError, msg:
- print IndexError, msg
- print index, len(base.indices)
- print vertex_index, len(mesh.verts)
+ print msg
+ print index, len(base.indices), len(vertex_map)
+ print len(mesh.verts)
print base.indices[index]
+ print vertex_index
break
except KeyError:
#print 'this mesh not has shape vertices'
break
-
- # set shapekey block
- mesh.update()
+
+ # get skin name
+ name=englishmap.getEnglishSkinName(s.getName())
+ if not name:
+ name=s.getName().encode(INTERNAL_ENCODING)
+ print(name)
+
+ # create shapekey block
mesh.insertKey()
- mesh.key.blocks[-1].name=name
+ shapeIndex=len(mesh.key.blocks)-1
+ keyBlock=mesh.key.blocks[shapeIndex]
+ keyBlock.name=name
- # set ipo curve
- icu=ipo.addCurve(name)
- icu.interpolation = Blender.IpoCurve.InterpTypes.LINEAR
- icu.append( (0.0, 0.0) )
+ # copy vertex to shape key
+ mesh.update()
# restore
- for mv, v in zip(mesh.verts, baseblock.getData()):
+ for mv, v in zip(mesh.verts, baseShapeBlock.getData()):
mv.co[0] = v[0]
mv.co[1] = v[1]
mv.co[2] = v[2]
mesh.update()
+ # select base shape
+ obj.activeShape=baseShapeIndex
def run(filename):
"""
# load pmd
progress_set('load %s' % filename, 0.0)
- import locale
- locale.setlocale(locale.LC_ALL, '')
-
l=pmd.IO()
if not l.read(filename):
print "fail to load %s" % filename
# import objects container
root=scene.objects.new("Empty")
root.setName(
- l.english_model_name if len(l.english_model_name)>0 else l.getName().encode(INTERNAL_ENCODING))
+ l.english_name if len(l.english_name)>0 else l.getName().encode(INTERNAL_ENCODING))
# import mesh
mesh_objects=importMesh(scene, l, tex_dir)
armature_object=importArmature(scene, l)
if armature_object:
armature = armature_object.getData()
- armature.drawNames=True
root.makeParent([armature_object])
# add armature modifier
mod=o.modifiers.append(Blender.Modifier.Types.ARMATURE)
mod[Blender.Modifier.Settings.OBJECT] = armature_object
mod[Blender.Modifier.Settings.ENVELOPES] = False
- o.makeDisplayList()
-
+ #o.makeDisplayList()
+
+ ############################################################
+ # Limitation
+ ############################################################
+ for n, b in armature_object.getPose().bones.items():
+ if n.endswith("_t"):
+ continue
+
+ if n.startswith("knee_"):
+ b.lockYRot=True
+ b.lockZRot=True
+ b.limitX=True
+ b.limitMin=[0, 0, 0]
+ b.limitMax=[180, 0, 0]
+ elif n.startswith("ankle_"):
+ b.lockYRot=True
+
# redraw
scene.update(0)