The VG Resource

Full Version: Gravity Rush 2
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hey, guys! So with PS4 games starting to get some exposure, I've decided to start ripping models from Gravity Rush 2. I've had some help over on Xentax, and I've managed to write a Python script that does a pretty good job with Kat/Kitten's many outfits:[Image: aX99Wai.png]
(Unfortunately, I don't have the files for the 2B outfit.)
The script works for Raven/Crow too, but I think most models are quite different from the playable characters.


kit00.gfx-kit21.gfx for Kat
cro00.gfx-cro03.gfx for Raven

The script works with Model Researcher Pro. I want to fine-tune it so that there aren't any errors or missing faces, but I also want to try to get the bones, which are in separate files (.mot) and must be assigned weights when the models are loaded in-game. The only problem with that is that I'm not entirely sure how the bone data looks in a hex file, or if I can use Model Researcher to visualize them. I may have to write a Blender script for this sooner than I'd hoped, haha! If you guys know a thing or two about ripping bones and weights, please do tell.

Code:
import mrp
import random

file = mrp.get_bfile()
vertStart = 0

subMeshes = []
#we gotta create the meshes.
#this should be done as we collect
#the vertices, faces, and uvs.
fileComplete = False
meshCounter = 1

#there are some instances where
#vertex blocks are 36 bytes, not 32.
#vertexType will tell me
#what size I'm processing.
vertexType = 32

while True:
   file.seek(30,1)
   checkedByte = file.readHalfFloat()
   if checkedByte == 1.0 or checkedByte == -1.0:
       file.seek(-32,1)
       vertStart = file.tell()
       break
       
while fileComplete == False:
   print(" ")
   print("Begin Mesh" + str(meshCounter).zfill(2))
   print("vertexType: " + str(vertexType))
   mesh = mrp.create_mesh("Mesh" + str(meshCounter).zfill(2))
   verts = []
   faces = []
   uvs = []
   
   dp = 0x400 #(1024)
   meshComplete = False
   
   #set vertex and uv data simultaneously
   file.seek(vertStart)
   vertCount = 0
   print("Vertices: " + file.tellHex())
   while meshComplete == False:
       #first, confirm that this is a vertex
       file.seek(vertexType - 1,1)
       checkedByte = file.readByte()
       file.seek(-vertexType,1)

       file.seek(16,1)
       byte40 = file.readShort()
       file.seek(20,1)
       altByte40 = file.readHalfFloat()
       file.seek(-40,1)
       
       if vertexType == 40 and byte40 != 65535 and altByte40 != 0.0:
           meshComplete = True
           continue
       elif vertexType != 40 and checkedByte != 60 and checkedByte != 188:
           meshComplete = True
           continue
       #read vertex
       v1,v2,v3 = file.read3Float()
       verts.append((v1,v2,v3))
       file.seek(8,1) #seek to uv data
       u1,u2 = file.read2short()
       u1 /= dp
       u2 /= dp
       uvs.append((u1,-u2))
       file.seek(vertexType - 24,1) #seek next vertex
       vertCount = vertCount + 1
   #end vertex & uv data
   print(file.tellHex() + " Count: " + str(vertCount))
   
   padding = True
   #loop to reach face data
   while padding == True:
       #print(file.tellHex())
       checkedByte = file.readByte()
       if checkedByte != 0:
           file.seek(-1,1)
           padding = False
           #while  file.tell() % 32 != 0:
               #file.seek(-1,1) #let's hope this doesn't corrupt good face data
   #end loop
   #now we need to confirm tht we're
   #starting at the right place.
   while file.tell() % 32 != 0:
       file.seek(-1,1)
   
   meshComplete = False
   
   print("Faces: " + file.tellHex())
   
   #face data
   #peek 31 (0x1f) bytes ahead.
   #if the block is not the end of a vertex,
   #step back 31 bytes and read 16 times.
   showData = True
   finalSubFaces = []
   subMeshStart40 = False
   simpleSubMesh = False
   while meshComplete == False:
       #if meshCounter == 78:
           #print("Squad")
       subMeshStart = False
       foundVertex = False
       file.seek(30,1)
       checkedByte = file.readHalfFloat()
       file.seek(-32,1)
       
       file.seek(34,1)
       altByte36 = file.readHalfFloat()
       file.seek(-36,1)

       file.seek(3,1)
       vertCheck1 = file.readByte()
       file.seek(3,1)
       vertCheck2 = file.readByte()
       file.seek(3,1)
       vertCheck3 = file.readByte()
       file.seek(2,1) #14 bytes from start
       checkedByte2 = file.readShort()
       byte40 = file.readShort()
       file.seek(20,1)
       altByte40 = file.readHalfFloat()
       file.seek(-40,1)

       file.seek(17,1)
       minorByte28 = file.readByte()
       file.seek(8,1) #26 bytes from start
       altByte28 = file.readHalfFloat()
       file.seek(-28,1)

       file.seek(1,1)
       faceConfirm1 = file.readByte()
       file.seek(1,1)
       faceConfirm2 = file.readByte()
       file.seek(1,1)
       faceConfirm3 = file.readByte()
       file.seek(-6,1)
       faceConfirmFinal = False
       
       subMeshStartFace = 0
       if faceConfirm1 == 0x3c:
           if faceConfirm1 == faceConfirm2 and faceConfirm2 == faceConfirm3:
               faceConfirmFinal = True
       
       if faceConfirmFinal == False and (file.tell() % 32 == 0) and vertCheck1 >= 0x00 and vertCheck1 <= 0xbf and vertCheck2 >= 0x3b and vertCheck2 <= 0xbf and vertCheck3 >= 0x3b and vertCheck3 <= 0xbf:
           if byte40 == 65535 and altByte40 == 0.0:
               foundVertex = True
               vertexType = 40
               #print("vertexType: " + str(vertexType))
           elif (altByte36 == 1.0 or altByte36 == -1.0) and (byte40 >= 65278 and byte40 <= 65535 or byte40 == 255):
               foundVertex = True
               vertexType = 36
               #print("vertexType: " + str(vertexType))
           elif (altByte28 == 1.0 or altByte28 == -1.0) and (minorByte28 >= 1 and minorByte28 <= 3):
               foundVertex = True
               vertexType = 28
               print("vertexType: " + str(vertexType))
           elif (checkedByte == 1.0 or checkedByte == -1.0) and (byte40 >= 255 and byte40 <= 65535 or byte40 == 12): #previously 65278 - 65535
               foundVertex = True
               vertexType = 32
               #print("vertexType: " + str(vertexType))
       elif checkedByte2 == 32768 and checkedByte == 0.0 or checkedByte2 == 32768 and checkedByte == 1.875:
           #end of compatible mesh data
           fileComplete = True
       elif subMeshStart40 == True:
           #this will be used to make
           #subMeshStart true.
           subMeshes.append(file.tell())
           subMeshStart40 = False
       elif simpleSubMesh == True:
           subMeshes.append(file.tell())
           simpleSubMesh = False

       for f in subMeshes:
           if file.tell() == f:
               subMeshStart = True
               subMeshStartFace = f
       if subMeshStart == True:
           subMeshes.remove(subMeshStartFace)
           
       if subMeshStart == False and foundVertex == False and fileComplete == False:
           for i in range(1):
               f1,f2,f3 = file.read3Short()
               if f1 == 0 and f2 == 0 and f3 == 0:
                   padding = True
                   padCount = 0
                   while padding == True:
                       #skip 0-bytes
                       checkedByte = file.readByte()
                       if checkedByte != 0:
                           file.seek(-1,1)
                           padding = False
                       elif file.tell() % 32 == 0:
                           #if the first vertex is 0, I don't need to do a full
                           #type32-vertex check. Instead, I can simply check
                           #the last half-float. That's enough info to continue the loop.
                           file.seek(30,1)
                           checkedByte = file.readHalfFloat()
                           file.seek(-32,1)
                           if (checkedByte == 1.0 or checkedByte == -1.0):
                               #print("possible vert at" + file.tellHex())
                               break
                       else:
                           padCount = padCount + 1
                           if padCount == 32 - 8:
                               simpleSubMesh = True
                           #print(file.tellHex())
                   if vertexType == 40: #we've found a lowpoly model. submeshes are separated by zeros.
                       subMeshStart40 = True
                   #if file.tell() % 32 == 0:
                       #simpleSubMesh = True
                   break
               elif f1 == 0 and f2 == 0 and file.tell() % 32 != 0:
                   file.seek(-2,1)
                   break
               faces.append((f1,f2,f3))
               #if showData == True and meshCounter == 42:
                   #print(str(f1) + ", " + str(f2) + ", " + str(f3))
                   #print(file.tellHex())
                   #print(i)            
       else:
           meshComplete = True
           vertStart = file.tell()
           if fileComplete == True:
               print("File Complete at Mesh" + str(meshCounter).zfill(2))
           elif subMeshStart == True:
               #we've encountered a submesh!
               meshComplete = False
               faceCount = int((len(faces)) / 3)
               for i in range(faceCount):
                   finalSubFaces.append(faces[i])
               faces = []
               print("Count: " + str(faceCount) + "- Submesh at "  + file.tellHex())
   #end face data
   
   #make sure to use only the first third of the faces array.
   #considering the values involved,
   #you divide by 18, not 3
   finalFaces = finalSubFaces[:]
   faceCount = int((len(faces)) / 3)
   for i in range(faceCount):
       finalFaces.append(faces[i])
   print(file.tellHex() + " Count: " + str(faceCount))
   #material
   material = mrp.create_material("Material" + str(meshCounter).zfill(2))
   material.set_color(random.randint(0, 256), random.randint(0, 256), random.randint(0, 256))
   material.set_texture("C:\\Users\\freez\\Pictures\\GR2\\kit01_face_00.bmp", "RGB", True)
   #end material
   
   mesh.set_vertices(verts,"ZYX","z","Float")
   mesh.set_faces(finalFaces, tp="Short")
   mesh.set_uvs(uvs)
   mesh.set_material(material)
   
   mrp.view_uvs("Mesh" + str(meshCounter).zfill(2))
   mrp.render("Mesh" + str(meshCounter).zfill(2))
   #mrp.print_mesh("Mesh" + str(meshCounter).zfill(2))
   print("Mesh" + str(meshCounter).zfill(2) + " complete")
   meshCounter = meshCounter + 1
   #failsafe for infinite loops
   if meshCounter == 90:
         fileComplete = True
mrp.render("All")
If you get the animation, please let me know. I plan to add to the program to support skeletal animation.
(07-02-2018, 05:45 AM)Lazov Wrote: [ -> ]If you get the animation, please let me know. I plan to add to the program to support skeletal animation.

Alright. I'll keep you posted on any developments.