1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

Decoding the Saints Row 3 mesh format.

Discussion in 'Guides and Tutorials' started by scanti, Jun 16, 2012.

  1. flow754

    flow754 Modding patch tester

    Is the script available to download somewhere? I'd be interested in porting it to Blender/Python.
  2. Sure, but they are still in development so things are going to change over time;
    SRIII formatdescription and maxscripts

    There is already quite some blender stuff available I think;

    Ps, here's a new screenshot of the progress on shaundi. Corrected normalmaps and a nice high-res head model. Doesn't she look good?

    Next step is proper material parsing. I deleted the old stuff and need to re-write it properly. And I need to figure out how the materials are being constructed.
    Last edited: Mar 6, 2017

  3. Give this man two bottles of rum, gentlemen!
    Awesome work.
    Admixon likes this.
  4. Fixed a small issue in the importer, so now we have Oleg!
    Download new version here:

    I still haven't figured out where the proper scales are referenced. They should be in the files somewhere. It seems very unlikely that they are hardcoded.
    Also still have to write a proper material parser. These textures were all manually applied. The old material stuff I had was shit.

    tyhender, Quantum and flow754 like this.
  5. Here's what I figured out about the material format in SR4 so far by playing with the material cruncher:

    matlib_pc format:

    Code (Text):

    char[4] signature
    uint64 strings_size
    uint64 strings_count
    align 16
    char[strings_size] strings1 // zero terminated strings
    align 16
    uint8[56] unknown1
    uint64 materials_count
    uint8[32] unknown2
    char[strings_count][] strings2 // No size, just keep reading strings until you have strings_count of them
    Material for ir_at_bbsimple1. ir_at_bbsimple3 is similar, except it does not have unknown6 to unknown12.

    Code (Text):

    uint64 size // size of the material entry
    uint8[8] unknown1
    uint32 flags
    uint8[4] unknown2
    uint8[36] unknown3
    uint8[4] unknown4
    uint8[4] unknown5
    uint32 unknown6
    uint8[4] unknown7
    uint32 unknown8
    uint32 unknown9
    uint8[4] unknown10
    uint32 unknown11
    uint8[28] unknown12
    uint8[12] unknown13
    fxparam[] params
    uint8[32] unknown32
    fxparam is always 16 bytes and can be a single float or vector of 4. The amount and type is defined in each shaders .fxinfo_pc file. They are inside the shaders.vpp_pc file for the SRIV SDK.


    Code (Text):

    Mat_Alpha_Mode 0x2
    Mat_Glows 0x4
    Mat_Distortion 0x8
    Mat_Cull_Mode 0x10
    Mat_Shadow_Cull_Mode 0x200
    norender 0x1000
    I used uint8 as the generic bytes type. The difference between uint8[4] and uint32 is that uint8[4] usually has values higher than 1 million, which is very uncommon for actual integers, I suspect they're hashes. Everything I wrote is mostly guessing, don't be confused if it doesn't match up with your files.

    Here's a gist with my Python (3) code: https://gist.github.com/Yepoleb/ce56be1f52322ae69887c2ed0736983f
    Quantum and harmalarm[NL] like this.
  6. Thanks man! To be honest I've been spending some time investigating the rig_pc files for characters and have now got a proper rig parser. Next Item on the agenda is to figure out the vertex weights to rig the character to the bones. I think I already found out how to do that.
    After this I will work on the materials and have a proper look at your findings ;)
    tyhender and Quantum like this.
  7. Okay, after some fiddling I figured out the structure at least. There are still a lot of unknowns though
    Code (Text):

    int Align(int length){
        local int val = FTell();
        while (val > length) {
            val = val-length;
        val = length-val;
        return val;

    struct TEXTURENAME {
        char Name[];

    struct TEXTURENAME2 {
        char Name[];
        byte zero1;
        byte spacing[Align(2)];

    struct SUBMAT {
        int bitmapnamestart;  
        byte crc[4];  
        int matindex;

    struct MATERIAL {  
        int64 matsize;
        byte unknown1[8];
        int flags;
        byte bitmap_count;
        byte unknown2;
        byte chunk_count;
        byte unknown3;
        byte unknown4[32];//0
        SUBMAT submats[bitmap_count];
        int unknown6[chunk_count];
        byte spacing1[Align(16)];
        float transforms[unknown3*4];

    int CRC;
    int textures_size;
    int null1;
    int textures_count;
    int null2;
    byte spacing1[Align(16)];
    TEXTURENAME TextureNames[textures_count] <optimize=false> ;
    byte spacing2[Align(16)];
    int unknown1[6];
    int materials_count;
    int unknown2;
    int materialslength; //the part between both texturename entries
    int unknown3[5];
    int entrycount;
    int unknown4;
    int matstartpositions[entrycount];
    byte spacing3[Align(16)];
    int64 matlenghtorsomething[entrycount];
    byte spacing4[Align(16)];
    MATERIAL Materials[materials_count] <optimize=false>;
    TEXTURENAME2 TextureNames2[textures_count] <optimize=false> ;
    byte spacing5[Align(16)];
    This is a part of a script I made for 010 Editor. I find it to be a pretty useful application for file format checking because it is very easy to make scripts that can parse the files and you can quickly see your errors.
    Anyway, still working on this at a slow pace. Hopefully the material parser will prove to be useful.

    EDIT: smal update with proper parsing right now. Still a lot of unknowns though ;)
    Last edited: Jun 29, 2017
    Lukong1515 and flow754 like this.
  8. I have done some work on this again. I figured out the ccmesh_pc file has identical information as the matlib_pc file, but it refers to the low-res materials that are default for the characters. All at the end of the file. I've managed to create a proper material parser, and I managed to use scanti's SR3Unpacktextures tool in combination with the maxscript to automatically unpack the textures. So now we have automatic material creation! :) Many models now successfully import, apart from a little few. So there is still a little tweaking that needs to be done. Other than that, things are starting to get somewhere! :)


    [​IMG] [​IMG]
  9. flow754

    flow754 Modding patch tester

    Unfortunately you can only like a post once, so I needed to comment to show that extra bit of appreciation :)
    harmalarm[NL] likes this.
  10. We are in luck! For the heads I have investigated so far, one of the vertices for the eyes is always the same index. That means I was able to determine where the morph should end up and from there I could calculate the scale values needed for the morph file to start working! So now we have automatic high head model import! yeay! I still wonder where the scales can be found without my dirty trick, because this won't work on morph files that are used for other items such as clothing and accessories I'm afraid...
    The screen below shows the LOD head and the HIGH head on top of each other. They fit perfectly :)


    From now on I will focus on cleaning up the script and making it more robust. Also I would like to be able to import ALL models without issues, so that will be the focus for the coming time. After that I will try to get that white hair to have the right color. Hopefully I don't have to go all the way into the shaders for that... I'm hoping there is a diffuse color in the matlib_pc file somewhere. After that I will focus on getting the rig files to work. I can already import them, but I am running into an issue where max crashes upon skinning the rig with the model. But all in good time... ;)
    Last edited: Aug 30, 2017
    Quantum and flow754 like this.