From: ousttrue Date: Wed, 12 May 2010 14:21:35 +0000 (+0900) Subject: add import_scene_pmd.py. X-Git-Url: http://git.osdn.jp/view?a=commitdiff_plain;h=29cfe1294994a2e95900097634c03f9c60323512;p=meshio%2Fmeshio.git add import_scene_pmd.py. --- diff --git a/blender25/import_scene_pmd.py b/blender25/import_scene_pmd.py new file mode 100644 index 0000000..0b580e2 --- /dev/null +++ b/blender25/import_scene_pmd.py @@ -0,0 +1,576 @@ +# coding: utf-8 + +__author__= ['ousttrue'] +__url__ = ("") +__version__= '20100508 0.1:' +__bpydoc__= '''\ +pmd Importer + +This script imports a pmd into Blender for editing. +''' + +import bpy +from bpy.props import * +import mathutils +import sys +import os +import math +from meshio import pmd, englishmap + + +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) + + +def get_bone_name(l, index): + name=englishmap.getEnglishBoneName(l.bones[index].getName()) + return name if name else l.bones[index].getName() + + +def create_texture(directory, texture_name): + texture=bpy.data.textures.new(texture_name) + texture.type='IMAGE' + texture=texture.recast_type() + texturePath="%s/%s" % (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 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 + + +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= 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=englishmap.getEnglishBoneName(l.bones[ik.index].getName()) + # 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 + + +def importShape(meshObject, l): + if len(l.morph_list)==0: + return + + # base + base=None + for s in l.morph_list: + if s.type!=0: + continue + base=s + break + assert(base) + + # create base key + baseblock=meshObject.add_shape_key("Basis") + + # mesh + mesh=meshObject.data + + # each skin + for s in l.morph_list: + if s.getName()==base.name: + # skip base + continue + + # 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) ) + + +def load(filename, context): + """ + load pmd file to context. + """ + io=pmd.IO() + if not io.read(filename): + print("fail to read", filename) + return + + scene=context.scene + + # create root object + root=bpy.data.objects.new(os.path.basename(filename), None) + scene.objects.link(root) + + # import mesh + mesh_objects=importMesh(scene, io, os.path.dirname(filename)) + for o in mesh_objects: + o.parent=root + + # import armature + armature_object=importArmature(scene, io) + if armature_object: + armature_object.parent=root + armature = armature_object.data + armature.draw_names=True + + # add armature modifier + for o in mesh_objects: + mod=o.modifiers.new("Modifier", "ARMATURE") + mod.object = armature_object + mod.use_bone_envelopes=False + #o.makeDisplayList() + + # redraw + scene.update() + + print("finised") + + +############################################################################### +# import operator +############################################################################### +class IMPORT_OT_pmd(bpy.types.Operator): + '''Import from Metasequoia file format (.pmd)''' + bl_idname = "import_scene.pmd" + bl_label = 'Import 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.") + + def execute(self, context): + load(self.properties.path, context) + return {'FINISHED'} + + def invoke(self, context, event): + wm = context.manager + wm.add_fileselect(self) + return {'RUNNING_MODAL'} + + +############################################################################### +# register menu +############################################################################### +menu_func = lambda self, context: self.layout.operator( + IMPORT_OT_pmd.bl_idname, text="MikuMikuDance model (.pmd)") + + +def register(): + bpy.types.register(IMPORT_OT_pmd) + bpy.types.INFO_MT_file_import.append(menu_func) + +def unregister(): + bpy.types.unregister(IMPORT_OT_pmd) + bpy.types.INFO_MT_file_import.remove(menu_func) + + +if __name__=="__main__": + register() +