huckleberrypie Posted June 22 Posted June 22 I know the guys over at the RBR community are at least planning to work on the game's model formats so they can be edited in Blender, but I'd like to know if it's possible to rip them for the time being as I've tried ripping the character models from it using Ninja Ripper but ended up not getting a T-pose. SGS.7z Cars.7z
Engineers shak-otay Posted June 27 Engineers Posted June 27 (edited) Low poly models usually don't raise that big interest but the mesh format shouldn't be a big obstacle, or should it? edit: didn't know whether triangle strips is the best choice here. Saved with normal triangles, drag&dropped it onto Noesis, F4 for backface culling, doesn't look much worse, imho. But after reviewing I'd suggest using strips. Edited June 27 by shak-otay 1
huckleberrypie Posted June 27 Author Posted June 27 12 minutes ago, shak-otay said: Low poly models usually don't raise that big interest but the mesh format shouldn't be a big obstacle, or should it? edit: didn't know whether triangle strips is the best choice here. Saved with normal triangles, drag&dropped it onto Noesis, F4 for backface culling, doesn't look much worse, imho. But after reviewing I'd suggest using strips. Same goes for characters (.SGS files), right? I know @Karpati already reversed the car model formats but not the character stuff iirc.
Engineers shak-otay Posted June 27 Engineers Posted June 27 25 minutes ago, huckleberrypie said: Same goes for characters (.SGS files), right? I know @Karpati already reversed the car model formats Dunno. If I had known the cars have already been reversed I'd checked the character SGS instead. 1
huckleberrypie Posted June 27 Author Posted June 27 2 minutes ago, shak-otay said: Dunno. If I had known the cars have already been reversed I'd checked the character SGS instead. Sorry about that. What I do know is that both share more or less the same structure but .SGS has skeletal model information. I could open some of the more simpler ones in Zmodeler 2 e.g. a can of Red Bull but not the human characters themselves.
Engineers shak-otay Posted June 27 Engineers Posted June 27 Char mesh format looks simple. For the skeleton you could try use Durik's skelfinder, read two posts here. 1
huckleberrypie Posted June 27 Author Posted June 27 25 minutes ago, shak-otay said: Char mesh format looks simple. For the skeleton you could try use Durik's skelfinder, read two posts here. Index and vertex buffer locations seem straightforward, but finding the stride and count is a little confusing for me.
Engineers shak-otay Posted June 27 Engineers Posted June 27 (edited) "stride" (or FVFsize in hex2obj) is a multiple of 4 for float based formats. Using vertex start address 0x3f94 (type in 3f94 without the 0x) for mechanic-1-4_01.sgs and trying 12 in a first step and pressing the go2 button you'll see "NORM" in each 2nd line in the lower left window. This means the FVFsize is 24 in this case. The vertexcount is calculated automatically (see lower left window) after pressing the go1 button. Provided you set the correct start address and FI count of the FI block. That's just a matter of experience. Or simply divide sizeOfVertex block by FVFsize. Works in most cases. Edited June 27 by shak-otay 1
Engineers h3x3r Posted June 27 Engineers Posted June 27 (edited) Struct of SGS/SGC is pretty much same... Here's some info... //------------------------------------------------ //--- 010 Editor v14.0 Binary Template // // File: // Authors: // Version: // Purpose: // Category: // File Mask: // ID Bytes: // History: //------------------------------------------------ LittleEndian();OutputPaneClear(); local uint32 i,j,k,l,TotalSize=FileSize(); string Sign; struct { do { struct { uint32 ResourceSign; enum <uint32> { Mesh = 0, Bone = 3, Material = 5, MaterialEffect = 15, Skeleton = 18, }ResourceType; uint32 Unknown_2; uint32 Unknown_3; uint32 ResourceSize; local uint32 ResourceInfoEndOffset=FTell(); byte ResourceData[ResourceSize]; local uint32 cPos=FTell(); }ResourceInfo; } while (ResourceInfo.ResourceSign == 12 & ResourceInfo.cPos != TotalSize); }ResourceTable; EDiT: Now you can dump it with this bms script. ################################### get BaseFileName basename get FileSize asize get Sign string do get ResourceSign uint32 get ResourceType uint32 get Unknown_2 uint32 get Unknown_3 uint32 get ResourceSize uint32 savepos ResourceOffset getdstring ResourceData ResourceSize savepos cPos if ResourceType == 0 set Extension string "mesh" elif ResourceType == 3 set Extension string "bone" elif ResourceType == 5 set Extension string "material" elif ResourceType == 15 set Extension string "materialEffect" elif ResourceType == 18 set Extension string "skeleton" else set Extension uint32 ResourceType endif string FileName p= "%s/%u.%s" BaseFileName ResourceOffset Extension log FileName ResourceOffset ResourceSize while ResourceSign == 12 & cPos != FileSize Edited June 27 by h3x3r 1
huckleberrypie Posted Saturday at 01:32 AM Author Posted Saturday at 01:32 AM (edited) 11 hours ago, h3x3r said: Struct of SGS/SGC is pretty much same... Here's some info... //------------------------------------------------ //--- 010 Editor v14.0 Binary Template // // File: // Authors: // Version: // Purpose: // Category: // File Mask: // ID Bytes: // History: //------------------------------------------------ LittleEndian();OutputPaneClear(); local uint32 i,j,k,l,TotalSize=FileSize(); string Sign; struct { do { struct { uint32 ResourceSign; enum <uint32> { Mesh = 0, Bone = 3, Material = 5, MaterialEffect = 15, Skeleton = 18, }ResourceType; uint32 Unknown_2; uint32 Unknown_3; uint32 ResourceSize; local uint32 ResourceInfoEndOffset=FTell(); byte ResourceData[ResourceSize]; local uint32 cPos=FTell(); }ResourceInfo; } while (ResourceInfo.ResourceSign == 12 & ResourceInfo.cPos != TotalSize); }ResourceTable; EDiT: Now you can dump it with this bms script. ################################### get BaseFileName basename get FileSize asize get Sign string do get ResourceSign uint32 get ResourceType uint32 get Unknown_2 uint32 get Unknown_3 uint32 get ResourceSize uint32 savepos ResourceOffset getdstring ResourceData ResourceSize savepos cPos if ResourceType == 0 set Extension string "mesh" elif ResourceType == 3 set Extension string "bone" elif ResourceType == 5 set Extension string "material" elif ResourceType == 15 set Extension string "materialEffect" elif ResourceType == 18 set Extension string "skeleton" else set Extension uint32 ResourceType endif string FileName p= "%s/%u.%s" BaseFileName ResourceOffset Extension log FileName ResourceOffset ResourceSize while ResourceSign == 12 & cPos != FileSize What about a Noesis script? I am able to figure out where the vertices are and more or less the count but the faces are a clincher to get. Edited Saturday at 02:31 AM by huckleberrypie
Engineers Solution shak-otay Posted Saturday at 04:58 AM Engineers Solution Posted Saturday at 04:58 AM Faces are simple for the mentioned mechanics: 1
huckleberrypie Posted Saturday at 06:43 AM Author Posted Saturday at 06:43 AM (edited) 2 hours ago, shak-otay said: Faces are simple for the mentioned mechanics: Got it now, thanks! EDIT: There's one problem tho: I don't get any UVs for some reason. Edited Saturday at 07:03 AM by huckleberrypie
Engineers shak-otay Posted Saturday at 08:57 AM Engineers Posted Saturday at 08:57 AM 0xc4b4, UVB size 8 1
huckleberrypie Posted Saturday at 09:34 AM Author Posted Saturday at 09:34 AM 37 minutes ago, shak-otay said: 0xc4b4, UVB size 8 Where do I enter that in the UV block?
Engineers shak-otay Posted Saturday at 10:19 AM Engineers Posted Saturday at 10:19 AM editboxes for start and size UVB (UV block) 1
Engineers h3x3r Posted Saturday at 02:27 PM Engineers Posted Saturday at 02:27 PM (edited) I have made a Noesis script but it's basic. Just simple mesh export. No materials/ no bones/ no skin. Anyway this is mesh struct. Just basic. //------------------------------------------------ //--- 010 Editor v14.0 Binary Template // // File: // Authors: // Version: // Purpose: // Category: // File Mask: // ID Bytes: // History: //------------------------------------------------ LittleEndian();OutputPaneClear(); local uint32 i,j,k,l,TotalSize=FileSize(); string MeshName; uint32 Unknown_0; uint32 Unknown_1; float Unknown_2[27]; float Unknown_3[5]; uint32 TotalVertexCount; uint32 StrideType; if (StrideType == 19) { byte VertexBuffer[TotalVertexCount*24]; byte ColorBuffer[TotalVertexCount*4]; } else if (StrideType == 23) { byte VertexBuffer[TotalVertexCount*24]; byte UVBuffer[TotalVertexCount*8]; byte ColorBuffer[TotalVertexCount*4]; } uint32 TotalIndexCount; byte IndexBuffer[TotalIndexCount*6]; uint32 ShapeIndex; struct { string MaterialName; uint32 IndexCount; // *3 uint32 Unknown_0; uint32 VertexCount; uint32 Unknown_1; }ShapeInfo[ShapeIndex]<optimize=false>; FSeek(startof(VertexBuffer)); if (StrideType == 19) { struct { float VPosX,VPosY,VPosZ,VNPosX,VNPosY,VNPosZ; }Vertices[TotalVertexCount]<optimize=false>; } else if (StrideType == 23) { struct { float VPosX,VPosY,VPosZ,VNPosX,VNPosY,VNPosZ; }Vertices[TotalVertexCount]<optimize=false>; struct { float UVPosX,UVPosY; }UnitVector[TotalVertexCount]<optimize=false>; } FSeek(startof(IndexBuffer)); for (i=0; i < ShapeIndex; i++) { struct { uint16 F1,F2,F3; }Indices[ShapeInfo[i].IndexCount]<optimize=false>; } Edited Saturday at 02:28 PM by h3x3r 2
huckleberrypie Posted Saturday at 03:37 PM Author Posted Saturday at 03:37 PM 1 hour ago, h3x3r said: I have made a Noesis script but it's basic. Just simple mesh export. No materials/ no bones/ no skin. Anyway this is mesh struct. Just basic. //------------------------------------------------ //--- 010 Editor v14.0 Binary Template // // File: // Authors: // Version: // Purpose: // Category: // File Mask: // ID Bytes: // History: //------------------------------------------------ LittleEndian();OutputPaneClear(); local uint32 i,j,k,l,TotalSize=FileSize(); string MeshName; uint32 Unknown_0; uint32 Unknown_1; float Unknown_2[27]; float Unknown_3[5]; uint32 TotalVertexCount; uint32 StrideType; if (StrideType == 19) { byte VertexBuffer[TotalVertexCount*24]; byte ColorBuffer[TotalVertexCount*4]; } else if (StrideType == 23) { byte VertexBuffer[TotalVertexCount*24]; byte UVBuffer[TotalVertexCount*8]; byte ColorBuffer[TotalVertexCount*4]; } uint32 TotalIndexCount; byte IndexBuffer[TotalIndexCount*6]; uint32 ShapeIndex; struct { string MaterialName; uint32 IndexCount; // *3 uint32 Unknown_0; uint32 VertexCount; uint32 Unknown_1; }ShapeInfo[ShapeIndex]<optimize=false>; FSeek(startof(VertexBuffer)); if (StrideType == 19) { struct { float VPosX,VPosY,VPosZ,VNPosX,VNPosY,VNPosZ; }Vertices[TotalVertexCount]<optimize=false>; } else if (StrideType == 23) { struct { float VPosX,VPosY,VPosZ,VNPosX,VNPosY,VNPosZ; }Vertices[TotalVertexCount]<optimize=false>; struct { float UVPosX,UVPosY; }UnitVector[TotalVertexCount]<optimize=false>; } FSeek(startof(IndexBuffer)); for (i=0; i < ShapeIndex; i++) { struct { uint16 F1,F2,F3; }Indices[ShapeInfo[i].IndexCount]<optimize=false>; } Would you mind sharing the script? Or are you still in the process of improving it?
Engineers h3x3r Posted Saturday at 04:07 PM Engineers Posted Saturday at 04:07 PM Nah no improvements so far and don't think there will be any... from inc_noesis import * import noesis import rapi import os def registerNoesisTypes(): handle = noesis.register("Richard Burns Rally - Geometry", ".mesh") noesis.setHandlerTypeCheck(handle, noepyCheckType) noesis.setHandlerLoadModel(handle, noepyLoadModel) noesis.logPopup() return 1 def noepyCheckType(data): bs = NoeBitStream(data) if len(data) < 20: return 0 return 1 def noepyLoadModel(data, mdlList): bs = NoeBitStream(data) baseName = rapi.getExtensionlessName(rapi.getLocalFileName(rapi.getInputName())) ctx = rapi.rpgCreateContext() Underline = "_" MeshName = bs.readString() Unknown_0 = bs.readUInt() Unknown_1 = bs.readUInt() bs.read(128) TotalVertexCount = bs.readUInt() StrideType = bs.readUInt() if StrideType == 19: VertexBuffer = bs.read(TotalVertexCount * 24) ColorBuffer = bs.read(TotalVertexCount * 4) elif StrideType == 23: VertexBuffer = bs.read(TotalVertexCount * 24) UnitVectorBuffer = bs.read(TotalVertexCount * 8) ColorBuffer = bs.read(TotalVertexCount * 4) TotalIndexCount = bs.readUInt() IndexBufferBaseOffset = bs.tell() bs.read(TotalIndexCount * 6) if StrideType == 19: rapi.rpgBindPositionBufferOfs(VertexBuffer, noesis.RPGEODATA_FLOAT, 24, 0) rapi.rpgBindNormalBufferOfs(VertexBuffer, noesis.RPGEODATA_FLOAT, 24, 12) elif StrideType == 23: rapi.rpgBindPositionBufferOfs(VertexBuffer, noesis.RPGEODATA_FLOAT, 24, 0) rapi.rpgBindNormalBufferOfs(VertexBuffer, noesis.RPGEODATA_FLOAT, 24, 12) rapi.rpgBindUV1BufferOfs(UnitVectorBuffer, noesis.RPGEODATA_FLOAT, 8, 0) ShapeIndex = bs.readUInt() IndexCountList = [] MaterialNameList = [] for i in range(0, ShapeIndex): MaterialNameList.append(bs.readString()) IndexCountList.append(bs.readUInt()*3) Unknown_0 = bs.readUInt() VertexCount = bs.readUInt() Unknown_1 = bs.readUInt() bs.seek(IndexBufferBaseOffset, NOESEEK_ABS) for i in range(0, ShapeIndex): IndexCount = IndexCountList[i] MaterialName = MaterialNameList[i] IndexBuffer = bs.read(IndexCount * 2) ShapeIdDigfmt = "{:04d}".format(i) rapi.rpgSetName(MeshName + Underline + ShapeIdDigfmt) #rapi.rpgSetMaterial(MaterialName) rapi.rpgCommitTriangles(IndexBuffer, noesis.RPGEODATA_USHORT, IndexCount, noesis.RPGEO_TRIANGLE) mdl = rapi.rpgConstructModel() mdlList.append(mdl) return 1 You can try on your own 😉 1
huckleberrypie Posted Saturday at 10:24 PM Author Posted Saturday at 10:24 PM 13 hours ago, shak-otay said: 0xc4b4, UVB size 8 This is for Richard, right? I tried the following values as shown in the screenshot and this is what I got:
Engineers shak-otay Posted Sunday at 04:26 AM Engineers Posted Sunday at 04:26 AM 6 hours ago, huckleberrypie said: This is for Richard, right? Who is Richard? I referred to mechanic-1-4_01.sgs.
huckleberrypie Posted Sunday at 05:51 AM Author Posted Sunday at 05:51 AM 1 hour ago, shak-otay said: Who is Richard? I referred to mechanic-1-4_01.sgs. I see.
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now