diff --git a/io_import_scene_unreal_psa_psk.py b/io_import_scene_unreal_psa_psk.py new file mode 100644 index 0000000000000000000000000000000000000000..f7805768c8f7fd4dfdb9d058c8614a52017042a0 --- /dev/null +++ b/io_import_scene_unreal_psa_psk.py @@ -0,0 +1,1089 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +bl_info = { + "name": "Import Unreal Skeleton Mesh (.psk)/Animation Set (psa)", + "author": "Darknet, flufy3d, camg188", + "version": (2, 1), + "blender": (2, 6, 4), + "location": "File > Import > Skeleton Mesh (.psk)/Animation Set (psa)", + "description": "Import Skeleleton Mesh/Animation Data", + "warning": "", + "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/" + "Scripts/Import-Export/Unreal_psk_psa", + "tracker_url": "https://projects.blender.org/tracker/index.php?"\ + "func=detail&aid=21366", + "category": "Import-Export"} + +""" +Version': '2.0' ported by Darknet + +Unreal Tournament PSK file to Blender mesh converter V1.0 +Author: D.M. Sturgeon (camg188 at the elYsium forum), ported by Darknet +Imports a *psk file to a new mesh + +-No UV Texutre +-No Weight +-No Armature Bones +-No Material ID +-Export Text Log From Current Location File (Bool ) +""" + +import bpy +import mathutils +import math +from mathutils import * +from math import * +from bpy.props import * +from string import * +from struct import * +from math import * +from bpy.props import * + +bpy.types.Scene.unrealbonesize = FloatProperty( + name="Bone Length", + description="Bone Length from head to tail distance", + default=1,min=0.001,max=1000) + +#output log in to txt file +DEBUGLOG = False + +scale = 1.0 +bonesize = 1.0 +from bpy_extras.io_utils import unpack_list, unpack_face_list + +class md5_bone: + bone_index=0 + name="" + bindpos=[] + bindmat=[] + origmat=[] + head=[] + tail=[] + scale = [] + parent="" + parent_index=0 + blenderbone=None + roll=0 + + def __init__(self): + self.bone_index=0 + self.name="" + self.bindpos=[0.0]*3 + self.scale=[0.0]*3 + self.head=[0.0]*3 + self.tail=[0.0]*3 + self.bindmat=[None]*3 #is this how you initilize a 2d-array + for i in range(3): self.bindmat[i] = [0.0]*3 + self.origmat=[None]*3 #is this how you initilize a 2d-array + for i in range(3): self.origmat[i] = [0.0]*3 + self.parent="" + self.parent_index=0 + self.blenderbone=None + + def dump(self): + print ("bone index: ", self.bone_index) + print ("name: ", self.name) + print ("bind position: ", self.bindpos) + print ("bind translation matrix: ", self.bindmat) + print ("parent: ", self.parent) + print ("parent index: ", self.parent_index) + print ("blenderbone: ", self.blenderbone) + +def getheadpos(pbone,bones): + pos_head = [0.0]*3 + + #pos = mathutils.Vector((x,y,z)) * pbone.origmat + pos = pbone.bindmat.to_translation() + + """ + tmp_bone = pbone + while tmp_bone.name != tmp_bone.parent.name: + pos = pos * tmp_bone.parent.bindmat + tmp_bone = tmp_bone.parent + """ + + pos_head[0] = pos.x + pos_head[1] = pos.y + pos_head[2] = pos.z + + return pos_head +def gettailpos(pbone,bones): + pos_tail = [0.0]*3 + ischildfound = False + childbone = None + childbonelist = [] + for bone in bones: + if bone.parent.name == pbone.name: + ischildfound = True + childbone = bone + childbonelist.append(bone) + + if ischildfound: + tmp_head = [0.0]*3 + for bone in childbonelist: + tmp_head[0] += bone.head[0] + tmp_head[1] += bone.head[1] + tmp_head[2] += bone.head[2] + tmp_head[0] /= len(childbonelist) + tmp_head[1] /= len(childbonelist) + tmp_head[2] /= len(childbonelist) + return tmp_head + else: + tmp_len = 0.0 + tmp_len += (pbone.head[0] - pbone.parent.head[0])**2 + tmp_len += (pbone.head[1] - pbone.parent.head[1])**2 + tmp_len += (pbone.head[2] - pbone.parent.head[2])**2 + tmp_len = tmp_len**0.5 * 0.5 + pos_tail[0] = pbone.head[0] + tmp_len * pbone.bindmat[0][0] + pos_tail[1] = pbone.head[1] + tmp_len * pbone.bindmat[1][0] + pos_tail[2] = pbone.head[2] + tmp_len * pbone.bindmat[2][0] + + + return pos_tail + + + +def pskimport(infile,importmesh,importbone,bDebugLogPSK,importmultiuvtextures): + global DEBUGLOG + DEBUGLOG = bDebugLogPSK + print ("--------------------------------------------------") + print ("---------SCRIPT EXECUTING PYTHON IMPORTER---------") + print ("--------------------------------------------------") + print (" DEBUG Log:",bDebugLogPSK) + print ("Importing file: ", infile) + + pskfile = open(infile,'rb') + if (DEBUGLOG): + logpath = infile.replace(".psk", ".txt") + print("logpath:",logpath) + logf = open(logpath,'w') + + def printlog(strdata): + if (DEBUGLOG): + logf.write(strdata) + + objName = infile.split('\\')[-1].split('.')[0] + + me_ob = bpy.data.meshes.new(objName) + print("objName:",objName) + printlog(("New Mesh = " + me_ob.name + "\n")) + #read general header + indata = unpack('20s3i',pskfile.read(32)) + #not using the general header at this time + #================================================================================================== + # vertex point + #================================================================================================== + #read the PNTS0000 header + indata = unpack('20s3i',pskfile.read(32)) + recCount = indata[3] + printlog(( "Nbr of PNTS0000 records: " + str(recCount) + "\n")) + counter = 0 + verts = [] + verts2 = [] + while counter < recCount: + counter = counter + 1 + indata = unpack('3f',pskfile.read(12)) + #print(indata[0],indata[1],indata[2]) + verts.extend([(indata[0],indata[1],indata[2])]) + verts2.extend([(indata[0],indata[1],indata[2])]) + #print([(indata[0],indata[1],indata[2])]) + printlog(str(indata[0]) + "|" +str(indata[1]) + "|" +str(indata[2]) + "\n") + #Tmsh.vertices.append(NMesh.Vert(indata[0],indata[1],indata[2])) + + #================================================================================================== + # UV + #================================================================================================== + #read the VTXW0000 header + indata = unpack('20s3i',pskfile.read(32)) + recCount = indata[3] + printlog( "Nbr of VTXW0000 records: " + str(recCount)+ "\n") + counter = 0 + UVCoords = [] + #UVCoords record format = [index to PNTS, U coord, v coord] + printlog("[index to PNTS, U coord, v coord]\n"); + while counter < recCount: + counter = counter + 1 + indata = unpack('hhffhh',pskfile.read(16)) + UVCoords.append([indata[0],indata[2],indata[3]]) + printlog(str(indata[0]) + "|" +str(indata[2]) + "|" +str(indata[3])+"\n") + #print('mat index %i',indata(4)) + #print([indata[0],indata[2],indata[3]]) + #print([indata[1],indata[2],indata[3]]) + + #================================================================================================== + # Face + #================================================================================================== + #read the FACE0000 header + indata = unpack('20s3i',pskfile.read(32)) + recCount = indata[3] + printlog( "Nbr of FACE0000 records: "+ str(recCount) + "\n") + #PSK FACE0000 fields: WdgIdx1|WdgIdx2|WdgIdx3|MatIdx|AuxMatIdx|SmthGrp + #associate MatIdx to an image, associate SmthGrp to a material + SGlist = [] + counter = 0 + faces = [] + faceuv = [] + facesmooth = [] + #the psk values are: nWdgIdx1|WdgIdx2|WdgIdx3|MatIdx|AuxMatIdx|SmthGrp + printlog("nWdgIdx1|WdgIdx2|WdgIdx3|MatIdx|AuxMatIdx|SmthGrp \n") + while counter < recCount: + counter = counter + 1 + indata = unpack('hhhbbi',pskfile.read(12)) + printlog(str(indata[0]) + "|" +str(indata[1]) + "|" +str(indata[2])+ "|" +str(indata[3])+ "|" +str(indata[4])+ "|" +str(indata[5]) + "\n") + #indata[0] = index of UVCoords + #UVCoords[indata[0]]=[index to PNTS, U coord, v coord] + #UVCoords[indata[0]][0] = index to PNTS + PNTSA = UVCoords[indata[2]][0] + PNTSB = UVCoords[indata[1]][0] + PNTSC = UVCoords[indata[0]][0] + #print(PNTSA,PNTSB,PNTSC) #face id vertex + #faces.extend([0,1,2,0]) + faces.extend([(PNTSA,PNTSB,PNTSC,0)]) + uv = [] + u0 = UVCoords[indata[2]][1] + v0 = UVCoords[indata[2]][2] + uv.append([u0,1.0 - v0]) + u1 = UVCoords[indata[1]][1] + v1 = UVCoords[indata[1]][2] + uv.append([u1,1.0 - v1]) + u2 = UVCoords[indata[0]][1] + v2 = UVCoords[indata[0]][2] + uv.append([u2,1.0 - v2]) + faceuv.append([uv,indata[3],indata[4],indata[5]]) + + #print("material:",indata[3]) + #print("UV: ",u0,v0) + #update the uv var of the last item in the Tmsh.faces list + # which is the face just added above + ##Tmsh.faces[-1].uv = [(u0,v0),(u1,v1),(u2,v2)] + #print("smooth:",indata[5]) + #collect a list of the smoothing groups + facesmooth.append(indata[5]) + #print(indata[5]) + if SGlist.count(indata[5]) == 0: + SGlist.append(indata[5]) + print("smooth:",indata[5]) + #assign a material index to the face + #Tmsh.faces[-1].materialIndex = SGlist.index(indata[5]) + printlog( "Using Materials to represent PSK Smoothing Groups...\n") + #========== + # skip something... + #========== + + #================================================================================================== + # Material + #================================================================================================== + ## + #read the MATT0000 header + indata = unpack('20s3i',pskfile.read(32)) + recCount = indata[3] + printlog("Nbr of MATT0000 records: " + str(recCount) + "\n" ) + printlog(" - Not importing any material data now. PSKs are texture wrapped! \n") + counter = 0 + materialcount = 0 + while counter < recCount: + counter = counter + 1 + indata = unpack('64s6i',pskfile.read(88)) + materialcount += 1 + print("Material",counter) + print("Mat name %s",indata[0]) + + ## + + #================================================================================================== + # Bones (Armature) + #================================================================================================== + #read the REFSKEL0 header + indata = unpack('20s3i',pskfile.read(32)) + recCount = indata[3] + printlog( "Nbr of REFSKEL0 records: " + str(recCount) + "\n") + #REFSKEL0 fields - Name|Flgs|NumChld|PrntIdx|Qw|Qx|Qy|Qz|LocX|LocY|LocZ|Lngth|XSize|YSize|ZSize + + Bns = [] + bone = [] + + md5_bones = [] + bni_dict = {} + #================================================================================================== + # Bone Data + #================================================================================================== + counter = 0 + print ("---PRASE--BONES---") + printlog("Name|Flgs|NumChld|PrntIdx|Qx|Qy|Qz|Qw|LocX|LocY|LocZ|Lngth|XSize|YSize|ZSize\n") + while counter < recCount: + indata = unpack('64s3i11f',pskfile.read(120)) + #print( "DATA",str(indata)) + + bone.append(indata) + + createbone = md5_bone() + #temp_name = indata[0][:30] + temp_name = indata[0] + temp_name = bytes.decode(temp_name) + temp_name = temp_name.lstrip(" ") + temp_name = temp_name.rstrip(" ") + temp_name = temp_name.strip() + temp_name = temp_name.strip( bytes.decode(b'\x00')) + printlog(temp_name + "|" +str(indata[1]) + "|" +str(indata[2])+ "|" +str(indata[3])+ "|" +str(indata[4])+ "|" +str(indata[5]) + "|" +str(indata[6]) + "|" +str(indata[7]) + "|" +str(indata[8])+ "|" +str(indata[9])+ "|" +str(indata[10])+ "|" +str(indata[11]) + "|" +str(indata[12]) + "|" +str(indata[13]) + "|" +str(indata[14])+ "\n") + createbone.name = temp_name + createbone.bone_index = counter + createbone.parent_index = indata[3] + createbone.bindpos[0] = indata[8] + createbone.bindpos[1] = indata[9] + createbone.bindpos[2] = indata[10] + createbone.scale[0] = indata[12] + createbone.scale[1] = indata[13] + createbone.scale[2] = indata[14] + + bni_dict[createbone.name] = createbone.bone_index + + #w,x,y,z + if (counter == 0):#main parent + createbone.bindmat = mathutils.Quaternion((indata[7],-indata[4],-indata[5],-indata[6])).to_matrix() + createbone.origmat = mathutils.Quaternion((indata[7],-indata[4],-indata[5],-indata[6])).to_matrix() + else: + createbone.bindmat = mathutils.Quaternion((indata[7],-indata[4],-indata[5],-indata[6])).to_matrix() + createbone.origmat = mathutils.Quaternion((indata[7],-indata[4],-indata[5],-indata[6])).to_matrix() + + createbone.bindmat = mathutils.Matrix.Translation(mathutils.Vector((indata[8],indata[9],indata[10]))) * createbone.bindmat.to_4x4() + + + md5_bones.append(createbone) + counter = counter + 1 + bnstr = (str(indata[0])) + Bns.append(bnstr) + + for pbone in md5_bones: + pbone.parent = md5_bones[pbone.parent_index] + + + for pbone in md5_bones: + if pbone.name != pbone.parent.name: + pbone.bindmat = pbone.parent.bindmat * pbone.bindmat + #print(pbone.name) + #print(pbone.bindmat) + #print("end") + else: + pbone.bindmat = pbone.bindmat + + for pbone in md5_bones: + pbone.head = getheadpos(pbone,md5_bones) + + for pbone in md5_bones: + pbone.tail = gettailpos(pbone,md5_bones) + + + + for pbone in md5_bones: + pbone.parent = md5_bones[pbone.parent_index].name + + + + bonecount = 0 + for armbone in bone: + temp_name = armbone[0][:30] + #print ("BONE NAME: ",len(temp_name)) + temp_name=str((temp_name)) + #temp_name = temp_name[1] + #print ("BONE NAME: ",temp_name) + bonecount +=1 + print ("-------------------------") + print ("----Creating--Armature---") + print ("-------------------------") + + #================================================================================================ + #Check armature if exist if so create or update or remove all and addnew bone + #================================================================================================ + #bpy.ops.object.mode_set(mode='OBJECT') + meshname ="ArmObject" + objectname = "armaturedata" + # arm = None # UNUSED + if importbone: + obj = bpy.data.objects.get(meshname) + # arm = obj # UNUSED + + if not obj: + armdata = bpy.data.armatures.new(objectname) + ob_new = bpy.data.objects.new(meshname, armdata) + #ob_new = bpy.data.objects.new(meshname, 'ARMATURE') + #ob_new.data = armdata + bpy.context.scene.objects.link(ob_new) + #bpy.ops.object.mode_set(mode='OBJECT') + for i in bpy.context.scene.objects: i.select = False #deselect all objects + ob_new.select = True + #set current armature to edit the bone + bpy.context.scene.objects.active = ob_new + #set mode to able to edit the bone + if bpy.ops.object.mode_set.poll(): + bpy.ops.object.mode_set(mode='EDIT') + + #newbone = ob_new.data.edit_bones.new('test') + #newbone.tail.y = 1 + print("creating bone(s)") + bpy.ops.object.mode_set(mode='OBJECT') + for bone in md5_bones: + #print(dir(bone)) + bpy.ops.object.mode_set(mode='EDIT')#Go to edit mode for the bones + newbone = ob_new.data.edit_bones.new(bone.name) + #parent the bone + #print("DRI:",dir(newbone)) + parentbone = None + #note bone location is set in the real space or global not local + bonesize = bpy.types.Scene.unrealbonesize + if bone.name != bone.parent: + pos_x = bone.bindpos[0] + pos_y = bone.bindpos[1] + pos_z = bone.bindpos[2] + #print( "LINKING:" , bone.parent ,"j") + parentbone = ob_new.data.edit_bones[bone.parent] + newbone.parent = parentbone + rotmatrix = bone.bindmat + newbone.head.x = bone.head[0] + newbone.head.y = bone.head[1] + newbone.head.z = bone.head[2] + newbone.tail.x = bone.tail[0] + newbone.tail.y = bone.tail[1] + newbone.tail.z = bone.tail[2] + + vecp = parentbone.tail - parentbone.head + vecc = newbone.tail - newbone.head + vecc.normalize() + vecp.normalize() + if vecp.dot(vecc) > -0.8: + newbone.roll = parentbone.roll + else: + newbone.roll = - parentbone.roll + else: + rotmatrix = bone.bindmat + newbone.head.x = bone.head[0] + newbone.head.y = bone.head[1] + newbone.head.z = bone.head[2] + newbone.tail.x = bone.tail[0] + newbone.tail.y = bone.tail[1] + newbone.tail.z = bone.tail[2] + newbone.roll = math.radians(90.0) + """ + vec = newbone.tail - newbone.head + if vec.z > 0.0: + newbone.roll = math.radians(90.0) + else: + newbone.roll = math.radians(-90.0) + """ + bpy.context.scene.update() + + #================================================================================================== + #END BONE DATA BUILD + #================================================================================================== + VtxCol = [] + for x in range(len(Bns)): + #change the overall darkness of each material in a range between 0.1 and 0.9 + tmpVal = ((float(x)+1.0)/(len(Bns))*0.7)+0.1 + tmpVal = int(tmpVal * 256) + tmpCol = [tmpVal,tmpVal,tmpVal,0] + #Change the color of each material slightly + if x % 3 == 0: + if tmpCol[0] < 128: tmpCol[0] += 60 + else: tmpCol[0] -= 60 + if x % 3 == 1: + if tmpCol[1] < 128: tmpCol[1] += 60 + else: tmpCol[1] -= 60 + if x % 3 == 2: + if tmpCol[2] < 128: tmpCol[2] += 60 + else: tmpCol[2] -= 60 + #Add the material to the mesh + VtxCol.append(tmpCol) + + #================================================================================================== + # Bone Weight + #================================================================================================== + #read the RAWW0000 header + indata = unpack('20s3i',pskfile.read(32)) + recCount = indata[3] + printlog( "Nbr of RAWW0000 records: " + str(recCount) +"\n") + #RAWW0000 fields: Weight|PntIdx|BoneIdx + RWghts = [] + counter = 0 + while counter < recCount: + counter = counter + 1 + indata = unpack('fii',pskfile.read(12)) + RWghts.append([indata[1],indata[2],indata[0]]) + #print("weight:",[indata[1],indata[2],indata[0]]) + #RWghts fields = PntIdx|BoneIdx|Weight + RWghts.sort() + printlog( "Vertex point and groups count =" + str(len(RWghts)) + "\n") + printlog("PntIdx|BoneIdx|Weight") + for vg in RWghts: + printlog( str(vg[0]) + "|" + str(vg[1]) + "|" + str(vg[2]) + "\n") + + #Tmsh.update_tag() + + #set the Vertex Colors of the faces + #face.v[n] = RWghts[0] + #RWghts[1] = index of VtxCol + """ + for x in range(len(Tmsh.faces)): + for y in range(len(Tmsh.faces[x].v)): + #find v in RWghts[n][0] + findVal = Tmsh.faces[x].v[y].index + n = 0 + while findVal != RWghts[n][0]: + n = n + 1 + TmpCol = VtxCol[RWghts[n][1]] + #check if a vertex has more than one influence + if n != len(RWghts)-1: + if RWghts[n][0] == RWghts[n+1][0]: + #if there is more than one influence, use the one with the greater influence + #for simplicity only 2 influences are checked, 2nd and 3rd influences are usually very small + if RWghts[n][2] < RWghts[n+1][2]: + TmpCol = VtxCol[RWghts[n+1][1]] + Tmsh.faces[x].col.append(NMesh.Col(TmpCol[0],TmpCol[1],TmpCol[2],0)) + """ + if (DEBUGLOG): + logf.close() + #================================================================================================== + #Building Mesh + #================================================================================================== + print("vertex:",len(verts),"faces:",len(faces)) + print("vertex2:",len(verts2)) + me_ob.vertices.add(len(verts2)) + me_ob.tessfaces.add(len(faces)) + me_ob.vertices.foreach_set("co", unpack_list(verts2)) + me_ob.tessfaces.foreach_set("vertices_raw",unpack_list( faces)) + + for face in me_ob.tessfaces: + face.use_smooth = facesmooth[face.index] + + + """ + Material setup coding. + First the mesh has to be create first to get the uv texture setup working. + -Create material(s) list in the psk pack data from the list.(to do list) + -Append the material to the from create the mesh object. + -Create Texture(s) + -fae loop for uv assign and assign material index + + """ + bpy.ops.object.mode_set(mode='OBJECT') + #=================================================================================================== + #Material Setup + #=================================================================================================== + print ("-------------------------") + print ("----Creating--Materials--") + print ("-------------------------") + materialname = "pskmat" + materials = [] + + for matcount in range(materialcount): + #if texturedata != None: + matdata = bpy.data.materials.new(materialname + str(matcount)) + #mtex = matdata.texture_slots.new() + #mtex.texture = texture[matcount].data + #print(type(texture[matcount].data)) + #print(dir(mtex)) + #print(dir(matdata)) + #for texno in range(len( bpy.data.textures)): + #print((bpy.data.textures[texno].name)) + #print(dir(bpy.data.textures[texno])) + #matdata.active_texture = bpy.data.textures[matcount-1] + #matdata.texture_coords = 'UV' + #matdata.active_texture = texturedata + materials.append(matdata) + + for material in materials: + #add material to the mesh list of materials + me_ob.materials.append(material) + #=================================================================================================== + #UV Setup + #=================================================================================================== + print ("-------------------------") + print ("-- Creating UV Texture --") + print ("-------------------------") + texture = [] + # texturename = "text1" # UNUSED + countm = 0 + for countm in range(materialcount): + psktexname="psk" + str(countm) + me_ob.uv_textures.new(name=psktexname) + countm += 1 + print("INIT UV TEXTURE...") + _matcount = 0 + #for mattexcount in materials: + #print("MATERAIL ID:",_matcount) + _textcount = 0 + for uv in me_ob.tessface_uv_textures: # uv texture + print("UV TEXTURE ID:",_textcount) + print(dir(uv)) + for face in me_ob.tessfaces:# face, uv + #print(dir(face)) + if faceuv[face.index][1] == _textcount: #if face index and texture index matches assign it + mfaceuv = faceuv[face.index] #face index + _uv1 = mfaceuv[0][0] #(0,0) + uv.data[face.index].uv1 = mathutils.Vector((_uv1[0],_uv1[1])) #set them + _uv2 = mfaceuv[0][1] #(0,0) + uv.data[face.index].uv2 = mathutils.Vector((_uv2[0],_uv2[1])) #set them + _uv3 = mfaceuv[0][2] #(0,0) + uv.data[face.index].uv3 = mathutils.Vector((_uv3[0],_uv3[1])) #set them + else: #if not match zero them + uv.data[face.index].uv1 = mathutils.Vector((0,0)) #zero them + uv.data[face.index].uv2 = mathutils.Vector((0,0)) #zero them + uv.data[face.index].uv3 = mathutils.Vector((0,0)) #zero them + _textcount += 1 + #_matcount += 1 + #print(matcount) + print("END UV TEXTURE...") + + print("UV TEXTURE LEN:",len(texture)) + #for tex in me_ob.uv_textures: + #print("mesh tex:",dir(tex)) + #print((tex.name)) + + #for face in me_ob.faces: + #print(dir(face)) + + #=================================================================================================== + # + #=================================================================================================== + obmesh = bpy.data.objects.new(objName,me_ob) + #=================================================================================================== + #Mesh Vertex Group bone weight + #=================================================================================================== + print("---- building bone weight mesh ----") + #print(dir(ob_new.data.bones)) + #create bone vertex group #deal with bone id for index number + for bone in ob_new.data.bones: + #print("names:",bone.name,":",dir(bone)) + #print("names:",bone.name) + group = obmesh.vertex_groups.new(bone.name) + + + for vgroup in obmesh.vertex_groups: + #print(vgroup.name,":",vgroup.index) + for vgp in RWghts: + #bone index + + if vgp[1] == bni_dict[vgroup.name]: + #print(vgp) + #[vertex id],weight + vgroup.add([vgp[0]], vgp[2], 'ADD') + + + #check if there is a material to set to + if len(materials) > 0: + obmesh.active_material = materials[0] #material setup tmp + print("---- adding mesh to the scene ----") + + bpy.ops.object.mode_set(mode='OBJECT') + #bpy.ops.object.select_pattern(extend=True, pattern=obmesh.name, case_sensitive=True) + #bpy.ops.object.select_pattern(extend=True, pattern=ob_new.name, case_sensitive=True) + + #bpy.ops.object.select_name(name=str(obmesh.name)) + #bpy.ops.object.select_name(name=str(ob_new.name)) + #bpy.context.scene.objects.active = ob_new + me_ob.update() + bpy.context.scene.objects.link(obmesh) + bpy.context.scene.update() + obmesh.select = False + ob_new.select = False + obmesh.select = True + ob_new.select = True + bpy.ops.object.parent_set(type="ARMATURE") + + print ("PSK2Blender completed") +#End of def pskimport######################### + +def getInputFilenamepsk(self,filename,importmesh,importbone,bDebugLogPSK,importmultiuvtextures): + checktype = filename.split('\\')[-1].split('.')[1] + print ("------------",filename) + if checktype.lower() != 'psk': + print (" Selected file = ",filename) + raise (IOError, "The selected input file is not a *.psk file") + #self.report({'INFO'}, ("Selected file:"+ filename)) + else: + pskimport(filename,importmesh,importbone,bDebugLogPSK,importmultiuvtextures) + +def getInputFilenamepsa(self,filename,context): + checktype = filename.split('\\')[-1].split('.')[1] + if checktype.lower() != 'psa': + print (" Selected file = ",filename) + raise (IOError, "The selected input file is not a *.psa file") + #self.report({'INFO'}, ("Selected file:"+ filename)) + else: + psaimport(filename,context) + +class IMPORT_OT_psk(bpy.types.Operator): + '''Load a skeleton mesh psk File''' + bl_idname = "import_scene.psk" + bl_label = "Import PSK" + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_options = {'UNDO'} + + # List of operator properties, the attributes will be assigned + # to the class instance from the operator settings before calling. + filepath = StringProperty( + subtype='FILE_PATH', + ) + filter_glob = StringProperty( + default="*.psk", + options={'HIDDEN'}, + ) + importmesh = BoolProperty( + name="Mesh", + description="Import mesh only. (not yet build.)", + default=True, + ) + importbone = BoolProperty( + name="Bones", + description="Import bones only. Current not working yet", + default=True, + ) + importmultiuvtextures = BoolProperty( + name="Single UV Texture(s)", + description="Single or Multi uv textures", + default=True, + ) + bDebugLogPSK = BoolProperty( + name="Debug Log.txt", + description="Log the output of raw format. It will save in " \ + "current file dir. Note this just for testing", + default=False, + ) + unrealbonesize = FloatProperty( + name="Bone Length", + description="Bone Length from head to tail distance", + default=1, + min=0.001, + max=1000, + ) + + def execute(self, context): + bpy.types.Scene.unrealbonesize = self.unrealbonesize + getInputFilenamepsk(self,self.filepath,self.importmesh,self.importbone,self.bDebugLogPSK,self.importmultiuvtextures) + return {'FINISHED'} + + def invoke(self, context, event): + wm = context.window_manager + wm.fileselect_add(self) + return {'RUNNING_MODAL'} + + +class psa_bone: + name="" + Transform=None + parent=None + def __init__(self): + self.name="" + self.Transform=None + self.parent=None + +def psaimport(filename,context): + print ("--------------------------------------------------") + print ("---------SCRIPT EXECUTING PYTHON IMPORTER---------") + print ("--------------------------------------------------") + print ("Importing file: ", filename) + psafile = open(filename,'rb') + debug = True + if (debug): + logpath = filename.replace(".psa", ".txt") + print("logpath:",logpath) + logf = open(logpath,'w') + def printlog(strdata): + if (debug): + logf.write(strdata) + def printlogplus(name,data): + if (debug): + logf.write(str(name)+'\n') + if isinstance(data,bytes): + logf.write(str(bytes.decode(data).strip(bytes.decode(b'\x00')))) + else: + logf.write(str(data)) + logf.write('\n') + + printlog('-----------Log File------------\n') + #General Header + indata = unpack('20s3i',psafile.read(32)) + printlogplus('ChunkID',indata[0]) + printlogplus('TypeFlag',indata[1]) + printlogplus('DataSize',indata[2]) + printlogplus('DataCount',indata[3]) + #Bones Header + indata = unpack('20s3i',psafile.read(32)) + printlogplus('ChunkID',indata[0]) + printlogplus('TypeFlag',indata[1]) + printlogplus('DataSize',indata[2]) + printlogplus('DataCount',indata[3]) + #Bones Data + BoneIndex2NamePairMap = {} + BoneNotFoundList = [] + printlog("Name|Flgs|NumChld|PrntIdx|Qx|Qy|Qz|Qw|LocX|LocY|LocZ|Length|XSize|YSize|ZSize\n") + recCount = indata[3] + counter = 0 + nobonematch = True + while counter < recCount: + indata = unpack('64s3i11f',psafile.read(120)) + #printlogplus('bone',indata[0]) + bonename = str(bytes.decode(indata[0]).strip(bytes.decode(b'\x00'))) + if bonename in bpy.data.armatures['armaturedata'].bones.keys(): + BoneIndex2NamePairMap[counter] = bonename + print('find bone',bonename) + nobonematch = False + else: + print('can not find the bone:',bonename) + BoneNotFoundList.append(counter) + counter += 1 + + if nobonematch: + print('no bone was match so skip import!') + return + + #Animations Header + indata = unpack('20s3i',psafile.read(32)) + printlogplus('ChunkID',indata[0]) + printlogplus('TypeFlag',indata[1]) + printlogplus('DataSize',indata[2]) + printlogplus('DataCount',indata[3]) + #Animations Data + recCount = indata[3] + counter = 0 + Raw_Key_Nums = 0 + Action_List = [] + while counter < recCount: + indata = unpack('64s64s4i3f3i',psafile.read(64+64+4*4+3*4+3*4)) + printlogplus('Name',indata[0]) + printlogplus('Group',indata[1]) + printlogplus('totalbones',indata[2]) + printlogplus('NumRawFrames',indata[-1]) + Name = str(bytes.decode(indata[0]).strip(bytes.decode(b'\x00'))) + Group = str(bytes.decode(indata[1]).strip(bytes.decode(b'\x00'))) + totalbones = indata[2] + NumRawFrames = indata[-1] + + Raw_Key_Nums += indata[2] * indata[-1] + Action_List.append((Name,Group,totalbones,NumRawFrames)) + + counter += 1 + + #Raw keys Header + Raw_Key_List = [] + indata = unpack('20s3i',psafile.read(32)) + printlogplus('ChunkID',indata[0]) + printlogplus('TypeFlag',indata[1]) + printlogplus('DataSize',indata[2]) + printlogplus('DataCount',indata[3]) + if(Raw_Key_Nums != indata[3]): + print('error! Raw_Key_Nums Inconsistent') + return + #Raw keys Data + recCount = Raw_Key_Nums + counter = 0 + while counter < recCount: + indata = unpack('3f4f1f',psafile.read(3*4+4*4+4)) + pos = mathutils.Vector((indata[0], indata[1], indata[2])) + quat = mathutils.Quaternion((indata[6], indata[3], indata[4], indata[5])) + time = indata[7] + Raw_Key_List.append((pos,quat,time)) + counter += 1 + #Scale keys Header,Scale keys Data,Curve keys Header,Curve keys Data + curFilePos = psafile.tell() + psafile.seek(0,2) + endFilePos = psafile.tell() + if curFilePos == endFilePos: + print('no Scale keys,Curve keys') + + #build the animation line + if bpy.ops.object.mode_set.poll(): + bpy.ops.object.mode_set(mode='OBJECT', toggle=False) + + NeededBoneMatrix = {} + for bone in bpy.data.armatures['armaturedata'].bones: + name = bone.name + ori_matrix = bone.matrix + matrix = bone.matrix_local.to_3x3() + bone_rest_matrix = Matrix(matrix) + #bone_rest_matrix = bone.matrix_local.to_3x3() + #bone_rest_matrix = bone.matrix_local.to_quaternion().conjugated().to_matrix() + bone_rest_matrix_inv = Matrix(bone_rest_matrix) + bone_rest_matrix_inv.invert() + bone_rest_matrix_inv.resize_4x4() + bone_rest_matrix.resize_4x4() + NeededBoneMatrix[name] = (bone_rest_matrix,bone_rest_matrix_inv,ori_matrix) + + #build tmp pose bone tree + psa_bones = {} + for bone in bpy.data.objects['ArmObject'].pose.bones: + _psa_bone = psa_bone() + _psa_bone.name = bone.name + _psa_bone.Transform = bone.matrix + if bone.parent != None: + _psa_bone.parent = psa_bones[bone.parent.name] + else: + _psa_bone.parent = None + psa_bones[bone.name] = _psa_bone + + raw_key_index = 0 + + for raw_action in Action_List: + Name = raw_action[0] + Group = raw_action[1] + Totalbones = raw_action[2] + NumRawFrames = raw_action[3] + context.scene.update() + object = bpy.data.objects['ArmObject'] + object.animation_data_create() + action = bpy.data.actions.new(name=Name) + object.animation_data.action = action + for i in range(NumRawFrames): + context.scene.frame_set(i+1) + pose_bones = object.pose.bones + for j in range(Totalbones): + if j not in BoneNotFoundList: + bName = BoneIndex2NamePairMap[j] + pbone = psa_bones[bName] + pos = Raw_Key_List[raw_key_index][0] + quat = Raw_Key_List[raw_key_index][1] + + mat = Matrix() + if pbone.parent != None: + quat = quat.conjugated() + mat = Matrix.Translation(pos) * quat.to_matrix().to_4x4() + mat = pose_bones[bName].parent.matrix * mat + #mat = pbone.parent.Transform * mat + else: + mat = pbone.Transform * Matrix.Translation(pos) * quat.to_matrix().to_4x4() + + pose_bones[bName].matrix = mat + pbone.Transform = mat + + raw_key_index += 1 + + #bpy.data.meshes[1] + for bone in pose_bones: + bone.matrix = psa_bones[bone.name].Transform + bone.keyframe_insert("rotation_quaternion") + bone.keyframe_insert("location") + + def whirlSingleBone(pose_bone,quat): + bpy.context.scene.update() + #record child's matrix and origin rotate + hymat = Quaternion((0.707,-0.707,0,0)).inverted().to_matrix().to_4x4() + children_infos = {} + childrens = pose_bone.children + for child in childrens: + armmat = bpy.data.armatures['armaturedata'].bones[child.name].matrix.copy().to_4x4() + cmat = child.matrix.copy() * armmat.inverted() * hymat.inverted() + pos = cmat.to_translation() + rotmat = cmat.to_3x3() + children_infos[child] = (armmat,pos,rotmat) + + #whirl this bone by quat + pose_bone.matrix *= quat.to_matrix().to_4x4() + pose_bone.keyframe_insert("location") + pose_bone.keyframe_insert("rotation_quaternion") + bpy.context.scene.update() + #set back children bon to original position + #reverse whirl child bone by quat.inverse() + + for child in childrens: + armmat = children_infos[child][0] + pos = children_infos[child][1] + rotmat = children_infos[child][2] + + child.matrix = Matrix.Translation(pos) * rotmat.to_4x4() * hymat * armmat + child.keyframe_insert("location") + child.keyframe_insert("rotation_quaternion") + + for bone in pose_bones: + if bone.parent != None: + whirlSingleBone(bone,Quaternion((0.707,0,0,-0.707))) + else: + bone.rotation_quaternion *= Quaternion((0.707,-0.707,0,0))*Quaternion((0.707,0,0,-0.707)) + bone.keyframe_insert("rotation_quaternion") + + break + + context.scene.frame_set(0) + if(debug): + logf.close() + +class IMPORT_OT_psa(bpy.types.Operator): + '''Load a skeleton anim psa File''' + bl_idname = "import_scene.psa" + bl_label = "Import PSA" + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + + filepath = StringProperty( + subtype='FILE_PATH', + ) + filter_glob = StringProperty( + default="*.psa", + options={'HIDDEN'}, + ) + + def execute(self, context): + getInputFilenamepsa(self,self.filepath,context) + return {'FINISHED'} + + def invoke(self, context, event): + wm = context.window_manager + wm.fileselect_add(self) + return {'RUNNING_MODAL'} + +class IMPORT_OT_psa(bpy.types.Operator): + '''Load a skeleton anim psa File''' + bl_idname = "import_scene.psa" + bl_label = "Import PSA" + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + + filepath = StringProperty( + subtype='FILE_PATH', + ) + filter_glob = StringProperty( + default="*.psa", + options={'HIDDEN'}, + ) + + def execute(self, context): + getInputFilenamepsa(self,self.filepath,context) + return {'FINISHED'} + + def invoke(self, context, event): + wm = context.window_manager + wm.fileselect_add(self) + return {'RUNNING_MODAL'} + +def menu_func(self, context): + self.layout.operator(IMPORT_OT_psk.bl_idname, text="Skeleton Mesh (.psk)") + self.layout.operator(IMPORT_OT_psa.bl_idname, text="Skeleton Anim (.psa)") + +def register(): + bpy.utils.register_module(__name__) + bpy.types.INFO_MT_file_import.append(menu_func) + +def unregister(): + bpy.utils.unregister_module(__name__) + bpy.types.INFO_MT_file_import.remove(menu_func) + +if __name__ == "__main__": + register() + +#note this only read the data and will not be place in the scene +#getInputFilename('C:\\blenderfiles\\BotA.psk') +#getInputFilename('C:\\blenderfiles\\AA.PSK') \ No newline at end of file diff --git a/io_import_scene_unreal_psk.py b/io_import_scene_unreal_psk.py deleted file mode 100644 index 96784b1d6da4a04666ab63f9612ae5dd4dc3c94c..0000000000000000000000000000000000000000 --- a/io_import_scene_unreal_psk.py +++ /dev/null @@ -1,804 +0,0 @@ -# ##### BEGIN GPL LICENSE BLOCK ##### -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -bl_info = { - "name": "Import Unreal Skeleton Mesh (.psk)", - "author": "Darknet", - "version": (2, 1), - "blender": (2, 6, 3), - "location": "File > Import > Skeleton Mesh (.psk)", - "description": "Import Skeleleton Mesh", - "warning": "", - "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/" - "Scripts/Import-Export/Unreal_psk_psa", - "tracker_url": "https://projects.blender.org/tracker/index.php?"\ - "func=detail&aid=21366", - "category": "Import-Export"} - -""" -Version': '2.0' ported by Darknet - -Unreal Tournament PSK file to Blender mesh converter V1.0 -Author: --Darknet (Redesign and reworked) --D.M. Sturgeon (camg188 at the elYsium forum) --#2011-01-20 MARIUSZ SZKARADEK GLOGOW POLAND - -Imports a *psk file to a new mesh - --No UV Texutre --No Weight --No Armature Bones --No Material ID -""" - -import bpy -import bmesh -import mathutils -import math -from string import * -from struct import * -import struct -from math import * -from bpy.props import * -from bpy_extras.io_utils import unpack_list, unpack_face_list - -Quaternion = mathutils.Quaternion - -bpy.types.Scene.unrealbonesize = FloatProperty( - name="Bone Length", - description="Bone Length from head to tail distance", - default=1,min=0.001,max=1000) - -#output log in to txt file -DEBUGLOG = False - -scale = 1.0 -bonesize = 1.0 -skala = 1 -flipyz = False -flipuv = True - -#pack read words -def word(long): - s='' - for j in range(0,long): - lit = struct.unpack('c',plik.read(1))[0] - #print(">",lit) - #print(">",bytes.decode(lit)) - if ord(lit)!=0: - #print(lit) - s+=bytes.decode(lit) - if len(s)>100: - break - return s -#pack read data -def b(n): - return struct.unpack(n*'b', plik.read(n)) -def B(n): - return struct.unpack(n*'B', plik.read(n)) -def h(n): - return struct.unpack(n*'h', plik.read(n*2)) -def H(n): - return struct.unpack(n*'H', plik.read(n*2)) -def i(n): - return struct.unpack(n*'i', plik.read(n*4)) -def f(n): - return struct.unpack(n*'f', plik.read(n*4)) - -#work in progress -#bmesh -#tess function prefix -def drawmesh(): - global DEBUGLOG, plik,vertexes,uvcoord,faceslist,num_faces,facemat,facesmooth,m - global vertexes_ids,bonesdata,meshesdata,groups,num_materials,skala,flipyz,flipuv,mat_faceslist - global vertices,faces - print(faces[0]) - print("[CREATING MESH:]") - me_ob = bpy.data.meshes.new('testmesh') - #create mesh - print("-Vertices count:",len(vertices)) - me_ob.vertices.add(len(vertices)) - print("-Faces count:",len(faces)) - me_ob.tessfaces.add(len(faces)) - print("-Creating vertices points...") - me_ob.vertices.foreach_set("co", unpack_list(vertices)) - print("-Creating faces idx...") - me_ob.tessfaces.foreach_set("vertices_raw",unpack_list( faces)) - for face in me_ob.tessfaces: - print(dir(face)) - face.use_smooth = facesmooth[face.index] - #face.material_index = facemat[face.index]#not yet working - print("-Creating UV Texture...") - me_ob.tessface_uv_textures.new('uvtexture') - #uvtex = me_ob.tessface_uv_textures[0] - for uv in me_ob.tessface_uv_textures: - for face in me_ob.tessfaces: - #uv.data[face.index].uv1.x = - - #print(uv.data[face.index].uv1) - #uv.data[face.index].uv1 = Vector(uvcoord[faces[face.index]][0],uvcoord[face.index][1]) - print(face.vertices_raw[0],face.vertices_raw[1],face.vertices_raw[2]) - uv.data[face.index].uv1 = mathutils.Vector((uvcoord[face.vertices_raw[0]][0],uvcoord[face.vertices_raw[0]][1])) - uv.data[face.index].uv2 = mathutils.Vector((uvcoord[face.vertices_raw[1]][0],uvcoord[face.vertices_raw[1]][1])) - uv.data[face.index].uv3 = mathutils.Vector((uvcoord[face.vertices_raw[2]][0],uvcoord[face.vertices_raw[2]][1])) - - ob = bpy.data.objects.new("TestObject",me_ob) - #create vertex group - for bone_id in range(len(bonesdata)): - bonedata = bonesdata[str(bone_id)] - namebone = bonedata[0]#.strip()[-25:] - #print("NAME:",namebone) - ob.vertex_groups.new(namebone) - me_ob.update() - bpy.context.scene.objects.link(ob) - -#Create Armature -def check_armature(): - global DEBUGLOG, plik,vertexes,uvcoord,faceslist,num_faces,facemat,facesmooth,m - global vertexes_ids,bonesdata,meshesdata,groups,num_materials,skala,flipyz,flipuv,amt - - #create Armature - bpy.ops.object.mode_set(mode='OBJECT') - for i in bpy.context.scene.objects: i.select = False #deselect all objects - - bpy.ops.object.add( - type='ARMATURE', - enter_editmode=True, - location=(0,0,0)) - ob = bpy.context.object - ob.show_x_ray = True - ob.name = "ARM" - amt = ob.data - amt.name = 'Amt' - amt.show_axes = True - bpy.ops.object.mode_set(mode='EDIT') - bpy.context.scene.update() -#Create bones -def make_bone(): - global DEBUGLOG, plik,vertexes,uvcoord,faceslist,num_faces,facemat,facesmooth,m - global vertexes_ids,bonesdata,meshesdata,groups,num_materials,skala,flipyz,flipuv,amt - global bonenames - bonenames = [] - - print ('make bone') - - for bone_id in range(len(bonesdata)): - bonedata = bonesdata[str(bone_id)] - namebone = bonedata[0]#.strip()[-25:] - newbone = amt.edit_bones.new(namebone) - #those are need to show in the scene - newbone.head = (0,0,0) - newbone.tail = (0,0,1) - bonenames.append(namebone) - bpy.context.scene.update() -#Make bone parent -def make_bone_parent(): - global DEBUGLOG, plik,vertexes,uvcoord,faceslist,num_faces,facemat,facesmooth,m - global vertexes_ids,bonesdata,meshesdata,groups,num_materials,skala,flipyz,flipuv,amt - global children - children = {} - - print ('make bone parent') - for bone_id in range(len(bonesdata)): - bonedata = bonesdata[str(bone_id)] - namebone = bonenames[bone_id] - nameparent = bonenames[bonedata[1][2]] - #print(nameparent) - if nameparent != None:#make sure it has name - parentbone = amt.edit_bones[nameparent] - bonecurrnet = amt.edit_bones[namebone] - bonecurrnet.parent = parentbone - bpy.context.scene.update() - -#make bone martix set -def bones_matrix(): - global DEBUGLOG, plik,vertexes,uvcoord,faceslist,num_faces,facemat,facesmooth,m - global vertexes_ids,bonesdata,meshesdata,groups,num_materials,skala,flipyz,flipuv,amt - - for bone_id in range(len(bonesdata)): - bonedata = bonesdata[str(bone_id)] - namebone = bonedata[0]#.strip()[-25:] - nameparent = bonenames[bonedata[1][2]] - pos = bonedata[2][4:7] - rot = bonedata[2][0:4] - qx,qy,qz,qw = rot[0],rot[1],rot[2],rot[3] - #print("Quaternion:",qx,qy,qz,qw) - if bone_id==0: - rot = mathutils.Quaternion((qw,-qx,-qy,-qz)) - if bone_id!=0: - rot = mathutils.Quaternion((qw,qx,qy,qz)) - matrix = mathutils.Matrix() - rot = rot.to_matrix().inverted() - #print(rot) - matrix[0][:3] = rot[0] - matrix[1][:3] = rot[1] - matrix[2][:3] = rot[2] - matrix[3][:3] = pos - if bone_id>0: - bonedata.append(matrix*bonesdata[str(bonedata[1][2])][3]) - else: - bonedata.append(matrix) - bpy.context.scene.update() - -#not working -def make_bone_position(): - print ('make bone position') - bpy.ops.object.mode_set(mode='EDIT') - for bone_id in range(len(bonesdata)): - bonedata = bonesdata[str(bone_id)] - namebone = bonedata[0]#.strip()[-25:] - bone = amt.edit_bones[namebone] - bone.transform(bonedata[3], scale=True, roll=True) - bvec = bone.tail- bone.head - bvec.normalize() - bone.tail = bone.head + 0.1 * bvec - #bone.tail = bone.head + 1 * bvec - bpy.context.scene.update() - -#not working -def make_bone_position1(): - print ('make bone position') - bpy.ops.object.mode_set(mode='EDIT') - for bone_id in range(len(bonesdata)): - bonedata = bonesdata[str(bone_id)] - namebone = bonedata[0]#.strip()[-25:] - pos = bonedata[2][4:7] - pos1 = pos[0]*skala - pos2 = pos[1]*skala - pos3 = pos[2]*skala - if flipyz == False: - pos = [pos1,pos2,pos3] - if flipyz == True: - pos = [pos1,-pos3,pos2] - rot = bonedata[2][0:4] - qx,qy,qz,qw = rot[0],rot[1],rot[2],rot[3] - if bone_id==0: - rot = mathutils.Quaternion((qw,-qx,-qy,-qz)) - if bone_id!=0: - rot = mathutils.Quaternion((qw,qx,qy,qz)) - #rot = rot.toMatrix().invert() - rot = rot.to_matrix().inverted() - bone = amt.edit_bones[namebone] - #print("BONES:",amt.bones[0]) - - if bone_id!=0: - bone.head = bone.parent.head+mathutils.Vector(pos) * bone.parent.matrix - #print(dir(rot)) - #print("rot:",rot) - #print("matrix:",bone.parent.matrix) - - tempM = rot.to_4x4()*bone.parent.matrix - #bone.matrix = tempM - bone.transform(tempM, scale=False, roll=True) - #bone.matrix_local = tempM - else: - bone.head = mathutils.Vector(pos) - #bone.matrix = rot - bone.transform(rot, scale=False, roll=True) - #bone.matrix_local = rot - bvec = bone.tail- bone.head - bvec.normalize() - bone.tail = bone.head + 0.1 * bvec - #bone.tail = bone.head + 1 * bvec - - -#http://www.blender.org/forum/viewtopic.php?t=13340&sid=8b17d5de07b17960021bbd72cac0495f -def fixRollZ(b): - v = (b.tail-b.head)/b.length - b.roll -= math.degrees(math.atan2(v[0]*v[2]*(1 - v[1]),v[0]*v[0] + v[1]*v[2]*v[2])) -def fixRoll(b): - v = (b.tail-b.head)/b.length - if v[2]*v[2] > .5: - #align X-axis - b.roll += math.degrees(math.atan2(v[0]*v[2]*(1 - v[1]),v[2]*v[2] + v[1]*v[0]*v[0])) - else: - #align Z-axis - b.roll -= math.degrees(math.atan2(v[0]*v[2]*(1 - v[1]),v[0]*v[0] + v[1]*v[2]*v[2])) -""" #did not port this yet unstable but work in some ways -def make_bone_position3(): - for bone in md5_bones: - #print(dir(bone)) - bpy.ops.object.mode_set(mode='EDIT') - newbone = ob_new.data.edit_bones.new(bone.name) - #parent the bone - print("DRI:",dir(newbone)) - parentbone = None - print("bone name:",bone.name) - #note bone location is set in the real space or global not local - bonesize = bpy.types.Scene.unrealbonesize - if bone.name != bone.parent: - - pos_x = bone.bindpos[0] - pos_y = bone.bindpos[1] - pos_z = bone.bindpos[2] - - #print( "LINKING:" , bone.parent ,"j") - parentbone = ob_new.data.edit_bones[bone.parent] - newbone.parent = parentbone - - rotmatrix = bone.bindmat.to_matrix().to_4x4().to_3x3() # XXX, redundant matrix conversion? - newbone.transform(bone.bindmat.to_matrix().to_4x4(),True,True) - #parent_head = parentbone.matrix.to_quaternion().inverse() * parentbone.head - #parent_tail = parentbone.matrix.to_quaternion().inverse() * parentbone.tail - #location=Vector(pos_x,pos_y,pos_z) - #set_position = (parent_tail - parent_head) + location - #print("tmp head:",set_position) - - #pos_x = set_position.x - #pos_y = set_position.y - #pos_z = set_position.z - - - newbone.head.x = parentbone.head.x + pos_x - newbone.head.y = parentbone.head.y + pos_y - newbone.head.z = parentbone.head.z + pos_z - #print("head:",newbone.head) - newbone.tail.x = parentbone.head.x + (pos_x + bonesize * rotmatrix[0][1]) - newbone.tail.y = parentbone.head.y + (pos_y + bonesize * rotmatrix[1][1]) - newbone.tail.z = parentbone.head.z + (pos_z + bonesize * rotmatrix[2][1]) - #newbone.roll = fixRoll(newbone) - else: - #print("rotmatrix:",dir(bone.bindmat.to_matrix().resize_4x4())) - #rotmatrix = bone.bindmat.to_matrix().resize_4x4().to_3x3() # XXX, redundant matrix conversion? - rotmatrix = bone.bindmat.to_matrix().to_3x3() # XXX, redundant matrix conversion? - #newbone.transform(bone.bindmat.to_matrix(),True,True) - newbone.head.x = bone.bindpos[0] - newbone.head.y = bone.bindpos[1] - newbone.head.z = bone.bindpos[2] - newbone.tail.x = bone.bindpos[0] + bonesize * rotmatrix[0][1] - newbone.tail.y = bone.bindpos[1] + bonesize * rotmatrix[1][1] - newbone.tail.z = bone.bindpos[2] + bonesize * rotmatrix[2][1] - #newbone.roll = fixRoll(newbone) - #print("no parent") -""" - - -#import psk file -def pskimport(filename,importmesh,importbone,bDebugLogPSK,importmultiuvtextures): - global DEBUGLOG, plik,vertexes,uvcoord,faceslist,num_faces,facemat,facesmooth,m - global vertexes_ids,bonesdata,meshesdata,groups,num_materials,skala,flipyz,flipuv,amt,vertices,faces - points = [] - vertexes = [] - vertices = [] - uvcoord = [] - faceslist = [] - datafaces = [] - faces = [] - facemat = [] - facesmooth = [] - groups = [] - vertexes_ids = [] - bonesdata = {} - meshesdata ={} - - DEBUGLOG = bDebugLogPSK - print ("--------------------------------------------------") - print ("---------SCRIPT EXECUTING PYTHON IMPORTER---------") - print ("--------------------------------------------------") - print (" DEBUG Log:",bDebugLogPSK) - print ("Importing file: ", filename) - - plik = open(filename,'rb') - word(20),i(3) - - #------POINTS------ - print ('reading points') - word(20) - data = i(3) - num_points = data[2] - for m in range(num_points): - v=f(3) - v1 =v[0]*skala - v2 =v[1]*skala - v3 =v[2]*skala - if flipyz == False: - points.append([v1,v2,v3]) - if flipyz == True: - points.append([v1,-v3,v2]) - vertexes_ids.append([]) - - #------VERTEXES---- - print ('reading vertexes') - word(20) - data = i(3) - num_vertexes = data[2] - for m in range(num_vertexes): - data1 = H(2) - vertexes.append(points[data1[0]]) - vertices.append(points[data1[0]]) - #vertices.extend(points[data1[0]]) - #vertices.extend([(points[data1[0]][0],points[data1[0]][1],points[data1[0]][2] )]) - #vertices.extend([(points[data1[0]][0],points[data1[0]][1],points[data1[0]][2] )]) - #print(points[data1[0]]) - if flipuv == False: - uvcoord.append([f(1)[0],1-f(1)[0]]) - if flipuv == True: - uvcoord.append([f(1)[0],f(1)[0]]) - vertexes_ids[data1[0]].append(m) - b(2),h(1) - - - #------FACES------- - print ('reading faces') - word(20) - data = i(3) - num_faces = data[2] - for m in range(num_faces): - v0=H(1)[0] - v1=H(1)[0] - v2=H(1)[0] - faceslist.append([v1,v0,v2]) - faces.extend([(v1,v0,v2,0)]) - #faces.append([v1,v0,v2]) - #print((v1,v0,v2,0)) - mat_ids = B(2) - facemat.append(mat_ids) - if str(mat_ids[0]) not in meshesdata: - meshesdata[str(mat_ids[0])] = [] - meshesdata[str(mat_ids[0])].append(m) - facesmooth.append(i(1)[0]) - #datafaces.append([v1,v0,v2],mat_ids - - #------MATERIALS--- - print ('making materials') - word(20) - data = i(3) - num_materials = data[2] - for m in range(num_materials): - name = word(64) - print ('read materials from',name) - matdata = bpy.data.materials.new(name) - #try: - #mat = Material.Get(namemodel+'-'+str(m)) - #mat = Material.Get(name) - #except: - #mat = Material.New(namemodel+'-'+str(m)) - #mat = Material.New(name) - i(6) - #make_materials(name,mat) - - #-------BONES------ - print ('reading bones') - #check_armature() - check_armature() - word(20) - data = i(3) - num_bones = data[2] - for m in range(num_bones): - #print(str(m)) #index - bonesdata[str(m)] = [] - bonename = word(64) - bonename = bonename#.strip() - bonename = bonename.strip() - #print(bonename)#bone name - bonesdata[str(m)].append(bonename) - bonesdata[str(m)].append(i(3)) - bonesdata[str(m)].append(f(11)) - make_bone() - make_bone_parent() - bones_matrix() - make_bone_position1() - - - #-------SKINNING--- - print ('making skinning') - word(20) - data = i(3) - num_groups = data[2] - - for m in range(num_groups): - w = f(1)[0] - v_id = i(1)[0] - gr = i(1)[0] - groups.append([w,v_id,gr]) - #create Mesh - drawmesh() - - print ("IMPORTER PSK Blender 2.6 completed") -#End of def pskimport######################### - -def psaimport(filename): - global plik,bonesdata,animdata,anim_offset,animation_names - bonesdata = {} - animation_names = [] - animation_num_bones = [] - animation_num_keys = [] - animation_loc_keys = [] - animation_rot_keys = [] - animdata = {} - plik = open(filename,'rb') - print (word(20),i(3)) - - #-------BONES------ - #check_armature_for_psa() - print (word(20)) - data = i(3) - #print data - num_bones = data[2] - for m in range(num_bones): - bonesdata[str(m)] = [] - name = word(64) - bonesdata[str(m)].append(name) - bonesdata[str(m)].append(i(3)) - bonesdata[str(m)].append(f(11)) - - - #--------ANIMATIONS-INFO - print (word(20)) - data = i(3) - #print data - for m in range(data[2]): - name_animation = word(64)#name animation - print("NAME:",name_animation) - animation_names.append(name_animation) - word(64)#name of owner of animation ? - data = i(4)#num bones - 0 - 0 - num keys for all bones for this animation - num_bones = data[0] - animation_num_bones.append(num_bones) - f(3) - data = i(3) - num_keys = data[2] - animation_num_keys.append(num_keys) - print (plik.tell()) - - #--------ANIMATIONS-KEYS - print (word(20)) - data = i(3) - #print data - anim_offset = {} - seek = plik.tell() - for m in range(len(animation_names)): - anim_name = animation_names[m] - anim_bones = animation_num_bones[m] - anim_keys = animation_num_keys[m] - anim_offset[anim_name] = [] - anim_offset[anim_name].append(seek) - anim_offset[anim_name].append(anim_keys) - anim_offset[anim_name].append(anim_bones) - seek+=anim_keys*anim_bones*32 - - -def getInputFilename(self,filename,importmesh,importbone,bDebugLogPSK,importmultiuvtextures): - checktype = filename.split('\\')[-1].split('.')[1] - print ("------------",filename) - if checktype.lower() != 'psk': - print (" Selected file = ",filename) - raise (IOError, "The selected input file is not a *.psk file") - #self.report({'INFO'}, ("Selected file:"+ filename)) - else: - pskimport(filename,importmesh,importbone,bDebugLogPSK,importmultiuvtextures) -#import panel -class IMPORT_OT_psk(bpy.types.Operator): - """Load a skeleton mesh psk File""" - bl_idname = "import_scene.psk" - bl_label = "Import PSK" - bl_space_type = "PROPERTIES" - bl_region_type = "WINDOW" - bl_options = {'UNDO'} - - # List of operator properties, the attributes will be assigned - # to the class instance from the operator settings before calling. - filepath = StringProperty( - subtype='FILE_PATH', - ) - filter_glob = StringProperty( - default="*.psk", - options={'HIDDEN'}, - ) - importmesh = BoolProperty( - name="Mesh", - description="Import mesh only. (not yet build.)", - default=True, - ) - importbone = BoolProperty( - name="Bones", - description="Import bones only. Current not working yet", - default=True, - ) - importmultiuvtextures = BoolProperty( - name="Single UV Texture(s)", - description="Single or Multi uv textures", - default=True, - ) - bDebugLogPSK = BoolProperty( - name="Debug Log.txt", - description="Log the output of raw format. It will save in " \ - "current file dir. Note this just for testing", - default=False, - ) - unrealbonesize = FloatProperty( - name="Bone Length", - description="Bone Length from head to tail distance", - default=1, - min=0.001, - max=1000, - ) - - def execute(self, context): - bpy.types.Scene.unrealbonesize = self.unrealbonesize - getInputFilename(self,self.filepath,self.importmesh,self.importbone,self.bDebugLogPSK,self.importmultiuvtextures) - return {'FINISHED'} - - def invoke(self, context, event): - wm = context.window_manager - wm.fileselect_add(self) - return {'RUNNING_MODAL'} -#import panel psk -class OBJECT_OT_PSKPath(bpy.types.Operator): - bl_idname = "object.pskpath" - bl_label = "PSK Path" - __doc__ = "" - - filepath = StringProperty( - subtype='FILE_PATH', - ) - filter_glob = StringProperty( - default="*.psk", - options={'HIDDEN'}, - ) - importmesh = BoolProperty( - name="Mesh", - description="Import mesh only. (not yet build.)", - default=True, - ) - importbone = BoolProperty( - name="Bones", - description="Import bones only. Current not working yet", - default=True, - ) - importmultiuvtextures = BoolProperty( - name="Single UV Texture(s)", - description="Single or Multi uv textures", - default=True, - ) - bDebugLogPSK = BoolProperty( - name="Debug Log.txt", - description="Log the output of raw format. It will save in " \ - "current file dir. Note this just for testing", - default=False, - ) - unrealbonesize = FloatProperty( - name="Bone Length", - description="Bone Length from head to tail distance", - default=1, - min=0.001, - max=1000, - ) - - def execute(self, context): - #context.scene.importpskpath = self.properties.filepath - bpy.types.Scene.unrealbonesize = self.unrealbonesize - getInputFilename(self,self.filepath,self.importmesh,self.importbone,self.bDebugLogPSK,self.importmultiuvtextures) - return {'FINISHED'} - - def invoke(self, context, event): - #bpy.context.window_manager.fileselect_add(self) - wm = context.window_manager - wm.fileselect_add(self) - return {'RUNNING_MODAL'} -#import panel psa -class OBJECT_OT_PSAPath(bpy.types.Operator): - bl_idname = "object.psapath" - bl_label = "PSA Path" - __doc__ = "" - - filepath = StringProperty(name="PSA File Path", description="Filepath used for importing the PSA file", maxlen= 1024, default= "") - filter_glob = StringProperty( - default="*.psa", - options={'HIDDEN'}, - ) - def execute(self, context): - #context.scene.importpsapath = self.properties.filepath - psaimport(self.filepath) - return {'FINISHED'} - - def invoke(self, context, event): - bpy.context.window_manager.fileselect_add(self) - return {'RUNNING_MODAL'} - -class OBJECT_OT_Path(bpy.types.Operator): - bl_idname = "object.path" - bl_label = "MESH BUILD TEST" - __doc__ = "" - # generic transform props - view_align = BoolProperty( - name="Align to View", - default=False, - ) - location = FloatVectorProperty( - name="Location", - subtype='TRANSLATION', - ) - rotation = FloatVectorProperty( - name="Rotation", - subtype='EULER', - ) - def execute(self, context): - return {'FINISHED'} - - def invoke(self, context, event): - me = bpy.data.meshes.new("test") - obmade = bpy.data.objects.new("TestObject",me) - print("Create Simple Mesh") - bpy.data.scenes[0].objects.link(obmade) - for i in bpy.context.scene.objects: i.select = False #deselect all objects - obmade.select = True - bpy.context.scene.objects.active = obmade - - verts = [(0,0,0),(2,0,0),(2,0,2)] - edges = [(0,1),(1,2),(2,0)] - faces = [] - faces.extend([(0,1,2,0)]) - #me.vertices.add(len(verts)) - #print(dir(me)) - me.vertices.add(len(verts)) - me.tessfaces.add(len(faces)) - for face in me.tessfaces: - print(dir(face)) - - me.vertices.foreach_set("co", unpack_list(verts)) - me.tessfaces.foreach_set("vertices_raw", unpack_list(faces)) - me.edges.add(len(edges)) - me.edges.foreach_set("vertices", unpack_list(edges)) - - #print(len(me.tessfaces)) - me.tessface_uv_textures.new("uvtexture") - #for uv in me.tessface_uv_textures: - #print(len(uv.data)) - #print(dir(uv.data[0])) - #print(dir(uv.data[0].uv1)) - return {'RUNNING_MODAL'} - -#import menu panel tool bar -class VIEW3D_PT_unrealimport_objectmode(bpy.types.Panel): - bl_space_type = "VIEW_3D" - bl_region_type = "TOOLS" - bl_label = "Import PSK/PSA" - - @classmethod - def poll(cls, context): - return context.active_object - - def draw(self, context): - layout = self.layout - rd = context.scene - - row2 = layout.row(align=True) - row2.operator(OBJECT_OT_PSKPath.bl_idname) - row2.operator(OBJECT_OT_PSAPath.bl_idname) - row2.operator(OBJECT_OT_Path.bl_idname) -#import panel -def menu_func(self, context): - self.layout.operator(IMPORT_OT_psk.bl_idname, text="Skeleton Mesh (.psk)") - -def register(): - bpy.utils.register_module(__name__) - bpy.types.INFO_MT_file_import.append(menu_func) - -def unregister(): - bpy.utils.unregister_module(__name__) - bpy.types.INFO_MT_file_import.remove(menu_func) - -if __name__ == "__main__": - register() - -#note this only read the data and will not be place in the scene -#getInputFilename('C:\\blenderfiles\\BotA.psk') -#getInputFilename('C:\\blenderfiles\\AA.PSK') -#getInputFilename('C:\\blender26x\\blender-2.psk')