Tooltip: 'Import PMD file for MikuMikuDance.'
"""
__author__= ["ousttrue"]
-__version__= "1.1"
+__version__= "2.0"
__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.
+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.
+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'
+#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 os
import sys
-import re
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
# wrapper
import bl24 as bl
+
+ def createPmdMaterial(m, index):
+ material=Blender.Material.New()
+ # 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)
+ # 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
+ material.setMirCol([m.ambient.r, m.ambient.g, m.ambient.b])
+ # flag
+ material.enableSSS=True if m.flag==1 else False
+ # name
+ material.name="m_%02d" % index
+ return material
+
+ def poseBoneLimit(n, b):
+ if n.endswith("_t"):
+ return
+ 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
+
+ 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
import bl25 as bl
+ 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)
-
-
-if isBlender24():
- # functions
- def convert_coord(pos):
- """
- Left handed y-up to Right handed z-up
- """
- return (pos.x, pos.z, pos.y)
-
+ def createPmdMaterial(m, index):
+ material = bpy.data.materials.new("Material")
+ # 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_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
+ # other
+ material.name="m_%02d" % index
+ material.preview_render_type='FLAT'
+ material.transparency=True
+ return material
- def convert_uv(uv):
- return (uv.x, 1.0 - uv.y)
+ def poseBoneLimit(n, b):
+ if n.endswith("_t"):
+ return
+ if n.startswith("knee_"):
+ b.ik_dof_y=False
+ b.ik_dof_z=False
+ b.ik_dof_x=True
+ b.ik_limit_x=True
+ b.ik_min_x=0
+ b.ik_max_x=180
+ elif n.startswith("ankle_"):
+ #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 get_bone_name(l, index):
- name=englishmap.getEnglishBoneName(l.bones[index].getName())
- return name if name else l.bones[index].getName().encode(bl.INTERNAL_ENCODING)
+###############################################################################
+def VtoV(v):
+ return bl.createVector(v.x, v.y, v.z)
- def createMaterial():
- """
- create default materil
- """
- material=Blender.Material.New()
- material.setDiffuseShader(Blender.Material.Shaders.DIFFUSE_TOON)
- material.setRef(1)
- material.diffuseSize = 3.14/2
- material.setDiffuseSmooth(0)
- material.setSpecShader(Blender.Material.Shaders.SPEC_TOON)
- material.setSpecSize(0)
- material.setSpec(0)
- return material
+def convert_coord(pos):
+ """
+ Left handed y-up to Right handed z-up
+ """
+ return (pos.x, pos.z, pos.y)
- def importMesh(scene, l, tex_dir):
- """
- @param l[in] mmd.PMDLoader
- @param filename[in]
- """
-
- ############################################################
- # shpaeキーで使われるマテリアル優先的に前に並べる
- ############################################################
- # shapeキーで使われる頂点インデックスを集める
- shape_key_used_vertices=set()
- if len(l.morph_list)>0:
- # base
- base=None
- for s in l.morph_list:
- if s.type!=0:
- continue
- base=s
- break
- assert(base)
-
- for index in base.indices:
- shape_key_used_vertices.add(index)
-
- # マテリアルに含まれる頂点がshape_keyに含まれるか否か?
- def isMaterialUsedInShape(offset, m):
- for i in xrange(offset, offset+m.vertex_count):
- if l.indices[i] in shape_key_used_vertices:
- return True
-
- # shapeキーで使われるマテリアルを記録する
- shape_key_materials=set()
- # 各マテリアルの開始頂点インデックスを記録する
- face_map={}
- face_count=0
- for i, m in enumerate(l.materials):
- face_map[i]=face_count
- if isMaterialUsedInShape(face_count, m):
- shape_key_materials.add(i)
- face_count+=m.vertex_count
-
- # 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_offset=0
- mesh_objects=[]
- while material_offset<len(l.materials):
- # create mesh
- mesh = Blender.Mesh.New()
- mesh.vertexUV = 1
- # create object
- obj = scene.objects.new(mesh)
- obj.layers = [1]
- mesh_objects.append(obj)
-
- # shapeキーで使われる順に並べなおしたマテリアル16個分の
- # メッシュを作成する
- vertex_map=import16MaerialAndMesh(
- mesh, l,
- material_order[material_offset:material_offset+16],
- face_map, tex_dir)
-
- # crete shape key
- importShape(obj, l, vertex_map)
+def to_radian(degree):
+ return math.pi * degree / 180
- mesh.update()
- material_offset+=16
-
- return mesh_objects
-
-
- def import16MaerialAndMesh(mesh, l, material_order, face_map, tex_dir):
- ############################################################
- # material
- ############################################################
- progress_print('create materials')
- mesh_material_map={}
- materials=[]
- index=0
- for material_index in material_order:
- try:
- m=l.materials[material_index]
- mesh_material_map[material_index]=index
- except KeyError:
- break
-
- material=createMaterial()
- material.setRGBCol([m.diffuse.r, m.diffuse.g, m.diffuse.b])
- material.setAlpha(m.diffuse.a)
- 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())
- tex_path = os.path.join(tex_dir, tex_file).encode(
- bl.INTERNAL_ENCODING)
- tex = Blender.Texture.New()
- tex.setType("Image")
- try:
- tex.image = Blender.Image.Load(tex_path)
- material.setTexture(0, tex)
- material.getTextures()[0].texco = Blender.Texture.TexCo.UV
- except IOError:
- print(material.name, "fail to load", tex_path)
- materials.append(material)
- # lookup table for assign
- index+=1
- mesh.materials=materials
-
- ############################################################
- # vertex
- ############################################################
- progress_print('create vertices')
- # create vertices
- vertex_groups={}
- vertices=[]
- for v in l.each_vertex():
- vertices.append(convert_coord(v.pos))
- vertex_groups[v.bone0]=True
- vertex_groups[v.bone1]=True
- mesh.verts.extend(vertices)
-
- # create vertex group
- for i in vertex_groups.keys():
- mesh.addVertGroup(get_bone_name(l, i))
-
- # vertex params
- for i, v, mvert in zip(xrange(len(l.vertices)), l.each_vertex(), mesh.verts):
- mvert.no=Mathutils.Vector(*convert_coord(v.normal))
- mvert.uvco=convert_uv(v.uv)
- w1=float(v.weight0)/100.0
- w2=1.0-w1
- mesh.assignVertsToGroup(get_bone_name(l, v.bone0), [i], w1,
- Blender.Mesh.AssignModes.ADD)
- mesh.assignVertsToGroup(get_bone_name(l, v.bone1), [i], w2,
- Blender.Mesh.AssignModes.ADD)
-
- ############################################################
- # face
- ############################################################
- progress_print('create faces')
- # create faces
- mesh_face_indices=[]
- mesh_face_materials=[]
- used_vertices=set()
- def degenerate(i0, i1, i2):
- return i0==i1 or i1==i2 or i2==i0
+def get_bone_name(l, index):
+ if index==0xFFFF:
+ return l.bones[0].getName()
- 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]
- for j in xrange(0, len(material_faces), 3):
- i0=material_faces[j]
- i1=material_faces[j+1]
- i2=material_faces[j+2]
- 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)
-
- # face params
- used_map={}
- mesh.addUVLayer('NewUV')
- for face, material_index in zip(mesh.faces, mesh_face_materials):
- try:
- index=mesh_material_map[material_index]
- except KeyError as message:
- print(message, mesh_material_map, m)
- assert(False)
- face.mat=index
- material=mesh.materials[index]
- texture=material.getTextures()[0]
- used_map[index]=True
- if texture:
- face.image=texture.tex.image
- texture.tex.imageFlags|=Blender.Texture.ImageFlags.USEALPHA
- face.uv=[face.verts[0].uvco, face.verts[1].uvco, face.verts[2].uvco]
- # set smooth
- face.smooth = 1
- # flip
- mesh.flipNormals()
-
- ############################################################
- # clean up not used vertices
- ############################################################
- progress_print('clean up vertices not used')
- remove_vertices=[]
- vertex_map={}
- for i, v in enumerate(l.each_vertex()):
- if i in used_vertices:
- vertex_map[i]=len(vertex_map)
- else:
- remove_vertices.append(i)
- mesh.verts.delete(remove_vertices)
-
- progress_print('%s created' % mesh.name)
- return vertex_map
-
-
- 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(bl.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]
-
- if bone.head==bone.tail:
- bone.tail=bone.head+Mathutils.Vector(0, 1, 0)
-
- for c in b.children:
- self.__build(armature, c, b, bone)
-
-
- def importArmature(scene, l):
- # create armature
- armature = Blender.Armature.New()
- # link to object
- armature_object = scene.objects.new(armature)
- # create action
- act = Blender.Armature.NLA.NewAction()
- act.setActive(armature_object)
- # set XRAY
- armature_object.drawMode = (
- 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()
-
- ############################################################
- # build bone
- ############################################################
- builder=Builder()
- builder.build(armature, l.bones)
-
- ############################################################
- # IK
- ############################################################
- pose = armature_object.getPose()
- cSetting = Blender.Constraint.Settings
- for ik in l.ik_list:
- # IKtarget->parent(=IK).name
- target=l.bones[ik.target]
- name = englishmap.getEnglishBoneName(target.getName())
- p_bone = pose.bones[name]
- if not p_bone:
- print('not found', name)
- continue
- if len(ik.children) >= 16:
- print('over MAX_CHAINLEN', ik, len(ik.children))
- continue
- # 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())
- 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(obj, l, vertex_map):
- if len(l.morph_list)==0:
- return
- obj.pinShape=True
- mesh=obj.getData(mesh=True)
-
- # find base
- base=None
- for s in l.morph_list:
- 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
+ if index < len(l.bones):
+ name=englishmap.getEnglishBoneName(l.bones[index].getName())
+ if name:
+ return name
+ return l.bones[index].getName()
+ 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
- assert(base)
+ # set shape_key pin
+ bl.object.pinShape(obj, True)
- # each skin
- for s in l.morph_list:
- if s.name==base.name:
- continue
+ # find base
+ base=None
+ for s in l.morph_list:
+ if s.type==0:
+ base=s
+ # create vertex group
+ bl.object.addVertexGroup(obj, MMD_SHAPE_GROUP_NAME)
+ hasShape=False
+ for i in s.indices:
+ if i in vertex_map:
+ hasShape=True
+ bl.object.assignVertexGroup(
+ obj, MMD_SHAPE_GROUP_NAME, vertex_map[i], 0)
+ if not hasShape:
+ return
+ assert(base)
+
+ # create base key
+ baseShapeBlock=bl.object.addShapeKey(obj, BASE_SHAPE_NAME)
+ # mesh
+ mesh=bl.object.getData(obj)
+ mesh.update()
+
+ # each skin
+ for s in l.morph_list:
+ if s.type==0:
+ continue
+
+ # name
+ name=englishmap.getEnglishSkinName(s.getName())
+ if not name:
+ name=s.getName()
+
+ if isBlender24():
+ # 24
for index, offset in zip(s.indices, s.pos_list):
try:
vertex_index=vertex_map[base.indices[index]]
v[0]+=offset[0]
v[1]+=offset[1]
v[2]+=offset[2]
- except IndexErrora as msg:
+ except IndexError as msg:
print(msg)
print(index, len(base.indices), len(vertex_map))
print(len(mesh.verts))
#print 'this mesh not has shape vertices'
break
- # get skin name
- name=englishmap.getEnglishSkinName(s.getName())
- if not name:
- name=s.getName().encode(bl.INTERNAL_ENCODING)
- print(name)
-
# create shapekey block
- mesh.insertKey()
- shapeIndex=len(mesh.key.blocks)-1
- keyBlock=mesh.key.blocks[shapeIndex]
- keyBlock.name=name
+ new_shape_key=bl.object.addShapeKey(obj, name)
# copy vertex to shape key
mesh.update()
mv.co[2] = v[2]
mesh.update()
- # select base shape
- obj.activeShape=baseShapeIndex
-
-else:
- # for 2.5
- def to_radian(degree):
- return math.pi * degree / 180
-
-
- 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)
+ else:
+ # 25
+ new_shape_key=bl.object.addShapeKey(obj, name)
+ for index, offset in zip(s.indices, s.pos_list):
+ try:
+ vertex_index=vertex_map[base.indices[index]]
+ bl.shapekey.assign(new_shape_key, vertex_index,
+ mesh.verts[vertex_index].co+
+ bl.createVector(*convert_coord(offset)))
+ except IndexError as msg:
+ 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
- def getBoneName(bone):
- name = englishmap.getEnglishBoneName(bone.getName())
- return name if name else bone.getName()
+ # select base shape
+ bl.object.setActivateShapeKey(obj, 0)
- def create_texture(directory, texture_name):
- texture=bpy.data.textures.new(texture_name)
- texture.type='IMAGE'
- texture=texture.recast_type()
- texturePath=os.path.join(directory, texture_name)
- print('create_texture', texturePath)
- image=bpy.data.images.load(texturePath)
- texture.image=image
- texture.mipmap = True
- texture.interpolation = True
- texture.use_alpha = True
- return texture
+def __build(armature, b, p, parent):
+ name=englishmap.getEnglishBoneName(b.getName())
+ if not name:
+ name=b.getName()
+ bone=bl.armature.createBone(armature, name)
- def createMaterial():
- """
- create default materil
- """
- material = bpy.data.materials.new("Material")
- material.diffuse_shader='TOON'
- material.specular_shader='TOON'
- # temporary
- material.emit=1.0
- return material
+ 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
+ if bone.name=="center_t":
+ # センターボーンは(0, 1, 0)の方向を向いていないと具合が悪い
+ parent.tail=parent.head+bl.createVector(0, 1, 0)
+ bone.head=parent.tail
+ bone.tail=bone.head+bl.createVector(0, 1, 0)
+ else:
+ if parent.tail==bone.head:
+ pass
+ else:
+ print('diffurence with parent.tail and head', name)
+
+ if b.type!=9:
+ bl.bone.setConnected(bone)
+ # armature layer 2
+ bl.bone.setLayerMask(bone, [0, 1])
+ else:
+ # 通常ボーン
+ bone.head = bl.createVector(*convert_coord(b.pos))
+ bone.tail = bl.createVector(*convert_coord(b.tail))
+ if parent:
+ bone.parent=parent
+ if parent.tail==bone.head:
+ bl.bone.setConnected(bone)
+
+ if bone.head==bone.tail:
+ bone.tail=bone.head+bl.createVector(0, 1, 0)
+
+ for c in b.children:
+ __build(armature, c, b, 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.enterObjectMode()
+
+ # IK constraint
+ pose = bl.object.getPose(armature_object)
+ 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)
+ continue
+ if len(ik.children) >= 16:
+ print('over MAX_CHAINLEN', ik, len(ik.children))
+ continue
+ effector_name=englishmap.getEnglishBoneName(
+ l.bones[ik.index].getName())
+ if not effector_name:
+ effector_name=l.bones[ik.index].getName()
+
+ constraint=bl.armature.createIkConstraint(armature_object,
+ p_bone, effector_name, ik)
+
+ bl.armature.makeEditable(armature_object)
+ bl.armature.update(armature)
+ 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, toon_material):
+
+ mesh=bl.object.getData(meshObject)
+ ############################################################
+ # material
+ ############################################################
+ bl.progress_print('create materials')
+ mesh_material_map={}
+ textureMap={}
+ imageMap={}
+ index=0
+
+ for material_index in material_order:
+ try:
+ m=l.materials[material_index]
+ mesh_material_map[material_index]=index
+ except KeyError:
+ break
- def importMesh(scene, l, tex_dir):
- """
- @param l[in] mmd.PMDLoader
- @param filename[in]
- """
-
- ############################################################
- # shpaeキーで使われるマテリアル優先的に前に並べる
- ############################################################
- # shapeキーで使われる頂点インデックスを集める
- shape_key_used_vertices=set()
- if len(l.morph_list)>0:
- # base
- base=None
- for s in l.morph_list:
- if s.type!=0:
- continue
- base=s
- break
- assert(base)
-
- for index in base.indices:
- shape_key_used_vertices.add(index)
-
- # マテリアルに含まれる頂点がshape_keyに含まれるか否か?
- def isMaterialUsedInShape(offset, m):
- for i in range(offset, offset+m.vertex_count):
- if l.indices[i] in shape_key_used_vertices:
- return True
-
- # shapeキーで使われるマテリアルを記録する
- shape_key_materials=set()
- # 各マテリアルの開始頂点インデックスを記録する
- face_map={}
- face_count=0
- for i, m in enumerate(l.materials):
- face_map[i]=face_count
- if isMaterialUsedInShape(face_count, m):
- 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
-
- # マテリアル16個ごとに分割したメッシュを作成する
- material_index=0
- mesh_objects=[]
- while material_index<len(l.materials):
- # shapeキーで使われる順に並べなおしたマテリアル16個分の
- # メッシュを作成する
- meshObject, used_vertices=import16MaerialAndMesh(l,
- material_index, material_map, face_map, tex_dir)
- scene.objects.link(meshObject)
- scene.update()
- mesh_objects.append(meshObject)
-
- # enter Edit Mode
- bpy.ops.object.select_all(action='DESELECT')
- meshObject.selected=True
- scene.objects.active=meshObject
- bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
-
- # crete shape key
- importShape(meshObject, l)
-
- ############################################################
- # clean up not used vertices
- ############################################################
- #progress_print('clean up vertices not used')
- vertex_map={}
- mesh=meshObject.data
- for i, v in enumerate(mesh.verts):
- if i in used_vertices:
- vertex_map[i]=len(vertex_map)
- v.selected=False
- else:
- v.selected=True
- assert(mesh.verts[i].selected)
- bpy.ops.object.mode_set(mode='EDIT', toggle=False)
- print("%d vertices selected" % mesh.total_vert_sel)
- print("used %d/%d" % (len(vertex_map), len(mesh.verts)))
- bpy.ops.mesh.delete(type='VERT')
-
- ############################################################
- # flip face
- ############################################################
- bpy.ops.mesh.select_all(action='SELECT')
- bpy.ops.mesh.flip_normals()
- bpy.ops.mesh.select_all(action='DESELECT')
-
- # exit Edit Mode
- bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
+ material=createPmdMaterial(m, material_index)
- mesh.update()
- material_index+=16
-
- return mesh_objects
-
-
- def import16MaerialAndMesh(l,
- material_offset, material_map, face_map, tex_dir):
- # create mesh
- mesh=bpy.data.meshes.new("Mesh")
-
- # create object
- meshObject= bpy.data.objects.new("Mesh", mesh)
- meshObject.layers[0]=True
-
- ############################################################
- # material
- ############################################################
- #progress_print('create materials')
- mesh_material_map={}
- materials=[]
- textureMap={}
- imageMap={}
- index=0
- for i in range(material_offset, material_offset+16):
- try:
- material_index=material_map[i]
- m=l.materials[material_index]
- mesh_material_map[material_index]=index
- except KeyError:
- break
-
- material=createMaterial()
- material.diffuse_color=([m.diffuse.r, m.diffuse.g, m.diffuse.b])
- material.alpha=m.diffuse.a
- material.specular_hardness=int(m.shinness)
- material.specular_color=([m.specular.r, m.specular.g, m.specular.b])
- material.mirror_color=([m.ambient.r, m.ambient.g, m.ambient.b])
- texture_name=m.getTexture()
- if texture_name!='':
- if texture_name in textureMap:
- texture=textureMap[texture_name]
+ # main texture
+ texture_name=m.getTexture()
+ if texture_name!='':
+ for i, t in enumerate(texture_name.split('*')):
+ if t in textureMap:
+ texture=textureMap[t]
else:
- texture=create_texture(tex_dir, texture_name)
+ path=os.path.join(tex_dir, t)
+ texture, image=bl.texture.create(path)
textureMap[texture_name]=texture
- imageMap[material_index]=texture.image
- #material.add_texture(texture, "UV", {"COLOR", "ALPHA"})
- material.add_texture(texture, "UV", "COLOR")
-
- materials.append(material)
- mesh.add_material(material)
- # lookup table for assign
- index+=1
-
- ############################################################
- # vertex
- ############################################################
- #progress_print('create vertices')
- # create vertices
- vertex_groups={}
- unpackedVertices=[]
- for v in l.each_vertex():
- unpackedVertices.extend(
- convert_coord(v.pos))
- vertex_groups[v.bone0]=True
- vertex_groups[v.bone1]=True
-
- ############################################################
- # face
- ############################################################
- #progress_print('create faces')
- # create faces
- mesh_face_indices=[]
- mesh_face_materials=[]
- used_vertices=set()
- for i in range(material_offset, material_offset+16):
- try:
- material_index=material_map[i]
- except KeyError:
- break
- face_offset=face_map[material_index]
- m=l.materials[material_index]
- material_faces=l.indices[face_offset:face_offset+m.vertex_count]
- for j in range(0, len(material_faces), 3):
- i0=material_faces[j]
- i1=material_faces[j+1]
- i2=material_faces[j+2]
- if i2==0:
- mesh_face_indices.extend([i2, i0, i1, 0])
- else:
- mesh_face_indices.extend([i0, i1, i2, 0])
- mesh_face_materials.append(material_index)
- used_vertices.add(i0)
- used_vertices.add(i1)
- used_vertices.add(i2)
-
- ############################################################
- # create vertices & faces
- ############################################################
- mesh.add_geometry(
- int(len(unpackedVertices)/3), 0, int(len(mesh_face_indices)/4))
- mesh.verts.foreach_set("co", unpackedVertices)
- mesh.faces.foreach_set("verts_raw", mesh_face_indices)
- assert(len(l.vertices)==len(mesh.verts))
-
- ############################################################
- # face params
- ############################################################
- used_map={}
- mesh.add_uv_texture()
-
- for face, uv_face, material_index in zip(mesh.faces,
- mesh.uv_textures[0].data,
- mesh_face_materials,
- ):
- try:
- index=mesh_material_map[material_index]
- except KeyError as message:
- print(message, mesh_material_map, m)
- assert(False)
- face.material_index=index
- material=mesh.materials[index]
- used_map[index]=True
- if material.texture_slots[0]:
- #texture=material.texture_slots[0].texture
- #face.image=texture.image
- #texture.imageFlags|=Blender.Texture.ImageFlags.USEALPHA
- uv=l.getUV(face.verts[0])
- uv_face.uv1=[uv.x, 1.0-uv.y]
-
- uv=l.getUV(face.verts[1])
- uv_face.uv2=[uv.x, 1.0-uv.y]
-
- uv=l.getUV(face.verts[2])
- uv_face.uv3=[uv.x, 1.0-uv.y]
- if face.material_index in imageMap:
- uv_face.image=imageMap[face.material_index]
- uv_face.tex=True
-
- # set smooth
- face.smooth = 1
-
- ############################################################
- # vertex weight
- ############################################################
- # create vertex group
- for i in vertex_groups.keys():
- meshObject.add_vertex_group(getBoneName(l.bones[i]))
-
- # vertex params
- for i, v, mvert in zip(range(len(l.vertices)),
- l.each_vertex(), mesh.verts):
- mvert.normal=mathutils.Vector(convert_coord(v.normal))
- #mvert.uvco=convert_uv(v.uv)
- w1=float(v.weight0)/100.0
- w2=1.0-w1
-
- meshObject.add_vertex_to_group(i,
- meshObject.vertex_groups[getBoneName(l.bones[v.bone0])], w1, 'ADD')
- meshObject.add_vertex_to_group(i,
- meshObject.vertex_groups[getBoneName(l.bones[v.bone1])], w2, 'ADD')
- mesh.update()
+ imageMap[material_index]=image
+ 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')
+
+ # 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
+
+ ############################################################
+ # vertex
+ ############################################################
+ bl.progress_print('create vertices')
+ # create vertices
+ vertices=[]
+ for v in l.each_vertex():
+ vertices.append(convert_coord(v.pos))
+
+ ############################################################
+ # face
+ ############################################################
+ bl.progress_print('create faces')
+ # create faces
+ mesh_face_indices=[]
+ mesh_face_materials=[]
+ used_vertices=set()
+
+ 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]
- #progress_print('%s created' % mesh.name)
- return meshObject, used_vertices
+ def degenerate(i0, i1, i2):
+ """
+ 縮退しているか?
+ """
+ return i0==i1 or i1==i2 or i2==i0
+ for j in xrange(0, len(material_faces), 3):
+ i0=material_faces[j]
+ i1=material_faces[j+1]
+ i2=material_faces[j+2]
+ # flip
+ triangle=[i2, i1, i0]
+ if degenerate(*triangle):
+ continue
+ mesh_face_indices.append(triangle[0:3])
+ mesh_face_materials.append(material_index)
+ used_vertices.add(i0)
+ used_vertices.add(i1)
+ used_vertices.add(i2)
+
+ ############################################################
+ # create vertices & faces
+ ############################################################
+ bl.mesh.addGeometry(mesh, vertices, mesh_face_indices)
+
+ ############################################################
+ # vertex bone weight
+ ############################################################
+ # create vertex group
+ vertex_groups={}
+ for v in l.each_vertex():
+ vertex_groups[v.bone0]=True
+ vertex_groups[v.bone1]=True
+ for i in vertex_groups.keys():
+ bl.object.addVertexGroup(meshObject, get_bone_name(l, i))
+
+ # vertex params
+ bl.mesh.useVertexUV(mesh)
+ for i, v, mvert in zip(xrange(len(l.vertices)),
+ l.each_vertex(), mesh.verts):
+ # normal, uv
+ bl.vertex.setNormal(mvert, convert_coord(v.normal))
+ # bone weight
+ w1=float(v.weight0)/100.0
+ w2=1.0-w1
+ bl.object.assignVertexGroup(meshObject, get_bone_name(l, v.bone0),
+ i, w1)
+ bl.object.assignVertexGroup(meshObject, get_bone_name(l, v.bone1),
+ i, w2)
+
+ ############################################################
+ # face params
+ ############################################################
+ used_map={}
+ bl.mesh.addUV(mesh)
+ for i, (face, material_index) in enumerate(
+ zip(mesh.faces, mesh_face_materials)):
+ try:
+ index=mesh_material_map[material_index]
+ except KeyError as message:
+ print(message, mesh_material_map, m)
+ assert(False)
+ bl.face.setMaterial(face, index)
+ material=mesh.materials[index]
+ used_map[index]=True
+ if bl.material.hasTexture(material):
+ uv_array=[l.getUV(i) for i in bl.face.getIndices(face)]
+ bl.mesh.setFaceUV(mesh, i, face,
+ # fix uv
+ [(uv.x, 1.0-uv.y) for uv in uv_array],
+ imageMap.get(index, None))
+
+ # set smooth
+ face.smooth = 1
+
+ mesh.update()
+
+ ############################################################
+ # clean up not used vertices
+ ############################################################
+ bl.progress_print('clean up vertices not used')
+ remove_vertices=[]
+ vertex_map={}
+ for i, v in enumerate(l.each_vertex()):
+ if i in used_vertices:
+ vertex_map[i]=len(vertex_map)
+ else:
+ remove_vertices.append(i)
- def build_bone(armature, b, parent=None):
- if b.tail_index==0:
- return
+ bl.mesh.vertsDelete(mesh, remove_vertices)
- name=getBoneName(b)
- bone = armature.edit_bones.new(name if name else b.getName())
- if parent:
- bone.head = mathutils.Vector(convert_coord(b.pos))
- bone.parent=parent
- bone.connected=True if parent.tail==bone.head else False
- 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))
-
- for child in b.children:
- build_bone(armature, child, bone)
-
-
- def importArmature(scene, l):
- # create armature
- armature = bpy.data.armatures.new('Armature')
- # link to object
- armature_object=bpy.data.objects.new('Armature', armature)
- scene.objects.link(armature_object)
- armature_object.x_ray=True
- armature.draw_names=True
-
- # armature settings
- armature.drawtype='OCTAHEDRAL'
- armature.deform_envelope=False
- armature.deform_vertexgroups=True
- armature.x_axis_mirror=True
-
- # create action
- #act = Blender.Armature.NLA.NewAction()
- #act.setActive(armature_object)
-
- # select only armature object and set edit mode
- scene.objects.active=armature_object
- bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
- bpy.ops.object.mode_set(mode='EDIT', toggle=False)
-
- # create armature
- for b in l.bones:
- if not b.parent:
- build_bone(armature, b)
-
- bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
- bpy.ops.object.select_all(action='DESELECT')
-
- ############################################################
- # IK
- ############################################################
- pose = armature_object.pose
- for ik in l.ik_list:
- effector=l.bones[ik.target]
- parent=l.bones[effector.parent_index]
- name=getBoneName(parent)
- p_bone = pose.bones[name]
- if not p_bone:
- print('not found', name)
- continue
- if len(ik.children) >= 16:
- print('over MAX_CHAINLEN', ik, len(ik.children))
- continue
- # IK
- ik_const = p_bone.constraints.new('IK')
- ik_const.chain_length=len(ik.children)
- ik_const.target=armature_object
- ik_const.subtarget=getBoneName(l.bones[ik.index])
- # ROT
- rot_const = p_bone.constraints.new('LIMIT_ROTATION')
- rot_const.influence = ik.weight
- rot_const.owner_space = 'LOCAL'
- rot_const.use_limit_x=True
- rot_const.use_limit_z=True
- rot_const.minimum_x=to_radian(ik.iterations)
- rot_const.maximum_x=to_radian(180)
- rot_const.minimum_z=to_radian(180 - ik.iterations)
- rot_const.maximum_z=to_radian(0)
-
- return armature_object
-
+ bl.progress_print('%s created' % mesh.name)
+ return vertex_map
- def importShape(meshObject, l):
- if len(l.morph_list)==0:
- return
+def __importMaterialAndMesh(io, tex_dir, toon_material):
+ """
+ @param l[in] mmd.PMDLoader
+ @param filename[in]
+ """
+ ############################################################
+ # shpaeキーで使われるマテリアル優先的に前に並べる
+ ############################################################
+ # shapeキーで使われる頂点インデックスを集める
+ shape_key_used_vertices=set()
+ if len(io.morph_list)>0:
# base
base=None
- for s in l.morph_list:
+ for s in io.morph_list:
if s.type!=0:
continue
base=s
break
assert(base)
- # create base key
- baseblock=meshObject.add_shape_key("Basis")
+ for index in base.indices:
+ shape_key_used_vertices.add(index)
- # mesh
- mesh=meshObject.data
+ # マテリアルに含まれる頂点がshape_keyに含まれるか否か?
+ def isMaterialUsedInShape(offset, m):
+ for i in xrange(offset, offset+m.vertex_count):
+ if io.indices[i] in shape_key_used_vertices:
+ return True
- # each skin
- for s in l.morph_list:
- if s.getName()==base.name:
- # skip base
- continue
+ material_with_shape=set()
- # restore
- #for v, base_pos in zip(mesh.verts, baseblock.data):
- # v.co=base_pos.co
- #mesh.update()
-
- # name
- name=englishmap.getEnglishSkinName(s.getName())
- if not name:
- name=s.getName()
- new_shape_key=meshObject.add_shape_key(name)
- #new_shape_key.value=1.0
-
- # morph
- for i, offset in zip(s.indices, s.pos_list):
- try:
- vertex_index=base.indices[i]
- new_shape_key.data[vertex_index].co=[p+o for p, o in zip(
- mesh.verts[vertex_index].co, convert_coord(offset))]
- except IndexError as msg:
- print(IndexError, msg)
- print(i, len(base.indices))
- print(vertex_index, len(mesh.verts))
- print(base.indices[i])
- break
- except KeyError:
- #print 'this mesh not has shape vertices'
- break
-
- # set ipo curve
- #icu=ipo.addCurve(name)
- #icu.interpolation = Blender.IpoCurve.InterpTypes.LINEAR
- #icu.append( (0.0, 0.0) )
+ # 各マテリアルの開始頂点インデックスを記録する
+ face_map={}
+ face_count=0
+ for i, m in enumerate(io.materials):
+ face_map[i]=face_count
+ if isMaterialUsedInShape(face_count, m):
+ material_with_shape.add(i)
+ face_count+=m.vertex_count
+
+ # shapeキーで使われる頂点のあるマテリアル
+ material_with_shape=list(material_with_shape)
+ material_with_shape.sort()
+
+ # shapeキーに使われていないマテリアル
+ material_without_shape=[]
+ for i in range(len(io.materials)):
+ if not i in material_with_shape:
+ material_without_shape.append(i)
+
+ # メッシュの生成
+ 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()
+ bl.object.activate(meshObject)
+
+ # shapeキーで使われる順に並べなおしたマテリアル16個分の
+ # メッシュを作成する
+ vertex_map=__import16MaerialAndMesh(
+ meshObject, io, material16, face_map, tex_dir, toon_material)
+
+ # crete shape key
+ __importShape(meshObject, io, vertex_map)
+
+ mesh.update()
+ return meshObject
-
-def __execute(filename, scene):
+ 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(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,
+ ]
+ material=bl.material.create('constraint')
+ material.diffuse_color=(1, 0, 0)
+ constraintMeshes=[]
+ for i, c in enumerate(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=bl.object.getActive()
+ constraintMeshes.append(meshObject)
+ mesh=bl.object.getData(meshObject)
+ bl.mesh.addMaterial(mesh, material)
+ meshObject.name='c_%d' % i
+ #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_NAME]=c.getName()
+ meshObject[CONSTRAINT_A]=io.rigidbodies[c.rigidA].getName()
+ meshObject[CONSTRAINT_B]=io.rigidbodies[c.rigidB].getName()
+ meshObject[CONSTRAINT_POS_MIN]=VtoV(c.constraintPosMin)
+ meshObject[CONSTRAINT_POS_MAX]=VtoV(c.constraintPosMax)
+ meshObject[CONSTRAINT_ROT_MIN]=VtoV(c.constraintRotMin)
+ meshObject[CONSTRAINT_ROT_MAX]=VtoV(c.constraintRotMax)
+ meshObject[CONSTRAINT_SPRING_POS]=VtoV(c.springPos)
+ meshObject[CONSTRAINT_SPRING_ROT]=VtoV(c.springRot)
+
+ for meshObject in reversed(constraintMeshes):
+ bl.object.makeParent(container, meshObject)
+
+ return container
+
+
+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,
+ ]
+ material=bl.material.create('rigidBody')
+ rigidMeshes=[]
+ for i, rigid in enumerate(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=bl.object.getActive()
+ mesh=bl.object.getData(meshObject)
+ rigidMeshes.append(meshObject)
+ bl.mesh.addMaterial(mesh, material)
+ meshObject.name='r_%d' % i
+ meshObject[RIGID_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_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.object.makeParent(container, meshObject)
+
+ return container
+
+
+def _execute(filename):
"""
load pmd file to context.
"""
+
# 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)
+ bl.message("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.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.objectMakeParent(root, o)
+ bl.object.makeParent(root, o)
# import armature
- armature_object=importArmature(scene, io)
+ armature_object=__importArmature(io)
if armature_object:
- bl.objectMakeParent(root, armature_object)
- armature = bl.objectGetData(armature_object)
+ bl.object.makeParent(root, armature_object)
+ armature = bl.object.getData(armature_object)
# add armature modifier
for o in mesh_objects:
- bl.objectAddArmatureModifier(o, armature_object)
+ bl.modifier.addArmature(o, armature_object)
# Limitation
- for n, b in bl.objectGetPose(armature_object).bones.items():
- bl.poseBoneLimit(n, b)
+ for n, b in bl.object.getPose(armature_object).bones.items():
+ poseBoneLimit(n, b)
+
+ # import rigid bodies
+ rigidBodies=__importRigidBodies(io)
+ if rigidBodies:
+ bl.object.makeParent(root, rigidBodies)
+
+ # import constraints
+ constraints=__importConstraints(io)
+ if constraints:
+ bl.object.makeParent(root, constraints)
+
+ bl.object.activate(root)
- # select objects
- bl.objectSelect(root)
- for o in mesh_objects:
- bl.objectSelect(o)
- bl.objectSelect(armature_object)
-
if isBlender24():
# for 2.4
def execute_24(filename):
- """
- @param filename
- """
- filename=filename.decode(bl.INTERNAL_ENCODING)
- print(bl.INTERNAL_ENCODING, bl.FS_ENCODING)
-
- # set object mode
- mode_edit = Blender.Window.EditMode()
- 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:
- Blender.Window.EditMode(1)
- Blender.Window.RedrawAll()
+ bl.initialize('pmd_import', bpy.data.scenes.active)
+ _execute(filename.decode(bl.INTERNAL_ENCODING))
+ bl.finalize()
Blender.Window.FileSelector(
execute_24,
Blender.sys.makename(ext='.pmd'))
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):
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)