Crimson Skies High Road to Revenge .x models
-
- Posts: 29
- Joined: Sat Dec 01, 2018 1:43 pm
Crimson Skies High Road to Revenge .x models
Hi there! I'm attempting to read and convert Crimson Skies' plane models (.x) into a format I can work with (.dae, .obj, .fbx, etc.) This does not appear to be the DirectX .x format, but more than likely something else. I need a way for it to export at least individual sub meshes or have them all in a hierarchy grouped instead of one single mesh with UV maps. Any help with this would be greatly appreciated!
This here is the Cinematic HR Devastator model.
https://www.dropbox.com/s/36ozeub6dlqow ... tor.x?dl=0
And here are textures to use as a reference for getting UV maps working.
https://www.dropbox.com/s/8undw9x8amhft ... r.png?dl=0 Main Texture
https://www.dropbox.com/s/2qf19vm4fizlc ... r.png?dl=0 Propellers texture
Also attached here is a simple Noesis plugin made by another person for reading and exporting .x files, although it does not preview textures, nor export with UV maps, submeshes or textures.
Thanks again for any help!
This here is the Cinematic HR Devastator model.
https://www.dropbox.com/s/36ozeub6dlqow ... tor.x?dl=0
And here are textures to use as a reference for getting UV maps working.
https://www.dropbox.com/s/8undw9x8amhft ... r.png?dl=0 Main Texture
https://www.dropbox.com/s/2qf19vm4fizlc ... r.png?dl=0 Propellers texture
Also attached here is a simple Noesis plugin made by another person for reading and exporting .x files, although it does not preview textures, nor export with UV maps, submeshes or textures.
Thanks again for any help!
-
- Posts: 29
- Joined: Sat Dec 01, 2018 1:43 pm
Re: Crimson Skies High Road to Revenge .x models
Gathered some info on the models.
It appears the game was primarily modelled with Autodesk Maya 2003. I don't have it on my computer right now, but it may be possible to open up the .x models in Maya? I don't think year version differences would matter.
It appears the game was primarily modelled with Autodesk Maya 2003. I don't have it on my computer right now, but it may be possible to open up the .x models in Maya? I don't think year version differences would matter.
-
- Posts: 29
- Joined: Sat Dec 01, 2018 1:43 pm
Re: Crimson Skies High Road to Revenge .x models
Bump. Still looking for help.
-
- Posts: 29
- Joined: Sat Dec 01, 2018 1:43 pm
Re: Crimson Skies High Road to Revenge .x models
And yet another bump.
-
- Posts: 124
- Joined: Sat Aug 29, 2015 1:13 pm
Re: Crimson Skies High Road to Revenge .x models
links to images are 404.
Code: Select all
#Noesis Python model import+export test module, imports/exports some data from/to a made-up format
import math
from inc_noesis import *
#registerNoesisTypes is called by Noesis to allow the script to register formats.
#Do not implement this function in script files unless you want them to be dedicated format modules!
def registerNoesisTypes():
handle = noesis.register("Crimson Skies (Xbox)", ".x")
noesis.setHandlerTypeCheck(handle, noepyCheckType)
noesis.setHandlerLoadModel(handle, noepyLoadModel) #see also noepyLoadModelRPG
noesis.logPopup()
return 1
#check if it's this type based on the data
def noepyCheckType(data):
if len(data) < 8:
return 0
return 1
#load the model
def noepyLoadModel(data, mdlList):
bs = NoeBitStream(data)
fileDir=rapi.getDirForFilePath(rapi.getInputName());
texDir= os.path.join(fileDir, '../TEXTURE/')
ctx = rapi.rpgCreateContext()
rapi.rpgSetOption(noesis.RPGOPT_SWAPHANDEDNESS, 1)
bs.seek(32, NOESEEK_ABS)
nameLength=bs.readInt()
MeshName = (bs.readBytes(nameLength).decode("ASCII").rstrip("\0"))
print("MeshName ", MeshName)
matrix = NoeMat43( (
NoeVec3( (bs.readFloat(), bs.readFloat(), bs.readFloat()) ),
NoeVec3( (bs.readFloat(), bs.readFloat(), bs.readFloat()) ),
NoeVec3( (bs.readFloat(), bs.readFloat(), bs.readFloat()) ),
NoeVec3( (bs.readFloat(), bs.readFloat(), bs.readFloat()) )
)
)
rapi.rpgSetTransform(matrix)
bs.seek(24, NOESEEK_REL)#unk
bs.seek(4, NOESEEK_REL) # 3 ??
meshes = []
numMeshesInObj = bs.readInt()
#for i in range(0, numMeshesInObj):
# loadMesh(bs, rapi)
#print(numMeshesInObj, "numMeshes")
numChildsInObj= bs.readInt()
#print(numChildsInObj, "numChildsInObj")
for i in range(0, numChildsInObj):
loadObj(bs, rapi)
mdl = rapi.rpgConstructModel()
# print(texList)
# print(matList)
#mdl.setModelMaterials(NoeModelMaterials(texList, matList))
mdlList.append(mdl)
rapi.rpgClearBufferBinds()
return 1
def loadObj(bs, rapi):
nameLength=bs.readInt()
MeshName = (bs.readBytes(nameLength).decode("ASCII").rstrip("\0"))
#print("MeshName ", MeshName)
matrix = NoeMat43( (
NoeVec3( (bs.readFloat(), bs.readFloat(), bs.readFloat()) ),
NoeVec3( (bs.readFloat(), bs.readFloat(), bs.readFloat()) ),
NoeVec3( (bs.readFloat(), bs.readFloat(), bs.readFloat()) ),
NoeVec3( (bs.readFloat(), bs.readFloat(), bs.readFloat()) )
)
)
rapi.rpgSetTransform(matrix)
#print (matrix)
bs.seek(24, NOESEEK_REL)#unk
bs.seek(4, NOESEEK_REL) # 3 ??
meshes = []
numMeshesInObj = bs.readInt()
#print(numMeshesInObj, "numMeshes")
for i in range(0, numMeshesInObj):
loadMesh(bs, rapi,i,MeshName)
extraSomeBlocks= bs.readShort()
#print (extraSomeBlocks,"extraSomeBlocks")
bs.seek(extraSomeBlocks * 2, NOESEEK_REL)
whoKnows= bs.readByte()
#print (whoKnows,"who")
if whoKnows == 1:
size=16
numberOfUnk= bs.readInt()
else:
size=28
numberOfUnk= bs.readShort()
#print (numberOfUnk *size)
bs.seek( numberOfUnk *size, NOESEEK_REL)
numChildsInObj= bs.readInt()
print("Obj :" ,MeshName,"numMeshes",numMeshesInObj, "numChildsInObj",numChildsInObj)
#print(bs.tell() ," POS PRE CHILD")
#print(numChildsInObj, "numChildsInObj")
for i in range(0, numChildsInObj):
loadObj(bs, rapi)
return 1
def loadMesh(bs, rapi,matID,name):
bs.seek(15, NOESEEK_REL)#unk
typeText= bs.readByte()
#exceptions
if typeText == 17:
typeText=3
elif typeText == 19:
typeText=7
elif typeText == 23:
typeText=15
#print(typeText, "numofText1")
numberOfText=math.log(typeText+1,2)
#print(numberOfText, "numofText2")
for i in range(0, int(numberOfText)):
nameLength=bs.readInt()
MaterialName = (bs.readBytes(nameLength).decode("ASCII").rstrip("\0"))
#print(MaterialName, "MaterialName")
numBlocks= bs.readShort()
print(numBlocks, "numBlocks")
tell=bs.tell()
uvbuffer=bytes()
for m in range(numBlocks*16):
sh=bs.readShort()/32768.0
uvbuffer+=struct.pack("f",sh)
bs.seek(tell)
VertBuff = bs.readBytes(numBlocks * 32)
bs.seek(16, NOESEEK_REL)#uuid¿?
extraInfo= bs.readByte()
#print(bs.tell() ,"pos")
if extraInfo>0:
bs.seek(bs.readShort() * 12 * 4, NOESEEK_REL)
#print(bs.tell() ,"pos")
numTris= bs.readShort()
#print(numTris, "numTris")
#print(bs.tell() ,"pos")
TrisBuff = bs.readBytes(numTris * 2)
rapi.rpgSetMaterial(name+str(matID))
rapi.rpgBindPositionBufferOfs(VertBuff, noesis.RPGEODATA_FLOAT, 32, 0)
rapi.rpgBindUV1BufferOfs(uvbuffer, noesis.RPGEODATA_FLOAT,64,32)
rapi.rpgCommitTriangles(TrisBuff, noesis.RPGEODATA_USHORT, numTris, noesis.RPGEO_TRIANGLE, 1)
bs.seek(2, NOESEEK_REL) #FF
#print(bs.tell() ,"pos")
return 1
-
- Posts: 3
- Joined: Mon Jan 28, 2019 2:10 pm
Re: Crimson Skies High Road to Revenge .x models
Yup, 404 for me as well, so it isn't a temporary issue. It's a shame since I'm on the hunt for good plane models, and the Crimson Skies games were among my favorites.
-
- Posts: 29
- Joined: Sat Dec 01, 2018 1:43 pm
Re: Crimson Skies High Road to Revenge .x models
Same here. Afraid I still don't have a real solution to extracting the models w/ uvs and hierachy submeshes though, but that noesis .x plugin update works really well!
-
- Posts: 29
- Joined: Sat Dec 01, 2018 1:43 pm
Re: Crimson Skies High Road to Revenge .x models
Szkaradek123 wrote:links to images are 404.Code: Select all
#Noesis Python model import+export test module, imports/exports some data from/to a made-up format
import math
from inc_noesis import *
#registerNoesisTypes is called by Noesis to allow the script to register formats.
#Do not implement this function in script files unless you want them to be dedicated format modules!
def registerNoesisTypes():
handle = noesis.register("Crimson Skies (Xbox)", ".x")
noesis.setHandlerTypeCheck(handle, noepyCheckType)
noesis.setHandlerLoadModel(handle, noepyLoadModel) #see also noepyLoadModelRPG
noesis.logPopup()
return 1
#check if it's this type based on the data
def noepyCheckType(data):
if len(data) < 8:
return 0
return 1
#load the model
def noepyLoadModel(data, mdlList):
bs = NoeBitStream(data)
fileDir=rapi.getDirForFilePath(rapi.getInputName());
texDir= os.path.join(fileDir, '../TEXTURE/')
ctx = rapi.rpgCreateContext()
rapi.rpgSetOption(noesis.RPGOPT_SWAPHANDEDNESS, 1)
bs.seek(32, NOESEEK_ABS)
nameLength=bs.readInt()
MeshName = (bs.readBytes(nameLength).decode("ASCII").rstrip("\0"))
print("MeshName ", MeshName)
matrix = NoeMat43( (
NoeVec3( (bs.readFloat(), bs.readFloat(), bs.readFloat()) ),
NoeVec3( (bs.readFloat(), bs.readFloat(), bs.readFloat()) ),
NoeVec3( (bs.readFloat(), bs.readFloat(), bs.readFloat()) ),
NoeVec3( (bs.readFloat(), bs.readFloat(), bs.readFloat()) )
)
)
rapi.rpgSetTransform(matrix)
bs.seek(24, NOESEEK_REL)#unk
bs.seek(4, NOESEEK_REL) # 3 ??
meshes = []
numMeshesInObj = bs.readInt()
#for i in range(0, numMeshesInObj):
# loadMesh(bs, rapi)
#print(numMeshesInObj, "numMeshes")
numChildsInObj= bs.readInt()
#print(numChildsInObj, "numChildsInObj")
for i in range(0, numChildsInObj):
loadObj(bs, rapi)
mdl = rapi.rpgConstructModel()
# print(texList)
# print(matList)
#mdl.setModelMaterials(NoeModelMaterials(texList, matList))
mdlList.append(mdl)
rapi.rpgClearBufferBinds()
return 1
def loadObj(bs, rapi):
nameLength=bs.readInt()
MeshName = (bs.readBytes(nameLength).decode("ASCII").rstrip("\0"))
#print("MeshName ", MeshName)
matrix = NoeMat43( (
NoeVec3( (bs.readFloat(), bs.readFloat(), bs.readFloat()) ),
NoeVec3( (bs.readFloat(), bs.readFloat(), bs.readFloat()) ),
NoeVec3( (bs.readFloat(), bs.readFloat(), bs.readFloat()) ),
NoeVec3( (bs.readFloat(), bs.readFloat(), bs.readFloat()) )
)
)
rapi.rpgSetTransform(matrix)
#print (matrix)
bs.seek(24, NOESEEK_REL)#unk
bs.seek(4, NOESEEK_REL) # 3 ??
meshes = []
numMeshesInObj = bs.readInt()
#print(numMeshesInObj, "numMeshes")
for i in range(0, numMeshesInObj):
loadMesh(bs, rapi,i,MeshName)
extraSomeBlocks= bs.readShort()
#print (extraSomeBlocks,"extraSomeBlocks")
bs.seek(extraSomeBlocks * 2, NOESEEK_REL)
whoKnows= bs.readByte()
#print (whoKnows,"who")
if whoKnows == 1:
size=16
numberOfUnk= bs.readInt()
else:
size=28
numberOfUnk= bs.readShort()
#print (numberOfUnk *size)
bs.seek( numberOfUnk *size, NOESEEK_REL)
numChildsInObj= bs.readInt()
print("Obj :" ,MeshName,"numMeshes",numMeshesInObj, "numChildsInObj",numChildsInObj)
#print(bs.tell() ," POS PRE CHILD")
#print(numChildsInObj, "numChildsInObj")
for i in range(0, numChildsInObj):
loadObj(bs, rapi)
return 1
def loadMesh(bs, rapi,matID,name):
bs.seek(15, NOESEEK_REL)#unk
typeText= bs.readByte()
#exceptions
if typeText == 17:
typeText=3
elif typeText == 19:
typeText=7
elif typeText == 23:
typeText=15
#print(typeText, "numofText1")
numberOfText=math.log(typeText+1,2)
#print(numberOfText, "numofText2")
for i in range(0, int(numberOfText)):
nameLength=bs.readInt()
MaterialName = (bs.readBytes(nameLength).decode("ASCII").rstrip("\0"))
#print(MaterialName, "MaterialName")
numBlocks= bs.readShort()
print(numBlocks, "numBlocks")
tell=bs.tell()
uvbuffer=bytes()
for m in range(numBlocks*16):
sh=bs.readShort()/32768.0
uvbuffer+=struct.pack("f",sh)
bs.seek(tell)
VertBuff = bs.readBytes(numBlocks * 32)
bs.seek(16, NOESEEK_REL)#uuid¿?
extraInfo= bs.readByte()
#print(bs.tell() ,"pos")
if extraInfo>0:
bs.seek(bs.readShort() * 12 * 4, NOESEEK_REL)
#print(bs.tell() ,"pos")
numTris= bs.readShort()
#print(numTris, "numTris")
#print(bs.tell() ,"pos")
TrisBuff = bs.readBytes(numTris * 2)
rapi.rpgSetMaterial(name+str(matID))
rapi.rpgBindPositionBufferOfs(VertBuff, noesis.RPGEODATA_FLOAT, 32, 0)
rapi.rpgBindUV1BufferOfs(uvbuffer, noesis.RPGEODATA_FLOAT,64,32)
rapi.rpgCommitTriangles(TrisBuff, noesis.RPGEODATA_USHORT, numTris, noesis.RPGEO_TRIANGLE, 1)
bs.seek(2, NOESEEK_REL) #FF
#print(bs.tell() ,"pos")
return 1
Any way you can improve the plugin? The UVs don't appear to scale or position correctly with their associated textures, which is a massive pain in the ass to work with.
I noticed the textures are now 404'd.
Here's a new link:
https://drive.google.com/open?id=1Xe9ay ... 1WXyEwDCRB
While I wish I could do this myself and not have to rely on others, I don't have the necessary knowledge or skill to actually pull it off myself.
If it's possible to have the noesis plugin actually load and export the textures with the model when selected as well, that would be absolutely amazing.
Note the original textures are in a normally *SPAM* up .tga format, which can only be exported with another noesis plugin someone else made here:
https://drive.google.com/open?id=1r5l_M ... WWivCM_vTK
-
- Posts: 5
- Joined: Tue May 30, 2017 1:44 pm
Re: Crimson Skies High Road to Revenge .x models
The problem with UVs on Crimson skies models it that it has some edge cases that don´t work on some models (the worst model it´s the cinematic devastator).
If you process the uvs as this (c# code not python)
You get mostly ok uvs for the modelx except for the cinematic devastator (right plane) and iirc some helis
I wrote that python script but i don´t have enough confidence on my knowledge of python to try to fix it
If you process the uvs as this (c# code not python)
Code: Select all
var uaux = (reader.ReadInt16()); //Signed short
if (uaux > 16384f || uaux < -16384f)
u = ((float)(uaux & 16383) / 16384f);
else
u = ((float)(uaux) / 16384f);
You get mostly ok uvs for the modelx except for the cinematic devastator (right plane) and iirc some helis
I wrote that python script but i don´t have enough confidence on my knowledge of python to try to fix it
-
- Posts: 29
- Joined: Sat Dec 01, 2018 1:43 pm
Re: Crimson Skies High Road to Revenge .x models
How would I process the UVs that way?
-
- Posts: 29
- Joined: Sat Dec 01, 2018 1:43 pm
Re: Crimson Skies High Road to Revenge .x models
Got some new problems.
Unfortunately, seems like not all .x files can be processed through the Noesis plugin - a lot fail.
Here's an example.
Also, I noticed when running the actual models through NinjaRipper instead of using the Noesis plugin... a lot of them (including the player's plane) have multiple UV sets.
Is it possible to support this?
Unfortunately, seems like not all .x files can be processed through the Noesis plugin - a lot fail.
Here's an example.
Also, I noticed when running the actual models through NinjaRipper instead of using the Noesis plugin... a lot of them (including the player's plane) have multiple UV sets.
Is it possible to support this?
-
- Posts: 29
- Joined: Sat Dec 01, 2018 1:43 pm
Re: Crimson Skies High Road to Revenge .x models
Massive update!
I now got access to the .pdb files of CS, dated 2 months prior to release. This should make it far more easy to reverse engineer the model formats, so I hope that some work here will be done.
Whoever manages to get the plugins improved through this; I'll love you forever.
I now got access to the .pdb files of CS, dated 2 months prior to release. This should make it far more easy to reverse engineer the model formats, so I hope that some work here will be done.
Whoever manages to get the plugins improved through this; I'll love you forever.