June 22, 20251 yr Localization 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
June 27, 20251 yr Supporter 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, 20251 yr by shak-otay
June 27, 20251 yr Author Localization 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.
June 27, 20251 yr Supporter 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.
June 27, 20251 yr Author Localization 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.
June 27, 20251 yr Supporter Char mesh format looks simple. For the skeleton you could try use Durik's skelfinder, read two posts here.
June 27, 20251 yr Author Localization 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.
June 27, 20251 yr Supporter "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, 20251 yr by shak-otay
June 27, 20251 yr Supporter 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, 20251 yr by h3x3r
June 28, 20251 yr Author Localization 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 June 28, 20251 yr by huckleberrypie
June 28, 20251 yr Author Localization 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 June 28, 20251 yr by huckleberrypie
June 28, 20251 yr Author Localization 37 minutes ago, shak-otay said: 0xc4b4, UVB size 8 Where do I enter that in the UV block?
June 28, 20251 yr Supporter 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 June 28, 20251 yr by h3x3r
June 28, 20251 yr Author Localization 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?
June 28, 20251 yr Supporter 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 😉
June 28, 20251 yr Author Localization 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:
June 29, 20251 yr Supporter 6 hours ago, huckleberrypie said: This is for Richard, right? Who is Richard? I referred to mechanic-1-4_01.sgs.
June 29, 20251 yr Author Localization 1 hour ago, shak-otay said: Who is Richard? I referred to mechanic-1-4_01.sgs. I see.
Create an account or sign in to comment