Advertisement
Guest User

GreatEmerald

a guest
Jan 23rd, 2009
224
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.59 KB | None | 0 0
  1. ##Unreal 2 GEM file to Blender mesh converter V1.0
  2. ##
  3. ## * Imports a *gem file to a new mesh
  4. ## * Smoothing groups are shown as different material colors, faces with no smoothing will be white
  5. ## **  This version DOES NOT import armature
  6. ##
  7. ## *Tested with Blender V2.33a
  8. ##
  9. ##Author: D.M. Sturgeon (camg188 at the elYsium forum)
  10. #
  11. # This program is free software; you can redistribute it and/or modify
  12. # it under the terms of the GNU General Public License as published by
  13. # the Free Software Foundation; either version 2 of the License, or
  14. # (at your option) any later version.
  15. #
  16. # This program is distributed in the hope that it will be useful,
  17. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19. # GNU General Public License for more details.
  20. #
  21. # You should have received a copy of the GNU General Public License
  22. # along with this program; if not, write to the Free Software
  23. # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  24. #
  25. ##USAGE#############################################
  26. #Set the input file name in the "infile" variable.
  27. #Run the script (alt-p).
  28. #Select any file. It will be ignored. This is leftover from the original script and needs to be removed.
  29. #-A new mesh will be created.  It will be very large in Blender units.
  30. ####################################################
  31. #Locating the data section in the GEM file.
  32. #
  33. #Data formats
  34. #h = half word, 2 bytes
  35. #i = integer, 4 bytes
  36. #f = float, 4 bytes
  37. #Data is in little endian format.
  38. #
  39. #Open the *.gem file with a hex editor (like XVI32).  Make sure it is displaying 16 bytes per line
  40. #
  41. #Locate VTX start:
  42. #gem vtx fmt = hhhh
  43. #From beginning of file scroll down, search for a set of nbrs like
  44. #(it usually starts right after a value of "\x803F")
  45. #nn 00 nn 00 nn 00 00 00 nn 00 nn 00 nn 00 00 00
  46. #nn 00 nn 00 nn 00 00 00 nn 00 nn 00 nn 00 00 00
  47. #nn 00 nn 00 nn 00 00 00 nn 00 nn 00 nn 00 00 00
  48. #where n generally gets larger down the list.
  49. #example:
  50. #02 00 02 00 00 00 00 00 01 00 01 00 01 00 00 00
  51. #00 00 00 00 02 00 00 00 03 00 03 00 03 00 00 00
  52. #05 00 05 00 04 00 00 00 04 00 04 00 05 00 00 00
  53. #07 00 07 00 06 00 00 00 06 00 06 00 07 00 00 00
  54. #09 00 09 00 08 00 00 00 08 00 08 00 09 00 00 00
  55. #Locate VTX end:
  56. #the pattern will break to an incrementing list of
  57. #00 00 01 00 02 00 03 00 ...
  58. #get the address of the first byte of this pattern starts
  59. #Calculate number of VTX records:
  60. #(VTX end - VTX start) / 8
  61. #
  62. #Look at the incrementing list of numbers (half word size, little endian format).
  63. #Scroll to the end of the list.
  64. #get the first half-word. It is the number of faces
  65. #skip ahead 8 bytes and get the half-word. It is the number of VTX
  66. #skip ahead 4 bytes and get the half-word. It is the number of PNTS
  67. #
  68. #Locate the FACE start:
  69. #gem face format = hhhh
  70. #Look at little further down the file for a bunch of 00 00 00 00 values.
  71. #The FACE data starts just after that, usually something like:
  72. #00 00 02 00 01 00 00 00 03 00 02 00 01 00 00 00
  73. #
  74. #Locate the PNTS start:
  75. #gem pnts format: fffhh
  76. #Look way ahead in the file, possibly search for hex 1A0000001B0000001C000000
  77. #the section after these incrementing hex values is the PNTS data
  78. #The last half word generally increased with each record.
  79. #Example:
  80. #89 C0 82 41 2E 8D 38 C2 74 0F D0 C0 01 00 00 00
  81. #3E EF B9 41 DA 49 37 C2 66 28 D0 C0 01 00 01 00
  82. #AD F4 89 41 B4 72 0F C2 CA 6F 0E C1 01 00 02 00
  83. #20 79 AD 41 75 9F 0E C2 2B 7E 0E C1 01 00 03 00
  84. #3C 74 42 41 2F F2 42 C2 98 1E B6 BE 01 00 04 00
  85. #7E 45 83 41 26 45 43 C2 84 D5 D3 C0 02 00 05 00
  86. #C0 9C BD 41 E3 A8 41 C2 35 C5 D3 C0 02 00 07 00
  87. #
  88. #Locate the UV start:
  89. #look a bit ahead for a section that looks like
  90. #nn nn nn nn nn nn jj 01 00 00 nn nn nn nn nn nn
  91. #nn nn nn nn nn nn jj 01 00 00 nn nn nn nn nn nn
  92. #nn nn nn nn nn nn jj 02 00 00 nn nn nn nn nn nn
  93. #nn nn nn nn nn nn jj 02 00 00 nn nn nn nn nn nn
  94. #nn nn nn nn nn nn jj 03 00 00 nn nn nn nn nn nn
  95. #nn nn nn nn nn nn jj 03 00 00 nn nn nn nn nn nn
  96. #nn nn nn nn nn nn jj 04 00 00 nn nn nn nn nn nn
  97. #nn nn nn nn nn nn jj 04 00 00 nn nn nn nn nn nn
  98. #where jj is an incrementing hex number
  99. #
  100. #uv data starts right after the 00 00 in the middle
  101. #gem uv format = ff
  102. #
  103. #Locate bone weight start:
  104. #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.
  105. #####################################################
  106.  
  107. import Blender
  108. from Blender import *
  109. import os, sys, string, math
  110. from string import *
  111. from struct import *
  112. from Blender import NMesh, Material, Window, Armature
  113. from Blender.Armature import *
  114. from Blender.Armature.Bone import *
  115.  
  116. #####################################################
  117.  
  118. infile = 'C:\\Program Files (x86)\\Epic Games\\Unreal Anthology\\Unreal2\\Meshes\\Characters\\MercFemHeavy\\MercFemHeavyBody.gem'
  119. print "Importing file: ", infile
  120. gemfile = file(infile,'rb')
  121. logf = file('C:\\gem2blendermesh.log','w')
  122. #
  123. objName = infile.split('\\')[-1].split('.')[0]
  124. mobj = Blender.Object.New('Mesh',objName)
  125. Tmsh = mobj.data
  126. print >> logf, "New Mesh = ",Tmsh.name
  127.  
  128. #data locations - input by user before running script
  129.  
  130. #MercFemale Heavy
  131. pnts_strt = 298760
  132. pnts_nbr = 1379
  133. vtx_strt = 32592
  134. vtx_nbr = 2540
  135. face_strt = 58074
  136. face_nbr = 2732
  137. uv_strt = 356568
  138. uv_nbr = 2854
  139. wgt_strt = 320824
  140. wgt_nbr = 1710
  141.  
  142. #MercFemHeavyHead01.gem
  143. #vtx_strt = 2592
  144. #vtx_nbr = 314
  145. #face_strt = 5814
  146. #face_nbr = 388
  147. #pnts_strt = 41336
  148. #pnts_nbr = 226
  149. #uv_strt = 51408
  150. #uv_nbr = 314
  151. #wgt_strt = 44952
  152. #wgt_nbr = 311
  153.  
  154. #Aida.gem
  155. #pnts_strt = 1615316
  156. #pnts_nbr = 2586
  157. #vtx_strt = 3214570
  158. #vtx_nbr = 3876
  159. #face_strt = 1177788
  160. #face_nbr = 4899
  161. #uv_strt = 1729268
  162. #uv_nbr = 3876
  163.  
  164. #Colonist Female
  165. #pnts_strt = 207634
  166. #pnts_nbr = 1120
  167. #vtx_strt = 7520
  168. #vtx_nbr = 1611
  169. #face_strt = 23712
  170. #face_nbr = 2044
  171. #uv_strt = 254810
  172. #uv_nbr = 1611
  173. #wgt_start = 225554
  174. #wgt_nbr = 1168
  175.  
  176. #Code Start#######################################################
  177. #read the PNTS data
  178. #data format = fffhh
  179. #field 4 = 1,2 or 3 - unknown function
  180. gemfile.seek(pnts_strt)
  181. recCount = pnts_nbr
  182. counter = 0
  183. while counter < recCount:
  184.   counter = counter + 1
  185.   indata = unpack('3f2h',gemfile.read(16))
  186.   Tmsh.verts.append(NMesh.Vert(indata[0],indata[1],indata[2]))
  187.  
  188. #read the VTX data
  189. gemfile.seek(vtx_strt)
  190. recCount = vtx_nbr
  191. counter = 0
  192. VTX = []
  193. while counter < recCount:
  194.   counter = counter + 1
  195.   indata = unpack('hhhh',gemfile.read(8))
  196.   VTX.append(indata[0])
  197.  
  198. #read the UV data
  199. gemfile.seek(uv_strt)
  200. recCount = uv_nbr
  201. counter = 0
  202. UVCoords = []
  203. while counter < recCount:
  204.   counter = counter + 1
  205.   indata = unpack('ff',gemfile.read(8))
  206.   UVCoords.append([indata[0],1-indata[1]])
  207.  
  208. #read the FACE data
  209. gemfile.seek(face_strt)
  210. recCount = face_nbr
  211. counter = 0
  212.  
  213. #struct hhhh = nA,nB,nC,nD
  214. #where A,B,C seem to be indices to vertices to form a face.
  215. #nD = probably material id
  216. SGlist = []
  217. counter = 0
  218. while counter < recCount:
  219.   counter = counter + 1
  220.   indata = unpack('hhhh',gemfile.read(8))
  221.   #VTX[n] = index to PNTS, PNTS is the Tmsh.verts list
  222. #  print indata
  223.   PNTSA = VTX[indata[0]]
  224.   PNTSB = VTX[indata[1]]
  225.   PNTSC = VTX[indata[2]]
  226.   Tmsh.faces.append(NMesh.Face([Tmsh.verts[PNTSA],Tmsh.verts[PNTSB],Tmsh.verts[PNTSC]]))
  227.   #get the uv coords - UVCoords[n][0] = u0, UVCoords[n][1] = v0 of the VTX point
  228.   u0 = UVCoords[indata[0]][0]
  229.   v0 = UVCoords[indata[0]][1]
  230.   u1 = UVCoords[indata[1]][0]
  231.   v1 = UVCoords[indata[1]][1]
  232.   u2 = UVCoords[indata[2]][0]
  233.   v2 = UVCoords[indata[2]][1]
  234.   #update the uv var of the last item in the Tmsh.faces list
  235.   # which is the face just added above
  236.   Tmsh.faces[-1].uv = [(u0,v0),(u1,v1),(u2,v2)]
  237.   #collect a list of the material groups
  238.   if SGlist.count(indata[3]) == 0:
  239.     SGlist.append(indata[3])
  240.   #assign a material index to the face
  241.   Tmsh.faces[-1].materialIndex = SGlist.index(indata[3])
  242.  
  243. #create a material for each UnknownGrp
  244. for x in range(len(SGlist)):
  245.   MatName = "SmthGrp"+str(SGlist[x])
  246.   if SGlist[x] == 0:
  247.     MatName = 'SmthGrpNone'
  248.   newMat = Material.New(MatName)
  249.   newMat.mode |= Material.Modes.SHADELESS
  250.   #change the overall darkness of each material in a range between 0.1 and 0.9
  251.   tmpVal = ((float(x)+1.0)/(len(SGlist))*0.7)+0.1
  252.   #set no smthgrp to light gray
  253.   if SGlist[x] == 0:  tmpVal = 0.9
  254.   newMat.R = tmpVal
  255.   newMat.G = tmpVal
  256.   newMat.B = tmpVal
  257.   #Change the color of each material slightly
  258.   if SGlist[x] != 0:
  259.     if x % 3 == 0:
  260.       if newMat.R < 0.5: newMat.R += 0.25
  261.       else: newMat.R -= 0.25
  262.     if x % 3 == 1:
  263.       if newMat.G < 0.5: newMat.G += 0.25
  264.       else: newMat.G -= 0.25
  265.     if x % 3 == 2:
  266.       if newMat.B < 0.5: newMat.B += 0.25
  267.       else: newMat.B -= 0.25
  268.   #Add the material to the mesh
  269.   Tmsh.materials.append(newMat)
  270.  
  271. Tmsh.update()
  272.  
  273. #read the Weight data
  274. #data format = if
  275. #need to link mesh to an object before adding vertex groups
  276. NMesh.PutRaw(Tmsh,objName)
  277. vgrp = []
  278. bnwgt = []
  279. vtxidx = 0
  280. wgtsum = 0
  281. gemfile.seek(wgt_strt)
  282. recCount = wgt_nbr
  283. counter = 0
  284. while counter < recCount:
  285.   counter = counter + 1
  286.   indata = unpack('if',gemfile.read(8))
  287.   bnwgt.append([indata[0],indata[1]])
  288.   if vgrp.count(str(indata[0])) == 0:
  289.     vgrp.append(str(indata[0]))
  290.     Tmsh.addVertGroup(str(indata[0]))
  291.   #keep processing the same vertex until the weight is 1
  292.   if wgtsum > 0.999:
  293.     wgtsum = 0
  294.     vtxidx += 1
  295.   Tmsh.assignVertsToGroup(str(indata[0]),[vtxidx],indata[1],'add')
  296.   wgtsum += indata[1]
  297.  
  298. Tmsh.update()
  299.  
  300. gemfile.close()
  301. logf.close()
  302.  
  303. #Blender.Window.RedrawAll()
  304.  
  305. print "PSK2Blender completed"
  306. ##End #########################
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement