Users browsing this thread: 3 Guest(s)
Gravity Rush 2
#1
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")
Reply
Thanked by: josh98, Resiliaxia
#2
If you get the animation, please let me know. I plan to add to the program to support skeletal animation.
Reply
Thanked by:
#3
(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.
Reply
Thanked by:


Forum Jump: