Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ##Unreal 2 GEM file to Blender mesh converter V1.0
- ##
- ## * Imports a *gem file to a new mesh
- ## * Smoothing groups are shown as different material colors, faces with no smoothing will be white
- ## ** This version DOES NOT import armature
- ##
- ## *Tested with Blender V2.33a
- ##
- ##Author: D.M. Sturgeon (camg188 at the elYsium forum)
- #
- # 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- #
- ##USAGE#############################################
- #Set the input file name in the "infile" variable.
- #Run the script (alt-p).
- #Select any file. It will be ignored. This is leftover from the original script and needs to be removed.
- #-A new mesh will be created. It will be very large in Blender units.
- ####################################################
- #Locating the data section in the GEM file.
- #
- #Data formats
- #h = half word, 2 bytes
- #i = integer, 4 bytes
- #f = float, 4 bytes
- #Data is in little endian format.
- #
- #Open the *.gem file with a hex editor (like XVI32). Make sure it is displaying 16 bytes per line
- #
- #Locate VTX start:
- #gem vtx fmt = hhhh
- #From beginning of file scroll down, search for a set of nbrs like
- #(it usually starts right after a value of "\x803F")
- #nn 00 nn 00 nn 00 00 00 nn 00 nn 00 nn 00 00 00
- #nn 00 nn 00 nn 00 00 00 nn 00 nn 00 nn 00 00 00
- #nn 00 nn 00 nn 00 00 00 nn 00 nn 00 nn 00 00 00
- #where n generally gets larger down the list.
- #example:
- #02 00 02 00 00 00 00 00 01 00 01 00 01 00 00 00
- #00 00 00 00 02 00 00 00 03 00 03 00 03 00 00 00
- #05 00 05 00 04 00 00 00 04 00 04 00 05 00 00 00
- #07 00 07 00 06 00 00 00 06 00 06 00 07 00 00 00
- #09 00 09 00 08 00 00 00 08 00 08 00 09 00 00 00
- #Locate VTX end:
- #the pattern will break to an incrementing list of
- #00 00 01 00 02 00 03 00 ...
- #get the address of the first byte of this pattern starts
- #Calculate number of VTX records:
- #(VTX end - VTX start) / 8
- #
- #Look at the incrementing list of numbers (half word size, little endian format).
- #Scroll to the end of the list.
- #get the first half-word. It is the number of faces
- #skip ahead 8 bytes and get the half-word. It is the number of VTX
- #skip ahead 4 bytes and get the half-word. It is the number of PNTS
- #
- #Locate the FACE start:
- #gem face format = hhhh
- #Look at little further down the file for a bunch of 00 00 00 00 values.
- #The FACE data starts just after that, usually something like:
- #00 00 02 00 01 00 00 00 03 00 02 00 01 00 00 00
- #
- #Locate the PNTS start:
- #gem pnts format: fffhh
- #Look way ahead in the file, possibly search for hex 1A0000001B0000001C000000
- #the section after these incrementing hex values is the PNTS data
- #The last half word generally increased with each record.
- #Example:
- #89 C0 82 41 2E 8D 38 C2 74 0F D0 C0 01 00 00 00
- #3E EF B9 41 DA 49 37 C2 66 28 D0 C0 01 00 01 00
- #AD F4 89 41 B4 72 0F C2 CA 6F 0E C1 01 00 02 00
- #20 79 AD 41 75 9F 0E C2 2B 7E 0E C1 01 00 03 00
- #3C 74 42 41 2F F2 42 C2 98 1E B6 BE 01 00 04 00
- #7E 45 83 41 26 45 43 C2 84 D5 D3 C0 02 00 05 00
- #C0 9C BD 41 E3 A8 41 C2 35 C5 D3 C0 02 00 07 00
- #
- #Locate the UV start:
- #look a bit ahead for a section that looks like
- #nn nn nn nn nn nn jj 01 00 00 nn nn nn nn nn nn
- #nn nn nn nn nn nn jj 01 00 00 nn nn nn nn nn nn
- #nn nn nn nn nn nn jj 02 00 00 nn nn nn nn nn nn
- #nn nn nn nn nn nn jj 02 00 00 nn nn nn nn nn nn
- #nn nn nn nn nn nn jj 03 00 00 nn nn nn nn nn nn
- #nn nn nn nn nn nn jj 03 00 00 nn nn nn nn nn nn
- #nn nn nn nn nn nn jj 04 00 00 nn nn nn nn nn nn
- #nn nn nn nn nn nn jj 04 00 00 nn nn nn nn nn nn
- #where jj is an incrementing hex number
- #
- #uv data starts right after the 00 00 in the middle
- #gem uv format = ff
- #
- #Locate bone weight start:
- #Search for \x803f (float 1.0). Look for a pattern of integer|float. There will be lots of \x803F float values. This is the bone weight data.
- #####################################################
- import Blender
- from Blender import *
- import os, sys, string, math
- from string import *
- from struct import *
- from Blender import NMesh, Material, Window, Armature
- from Blender.Armature import *
- from Blender.Armature.Bone import *
- #####################################################
- infile = 'C:\\Program Files (x86)\\Epic Games\\Unreal Anthology\\Unreal2\\Meshes\\Characters\\MercFemHeavy\\MercFemHeavyBody.gem'
- print "Importing file: ", infile
- gemfile = file(infile,'rb')
- logf = file('C:\\gem2blendermesh.log','w')
- #
- objName = infile.split('\\')[-1].split('.')[0]
- mobj = Blender.Object.New('Mesh',objName)
- Tmsh = mobj.data
- print >> logf, "New Mesh = ",Tmsh.name
- #data locations - input by user before running script
- #MercFemale Heavy
- pnts_strt = 298760
- pnts_nbr = 1379
- vtx_strt = 32592
- vtx_nbr = 2540
- face_strt = 58074
- face_nbr = 2732
- uv_strt = 356568
- uv_nbr = 2854
- wgt_strt = 320824
- wgt_nbr = 1710
- #MercFemHeavyHead01.gem
- #vtx_strt = 2592
- #vtx_nbr = 314
- #face_strt = 5814
- #face_nbr = 388
- #pnts_strt = 41336
- #pnts_nbr = 226
- #uv_strt = 51408
- #uv_nbr = 314
- #wgt_strt = 44952
- #wgt_nbr = 311
- #Aida.gem
- #pnts_strt = 1615316
- #pnts_nbr = 2586
- #vtx_strt = 3214570
- #vtx_nbr = 3876
- #face_strt = 1177788
- #face_nbr = 4899
- #uv_strt = 1729268
- #uv_nbr = 3876
- #Colonist Female
- #pnts_strt = 207634
- #pnts_nbr = 1120
- #vtx_strt = 7520
- #vtx_nbr = 1611
- #face_strt = 23712
- #face_nbr = 2044
- #uv_strt = 254810
- #uv_nbr = 1611
- #wgt_start = 225554
- #wgt_nbr = 1168
- #Code Start#######################################################
- #read the PNTS data
- #data format = fffhh
- #field 4 = 1,2 or 3 - unknown function
- gemfile.seek(pnts_strt)
- recCount = pnts_nbr
- counter = 0
- while counter < recCount:
- counter = counter + 1
- indata = unpack('3f2h',gemfile.read(16))
- Tmsh.verts.append(NMesh.Vert(indata[0],indata[1],indata[2]))
- #read the VTX data
- gemfile.seek(vtx_strt)
- recCount = vtx_nbr
- counter = 0
- VTX = []
- while counter < recCount:
- counter = counter + 1
- indata = unpack('hhhh',gemfile.read(8))
- VTX.append(indata[0])
- #read the UV data
- gemfile.seek(uv_strt)
- recCount = uv_nbr
- counter = 0
- UVCoords = []
- while counter < recCount:
- counter = counter + 1
- indata = unpack('ff',gemfile.read(8))
- UVCoords.append([indata[0],1-indata[1]])
- #read the FACE data
- gemfile.seek(face_strt)
- recCount = face_nbr
- counter = 0
- #struct hhhh = nA,nB,nC,nD
- #where A,B,C seem to be indices to vertices to form a face.
- #nD = probably material id
- SGlist = []
- counter = 0
- while counter < recCount:
- counter = counter + 1
- indata = unpack('hhhh',gemfile.read(8))
- #VTX[n] = index to PNTS, PNTS is the Tmsh.verts list
- # print indata
- PNTSA = VTX[indata[0]]
- PNTSB = VTX[indata[1]]
- PNTSC = VTX[indata[2]]
- Tmsh.faces.append(NMesh.Face([Tmsh.verts[PNTSA],Tmsh.verts[PNTSB],Tmsh.verts[PNTSC]]))
- #get the uv coords - UVCoords[n][0] = u0, UVCoords[n][1] = v0 of the VTX point
- u0 = UVCoords[indata[0]][0]
- v0 = UVCoords[indata[0]][1]
- u1 = UVCoords[indata[1]][0]
- v1 = UVCoords[indata[1]][1]
- u2 = UVCoords[indata[2]][0]
- v2 = UVCoords[indata[2]][1]
- #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)]
- #collect a list of the material groups
- if SGlist.count(indata[3]) == 0:
- SGlist.append(indata[3])
- #assign a material index to the face
- Tmsh.faces[-1].materialIndex = SGlist.index(indata[3])
- #create a material for each UnknownGrp
- for x in range(len(SGlist)):
- MatName = "SmthGrp"+str(SGlist[x])
- if SGlist[x] == 0:
- MatName = 'SmthGrpNone'
- newMat = Material.New(MatName)
- newMat.mode |= Material.Modes.SHADELESS
- #change the overall darkness of each material in a range between 0.1 and 0.9
- tmpVal = ((float(x)+1.0)/(len(SGlist))*0.7)+0.1
- #set no smthgrp to light gray
- if SGlist[x] == 0: tmpVal = 0.9
- newMat.R = tmpVal
- newMat.G = tmpVal
- newMat.B = tmpVal
- #Change the color of each material slightly
- if SGlist[x] != 0:
- if x % 3 == 0:
- if newMat.R < 0.5: newMat.R += 0.25
- else: newMat.R -= 0.25
- if x % 3 == 1:
- if newMat.G < 0.5: newMat.G += 0.25
- else: newMat.G -= 0.25
- if x % 3 == 2:
- if newMat.B < 0.5: newMat.B += 0.25
- else: newMat.B -= 0.25
- #Add the material to the mesh
- Tmsh.materials.append(newMat)
- Tmsh.update()
- #read the Weight data
- #data format = if
- #need to link mesh to an object before adding vertex groups
- NMesh.PutRaw(Tmsh,objName)
- vgrp = []
- bnwgt = []
- vtxidx = 0
- wgtsum = 0
- gemfile.seek(wgt_strt)
- recCount = wgt_nbr
- counter = 0
- while counter < recCount:
- counter = counter + 1
- indata = unpack('if',gemfile.read(8))
- bnwgt.append([indata[0],indata[1]])
- if vgrp.count(str(indata[0])) == 0:
- vgrp.append(str(indata[0]))
- Tmsh.addVertGroup(str(indata[0]))
- #keep processing the same vertex until the weight is 1
- if wgtsum > 0.999:
- wgtsum = 0
- vtxidx += 1
- Tmsh.assignVertsToGroup(str(indata[0]),[vtxidx],indata[1],'add')
- wgtsum += indata[1]
- Tmsh.update()
- gemfile.close()
- logf.close()
- #Blender.Window.RedrawAll()
- print "PSK2Blender completed"
- ##End #########################
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement