Important information: this site is currently scheduled to go offline indefinitely by end of the year.

Gran Turismo 6 Models

Post questions about game models here, or help out others!
EcheloCross
veteran
Posts: 88
Joined: Sat Feb 27, 2010 6:57 pm
Has thanked: 40 times
Been thanked: 77 times

Re: Gran Turismo 6 Models

Post by EcheloCross »

Here is my code so far for handling the MDL3 files. If you read through it you can either copy it to a c# program of your own, or re-write it in the language of your choice.

This code handles both the 2nd highest lod, and the vertices only of the highest lod. The faces for the highest lod are edge compressed, I need to spend some more time with edge to get them figured out.

Code: Select all

//Extract MDL3 Standard and (HIGHLOD vertices only)
public void extractMDL3_HIGHLOD(ref FileStream fs, ref FileInfo fi)
{
    //string extractedPath = fi.DirectoryName + "\\extracted_mdl3";
    //Directory.CreateDirectory(extractedPath);

    fs.Read(infoBuffer4, 0, 4); //magic
    fs.Read(infoBuffer4, 0, 4); //MDL3 Total Size
    mdl3Size = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0);

    //Get meshInfoTable and sTable count
    fs.Seek(0x14, SeekOrigin.Begin);
    fs.Read(infoBuffer2, 0, 2);
    uint sTableCount = BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0);

    //Enumerate Mesh Info Table
    List<List<uint>> meshInfoTable = new List<List<uint>>();
    fs.Seek(0x38, SeekOrigin.Begin);
    fs.Read(infoBuffer4, 0, 4);
    uint meshInfoTableAddress = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0);
    fs.Seek(meshInfoTableAddress, SeekOrigin.Begin);
    for (int i = 0; i < sTableCount; i++)
    {
        List<uint> meshInfoEnum = new List<uint>();
        fs.Read(infoBuffer1, 0, 1); meshInfoEnum.Add(infoBuffer1[0]);   //unk flag 1
        fs.Read(infoBuffer1, 0, 1); meshInfoEnum.Add(infoBuffer1[0]);   //unk flag 2
        fs.Read(infoBuffer2, 0, 2); uint meshIndex = BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0); meshInfoEnum.Add(meshIndex);
        fs.Read(infoBuffer2, 0, 2); uint unkIndex = BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0); meshInfoEnum.Add(unkIndex);
        fs.Read(infoBuffer2, 0, 2); uint null_MIT1 = BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0); meshInfoEnum.Add(null_MIT1);
        fs.Read(infoBuffer4, 0, 4); uint vertexCount = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0); meshInfoEnum.Add(vertexCount);
        fs.Read(infoBuffer4, 0, 4); uint null_MIT2 = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0); meshInfoEnum.Add(null_MIT2);
        fs.Read(infoBuffer4, 0, 4); uint null_MIT3 = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0); meshInfoEnum.Add(null_MIT3);
        fs.Read(infoBuffer4, 0, 4); uint faceIndexCount = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0); meshInfoEnum.Add(faceIndexCount);
        fs.Read(infoBuffer4, 0, 4); uint null_MIT4 = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0); meshInfoEnum.Add(null_MIT4);
        fs.Read(infoBuffer4, 0, 4); uint null_MIT5 = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0); meshInfoEnum.Add(null_MIT5);
        fs.Read(infoBuffer4, 0, 4); uint null_MIT6 = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0); meshInfoEnum.Add(null_MIT6);
        fs.Read(infoBuffer1, 0, 1); meshInfoEnum.Add(infoBuffer1[0]);   //unk flag 3
        fs.Read(infoBuffer1, 0, 1); meshInfoEnum.Add(infoBuffer1[0]);   //unk flag 4
        fs.Read(infoBuffer2, 0, 2); uint unkCount1 = BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0); meshInfoEnum.Add(unkCount1);
        fs.Read(infoBuffer4, 0, 4); uint null_MIT7 = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0); meshInfoEnum.Add(null_MIT7);
        fs.Read(infoBuffer4, 0, 4); uint null_MIT8 = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0); meshInfoEnum.Add(null_MIT8);
        meshInfoTable.Add(meshInfoEnum);
    }

    //Get fvfTable Count
    fs.Seek(0x18, SeekOrigin.Begin);
    fs.Read(infoBuffer2, 0, 2);
    uint fvfTableCount = BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0);

    //Enumerate fvfTable
    List<List<uint>> fvfTable = new List<List<uint>>();
    fs.Seek(0x40, SeekOrigin.Begin);
    fs.Read(infoBuffer4, 0, 4);
    uint fvfTableAddress = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0);
    fs.Seek(fvfTableAddress, SeekOrigin.Begin);
    for (int i = 0; i < fvfTableCount; i++)
    {
        List<uint> fvfTableEnum = new List<uint>();
        //def loadfvf(self, bs):
        //#FVF Table
        //for a in range(0, self.fvfCount):
        fs.Seek((fvfTableAddress + (i * 0x78)), SeekOrigin.Begin);  //bs.seek(self.fvfOffst + (a * 0x78), NOESEEK_ABS)
        //print(bs.tell())
        //fvfData = bs.read(">" + "6I4B23I")
        fs.Read(infoBuffer4, 0, 4); fvfTableEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
        fs.Read(infoBuffer4, 0, 4); fvfTableEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
        fs.Read(infoBuffer4, 0, 4); fvfTableEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
        fs.Read(infoBuffer4, 0, 4); fvfTableEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
        fs.Read(infoBuffer4, 0, 4); fvfTableEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
        fs.Read(infoBuffer4, 0, 4); fvfTableEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
        fs.Read(infoBuffer1, 0, 1); fvfTableEnum.Add(infoBuffer1[0]);
        fs.Read(infoBuffer1, 0, 1); fvfTableEnum.Add(infoBuffer1[0]);
        fs.Read(infoBuffer1, 0, 1); fvfTableEnum.Add(infoBuffer1[0]);
        fs.Read(infoBuffer1, 0, 1); fvfTableEnum.Add(infoBuffer1[0]);
        fs.Read(infoBuffer4, 0, 4); fvfTableEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
        fs.Read(infoBuffer4, 0, 4); fvfTableEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
        fs.Read(infoBuffer4, 0, 4); fvfTableEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
        fs.Read(infoBuffer4, 0, 4); fvfTableEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
        fs.Read(infoBuffer4, 0, 4); fvfTableEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
        fs.Read(infoBuffer4, 0, 4); fvfTableEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
        fs.Read(infoBuffer4, 0, 4); fvfTableEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
        fs.Read(infoBuffer4, 0, 4); fvfTableEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
        fs.Read(infoBuffer4, 0, 4); fvfTableEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
        fs.Read(infoBuffer4, 0, 4); fvfTableEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
        fs.Read(infoBuffer4, 0, 4); fvfTableEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
        fs.Read(infoBuffer4, 0, 4); fvfTableEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
        fs.Read(infoBuffer4, 0, 4); fvfTableEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
        fs.Read(infoBuffer4, 0, 4); fvfTableEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
        fs.Read(infoBuffer4, 0, 4); fvfTableEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
        fs.Read(infoBuffer4, 0, 4); fvfTableEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
        fs.Read(infoBuffer4, 0, 4); fvfTableEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
        fs.Read(infoBuffer4, 0, 4); fvfTableEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
        fs.Read(infoBuffer4, 0, 4); fvfTableEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
        fs.Read(infoBuffer4, 0, 4); fvfTableEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
        fs.Read(infoBuffer4, 0, 4); fvfTableEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
        fs.Read(infoBuffer4, 0, 4); fvfTableEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
        fs.Read(infoBuffer4, 0, 4); fvfTableEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));

        fs.Seek(fvfTableEnum[0], SeekOrigin.Begin);

        fvfTableEnum.Add((uint)fs.Position);

        fvfTable.Add(fvfTableEnum);
    }

    bp++;

    //Get PMSH Address
    fs.Seek(0xD0, SeekOrigin.Begin);
    fs.Read(infoBuffer4, 0, 4);
    pmshAddress = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0);

    //Get zlibInfoAddress
    fs.Seek(0xDC, SeekOrigin.Begin);
    fs.Read(infoBuffer4, 0, 4);
    zlibInfoAddress = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0);

    ushort pmshTable1Count = 0;
    ushort pmshTable2Count = 0;
    ushort pmshTable3Count = 0;
    ushort pmshTable4Count = 0;
    uint pmshTable1Address = 0;
    uint pmshTable2Address = 0;
    uint pmshTable3Address = 0;
    uint pmshTable4Address = 0;
    //Parse PMSH
    fs.Seek(pmshAddress, SeekOrigin.Begin);
    fs.Read(infoBuffer4, 0, 4); //PMSH Magic
    fs.Read(infoBuffer2, 0, 2);
    fs.Read(infoBuffer2, 0, 2);
    fs.Read(infoBuffer4, 0, 4); //PMSH Address from beginning of MDL3 file
    fs.Read(infoBuffer4, 0, 4); //padding?
    fs.Read(infoBuffer2, 0, 2);
    pmshTable1Count = BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0);
    fs.Read(infoBuffer2, 0, 2);
    pmshTable2Count = BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0);
    fs.Read(infoBuffer2, 0, 2);
    pmshTable3Count = BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0);
    fs.Read(infoBuffer2, 0, 2);
    pmshTable4Count = BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0);
    fs.Read(infoBuffer4, 0, 4);
    pmshTable1Address = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0);
    fs.Read(infoBuffer4, 0, 4);
    pmshTable2Address = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0);
    fs.Read(infoBuffer4, 0, 4);
    pmshTable3Address = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0);
    fs.Read(infoBuffer4, 0, 4);
    pmshTable4Address = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0);

    if (pmshTable1Count > 0)
    {
        fs.Seek(pmshTable1Address, SeekOrigin.Begin);

    }

    if (pmshTable2Count > 0)
    {
        fs.Seek(pmshTable2Address, SeekOrigin.Begin);
    }

    if (pmshTable3Count > 0)
    {
        fs.Seek(pmshTable3Address, SeekOrigin.Begin);
    }


    if (pmshTable4Count > 0)
    {
        List<uint> stringTableInfoPointers = new List<uint>();

        fs.Seek(pmshTable4Address, SeekOrigin.Begin);

        for (int i = 0; i < pmshTable4Count; i++)
        {
            fs.Read(infoBuffer1, 0, 1); //flag1
            fs.Read(infoBuffer1, 0, 1); //flag2
            fs.Read(infoBuffer1, 0, 1); //flag3
            fs.Read(infoBuffer1, 0, 1); //flag4
            fs.Read(infoBuffer4, 0, 4); //unk1
            fs.Read(infoBuffer4, 0, 4); //stringTableInfoPointer
            stringTableInfoPointers.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
            fs.Read(infoBuffer4, 0, 4); //unk2
        }

        for (int i = 0; i < pmshTable4Count; i++)
        {
            fs.Seek(stringTableInfoPointers[i], SeekOrigin.Begin);
            fs.Read(infoBuffer2, 0, 2); // ushort unk01;
            fs.Read(infoBuffer2, 0, 2); //ushort unk02;
            fs.Read(infoBuffer2, 0, 2); //ushort unk03;
            fs.Read(infoBuffer2, 0, 2); //ushort unk04;
            fs.Read(infoBuffer2, 0, 2); //ushort unk05;
            fs.Read(infoBuffer2, 0, 2); //ushort unk06;
            fs.Read(infoBuffer2, 0, 2); //ushort unk07;
            fs.Read(infoBuffer1, 0, 1); int entryType = infoBuffer1[0];
            fs.Read(infoBuffer1, 0, 1); //byte unk08;
            if (entryType == -2)
            {
                fs.Read(infoBuffer4, 0, 4); //ulong unkL01;
                fs.Read(infoBuffer4, 0, 4); //ulong unkL02;
                fs.Read(infoBuffer2, 0, 2); //ushort unkS03;
                fs.Read(infoBuffer2, 0, 2); //ushort unkS04;
                fs.Read(infoBuffer2, 0, 2); //ushort unkS05;
                fs.Read(infoBuffer2, 0, 2); //ushort unkS06;
            }
            if (entryType == -94)
            {
                fs.Read(infoBuffer4, 0, 4); //ulong unkL01;
                fs.Read(infoBuffer4, 0, 4); //ulong unkL02;
                fs.Read(infoBuffer2, 0, 2); //ushort unkS03;
                fs.Read(infoBuffer2, 0, 2); //ushort unkS04;
                fs.Read(infoBuffer2, 0, 2); //ushort unkS05;
                fs.Read(infoBuffer2, 0, 2); //ushort unkS06;
            }
            if (entryType == 2)
            {
                fs.Read(infoBuffer4, 0, 4); //ulong unkL01;
                fs.Read(infoBuffer4, 0, 4); //ulong unkL02;
                fs.Read(infoBuffer4, 0, 4); //ulong unkL03;
                fs.Read(infoBuffer4, 0, 4); //ulong unkL04;
            }
            if (entryType == 4)
            {
                fs.Read(infoBuffer2, 0, 2); //ushort unkS01;
                fs.Read(infoBuffer2, 0, 2); //ushort unkS02;
                fs.Read(infoBuffer4, 0, 4); //ulong unkL02;
                fs.Read(infoBuffer4, 0, 4); //ulong unkL03;
                fs.Read(infoBuffer4, 0, 4); //ulong unkL04;
                fs.Read(infoBuffer4, 0, 4); //ulong unkL05;
                fs.Read(infoBuffer4, 0, 4); //ulong unkL06;
                fs.Read(infoBuffer4, 0, 4); //ulong unkL07;
                fs.Read(infoBuffer4, 0, 4); //ulong unkL08;
            }
            if (i == (pmshTable4Count - 1))
            {
                bp++;
            }
        }

        //Read data info start
        fs.Seek(zlibInfoAddress, SeekOrigin.Begin);
        //FileStream zfs = new FileStream(fi.DirectoryName + "\\body_s.multiZlib", FileMode.Open, FileAccess.Read);
        FileStream zfs = new FileStream(fi.DirectoryName + "\\body_s", FileMode.Open, FileAccess.Read);
        FileStream dfs = new FileStream(fi.DirectoryName + "\\body_s.bin", FileMode.Create, FileAccess.Write);

        fs.Read(infoBuffer2, 0, 2); uint zlibInfo0 = BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0);
        fs.Read(infoBuffer2, 0, 2); uint zlibInfo1 = BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0);
        fs.Read(infoBuffer2, 0, 2); uint zlibInfo2 = BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0);
        fs.Read(infoBuffer2, 0, 2); uint zlibInfo3 = BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0);
        fs.Read(infoBuffer4, 0, 4); uint zlibInfo4 = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0);
        fs.Read(infoBuffer4, 0, 4); uint zlibInfo5 = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0);

        for (int i = 0; i < zlibInfo1; i++)
        {
            fs.Seek((zlibInfo4 + (0xC * i)), SeekOrigin.Begin);
            fs.Read(infoBuffer4, 0, 4); uint zlibHId = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0);
            fs.Read(infoBuffer4, 0, 4); uint zlibHCount = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0);
            fs.Read(infoBuffer4, 0, 4); uint zlibHoff = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0);

            for (int j = 0; j < zlibHCount; j++)
            {
                fs.Seek((zlibHoff + (0x18 * j)), SeekOrigin.Begin);
                fs.Read(infoBuffer4, 0, 4); uint null00 = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0);
                fs.Read(infoBuffer4, 0, 4); uint chunkStart = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0);
                fs.Read(infoBuffer2, 0, 2); uint chunkCount00 = BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0);
                fs.Read(infoBuffer2, 0, 2); uint chunkCount01 = BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0);
                fs.Read(infoBuffer4, 0, 4); uint chunkInfoOff00 = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0);
                fs.Read(infoBuffer2, 0, 2); uint chunkCount02 = BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0);
                fs.Read(infoBuffer2, 0, 2); uint chunkCount03 = BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0);
                fs.Read(infoBuffer4, 0, 4); uint chunkInfoOff01 = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0);

                for (int k = 0; k < (chunkCount00 + chunkCount01); k++)
                {
                    fs.Seek((chunkInfoOff00 + (0x8 * k)), SeekOrigin.Begin);
                    fs.Read(infoBuffer2, 0, 2); uint zFlag = BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0);
                    fs.Read(infoBuffer2, 0, 2); uint zSize = BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0);
                    fs.Read(infoBuffer4, 0, 4); uint uSize = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0);

                    zfs.Seek(chunkStart, SeekOrigin.Begin);
                    byte[] cmpData = new byte[zSize];
                    zfs.Read(cmpData, 0, cmpData.Length);
                    if (zFlag == 0)
                    {
                        dfs.Write(cmpData, 0, cmpData.Length);
                    }
                    else
                    {
                        byte[] dcmpData = DeflateStream.UncompressBuffer(cmpData);
                        dfs.Write(dcmpData, 0, dcmpData.Length);
                    }
                    chunkStart += zSize;
                }

                for (int k = 0; k < (chunkCount02 + chunkCount03); k++)
                {
                    fs.Seek((chunkInfoOff01 + (0x10 * k)), SeekOrigin.Begin);
                    fs.Read(infoBuffer4, 0, 4); uint null00a = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0);
                    fs.Read(infoBuffer4, 0, 4); uint chunkStart2 = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0);
                    fs.Read(infoBuffer2, 0, 2); uint chunkCount04 = BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0);
                    fs.Read(infoBuffer2, 0, 2); uint chunkCount05 = BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0);
                    fs.Read(infoBuffer4, 0, 4); uint zlibHoff2 = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0);

                    for (int l = 0; l < (chunkCount04 + chunkCount05); l++)
                    {
                        fs.Seek((zlibHoff2 + (0x8 * l)), SeekOrigin.Begin);
                        fs.Read(infoBuffer2, 0, 2); uint zFlag = BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0);
                        fs.Read(infoBuffer2, 0, 2); uint zSize = BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0);
                        fs.Read(infoBuffer4, 0, 4); uint uSize = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0);

                        zfs.Seek(chunkStart2, SeekOrigin.Begin);
                        byte[] cmpData = new byte[zSize];
                        zfs.Read(cmpData, 0, cmpData.Length);
                        if (zFlag == 0)
                        {
                            dfs.Write(cmpData, 0, cmpData.Length);
                        }
                        else
                        {
                            byte[] dcmpData = DeflateStream.UncompressBuffer(cmpData);
                            dfs.Write(dcmpData, 0, dcmpData.Length);
                        }
                        chunkStart2 += zSize;
                    }
                }
            }
        }

        zfs.Close();
        dfs.Close();

        //Enumerate body_s.bin header and main table
        FileStream bfs = new FileStream(fi.DirectoryName + "\\body_s.bin", FileMode.Open, FileAccess.Read);
        FileInfo bfi = new FileInfo(fi.DirectoryName + "\\body_s.bin");

        //Enumerate body_s.bin header
        bfs.Read(infoBuffer4, 0, 4); uint sNull00 = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0);
        bfs.Read(infoBuffer4, 0, 4); uint sAddress1 = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0); //unknown data address
        bfs.Read(infoBuffer4, 0, 4); uint sAddress2 = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0); //data near end of file
        bfs.Read(infoBuffer4, 0, 4); uint sAddress3 = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0); //unknown data address or size
        bfs.Read(infoBuffer4, 0, 4); uint sNull01 = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0);
        bfs.Read(infoBuffer2, 0, 2); uint sTable1Count = BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0);
        bfs.Read(infoBuffer2, 0, 2); uint sCount2 = BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0);
        bfs.Read(infoBuffer4, 0, 4); uint sCount3 = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0);
        bfs.Read(infoBuffer4, 0, 4); uint sAddress4 = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0); //pointer to another table

        List<List<uint>> sTable1 = new List<List<uint>>();
        for (int i = 0; i < sTable1Count; i++)
        {
            List<uint> sTable1Enum = new List<uint>();
            bfs.Read(infoBuffer4, 0, 4); uint dataId = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0); sTable1Enum.Add(dataId);
            bfs.Read(infoBuffer4, 0, 4); uint vAddress = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0); sTable1Enum.Add(vAddress);
            bfs.Read(infoBuffer4, 0, 4); uint fAddress = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0); sTable1Enum.Add(fAddress);
            bfs.Read(infoBuffer4, 0, 4); uint u1Address = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0); sTable1Enum.Add(u1Address);
            bfs.Read(infoBuffer4, 0, 4); uint u2Address = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0); sTable1Enum.Add(u2Address);
            bfs.Read(infoBuffer4, 0, 4); uint u3Address = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0); sTable1Enum.Add(u3Address);
            bfs.Read(infoBuffer4, 0, 4); uint u4Address = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0); sTable1Enum.Add(u4Address);
            bfs.Read(infoBuffer4, 0, 4); uint dataTypeFlag = BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0); sTable1Enum.Add(dataTypeFlag);
            sTable1.Add(sTable1Enum);
        }

        //Parse and extract sTable1[i][7] //SO FAR, (known as the mesh data signaling flag when its 0x00000000, 0x00000001, and 0x00000002)
        for (int i = 0; i < sTable1Count; i++)
        {
            if (sTable1[i][7] == 0) //standard lod
            {
                //Process known mesh data
                int meshInfoTableIndex = (int)sTable1[i][0];
                uint vCount = meshInfoTable[meshInfoTableIndex][5];
                uint fCount = meshInfoTable[meshInfoTableIndex][8];
                uint vAddress = sTable1[i][1];
                uint fAddress = sTable1[i][2];
                uint vStride = fvfTable[(int)meshInfoTable[(int)sTable1[i][0]][2]][7];

                //Enumerate vertices
                List<List<float>> verticesList = new List<List<float>>();
                bfs.Seek(vAddress, SeekOrigin.Begin);
                for (int j = 0; j < vCount; j++)
                {
                    List<float> vEnum = new List<float>();
                    if (vStride >= 12)
                    {
                        bfs.Read(infoBuffer4, 0, 4); vEnum.Add(-BitConverter.ToSingle(mh.ArrayReverse(infoBuffer4), 0));
                        bfs.Read(infoBuffer4, 0, 4); vEnum.Add(BitConverter.ToSingle(mh.ArrayReverse(infoBuffer4), 0));
                        bfs.Read(infoBuffer4, 0, 4); vEnum.Add(BitConverter.ToSingle(mh.ArrayReverse(infoBuffer4), 0));
                        bfs.Seek((vStride - 12), SeekOrigin.Current);
                        verticesList.Add(vEnum);
                    }
                    else
                    {

                    }
                }

                //Enumerate Faces
                List<List<ushort>> facesList = new List<List<ushort>>();
                bfs.Seek(fAddress, SeekOrigin.Begin);
                for (int j = 0; j < (fCount / 3); j++)
                {
                    List<ushort> fEnum = new List<ushort>();
                    if (vStride >= 12)
                    {
                        bfs.Read(infoBuffer2, 0, 2); fEnum.Add(BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0));
                        bfs.Read(infoBuffer2, 0, 2); fEnum.Add(BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0));
                        bfs.Read(infoBuffer2, 0, 2); fEnum.Add(BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0));
                        facesList.Add(fEnum);
                    }
                }

                //Write .obj file
                if (vStride >= 12)
                {
                    string outputPath = bfi.DirectoryName + "\\" + Path.GetFileNameWithoutExtension(bfi.Name) + "_extracted";
                    Directory.CreateDirectory(outputPath);
                    ow.writeSpecifiedObjFile(verticesList, facesList, null, ref bfi, ref bfi, 1, bfi.Name, "__" + mh.readString(ref fs, fvfTable[(int)meshInfoTable[(int)sTable1[i][0]][2]][0x21]) + "_" + meshInfoTableIndex.ToString("X"), 0);
                }
            }
            else //highest lod
            {
                //Read bounding box
                bfs.Seek(sTable1[i][3], SeekOrigin.Begin);
                List<List<float>> boundingBox = new List<List<float>>();
                for (int j = 0; j < 8; j++)
                {
                    List<float> bbEnum = new List<float>();
                    bfs.Read(infoBuffer4, 0, 4); bbEnum.Add(BitConverter.ToSingle(mh.ArrayReverse(infoBuffer4), 0));
                    bfs.Read(infoBuffer4, 0, 4); bbEnum.Add(BitConverter.ToSingle(mh.ArrayReverse(infoBuffer4), 0));
                    bfs.Read(infoBuffer4, 0, 4); bbEnum.Add(BitConverter.ToSingle(mh.ArrayReverse(infoBuffer4), 0));
                    boundingBox.Add(bbEnum);
                }

                string outputPathbb = bfi.DirectoryName + "\\" + Path.GetFileNameWithoutExtension(bfi.Name) + "_extracted";
                Directory.CreateDirectory(outputPathbb);
                ow.writeSpecifiedObjFile(boundingBox, ref bfi, ref bfi, 1, bfi.Name, "_" + "boundingBox_" + sTable1[i][0].ToString("X"));

                //Read info1
                bfs.Seek(sTable1[i][4], SeekOrigin.Begin);
                List<ushort> info1 = new List<ushort>();
                bfs.Read(infoBuffer2, 0, 2); info1.Add(BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0));
                bfs.Read(infoBuffer2, 0, 2); info1.Add(BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0));
                bfs.Read(infoBuffer2, 0, 2); info1.Add(BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0));
                bfs.Read(infoBuffer2, 0, 2); info1.Add(BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0));
                bfs.Read(infoBuffer2, 0, 2); info1.Add(BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0));
                bfs.Read(infoBuffer2, 0, 2); info1.Add(BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0));
                bfs.Read(infoBuffer2, 0, 2); info1.Add(BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0));
                bfs.Read(infoBuffer2, 0, 2); info1.Add(BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0));

                //Read info for mesh data
                bfs.Seek(sTable1[i][5], SeekOrigin.Begin);
                List<List<uint>> meshDataInfo = new List<List<uint>>();
                for (int j = 0; j < sTable1[i][7]; j++) //find this count if it exists
                {
                    List<uint> mdiEnum = new List<uint>();
                    bfs.Read(infoBuffer4, 0, 4); mdiEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
                    bfs.Read(infoBuffer4, 0, 4); mdiEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
                    bfs.Read(infoBuffer4, 0, 4); mdiEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
                    bfs.Read(infoBuffer4, 0, 4); mdiEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
                    bfs.Read(infoBuffer4, 0, 4); mdiEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
                    bfs.Read(infoBuffer4, 0, 4); mdiEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
                    bfs.Read(infoBuffer4, 0, 4); mdiEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
                    bfs.Read(infoBuffer4, 0, 4); mdiEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
                    bfs.Read(infoBuffer4, 0, 4); mdiEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
                    bfs.Read(infoBuffer4, 0, 4); mdiEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
                    bfs.Read(infoBuffer4, 0, 4); mdiEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
                    bfs.Read(infoBuffer4, 0, 4); mdiEnum.Add(BitConverter.ToUInt32(mh.ArrayReverse(infoBuffer4), 0));
                    meshDataInfo.Add(mdiEnum);
                }

                //Process HIGHLOD vertices
                for (int j = 0; j < sTable1[i][7]; j++)
                {
                    bfs.Seek(meshDataInfo[j][0], SeekOrigin.Begin);

                    //Enumerate ushort vertices as tris
                    List<List<float>> vList0 = new List<List<float>>();
                    for (int k = 0; k < meshDataInfo[j][8]; k++)
                    {
                        List<float> vEnum = new List<float>();
                        float vxF = 0; float vyF = 0; float vzF = 0;
                        bfs.Read(infoBuffer2, 0, 2); vxF = -BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0); vxF /= 0xFFFF; vEnum.Add(vxF);
                        bfs.Read(infoBuffer2, 0, 2); vyF = BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0); vyF /= 0xFFFF; vEnum.Add(vyF);
                        bfs.Read(infoBuffer2, 0, 2); vzF = BitConverter.ToUInt16(mh.ArrayReverse(infoBuffer2), 0); vzF /= 0xFFFF; vEnum.Add(vzF);
                        vList0.Add(vEnum);
                    }
                    string outputPath = bfi.DirectoryName + "\\" + Path.GetFileNameWithoutExtension(bfi.Name) + "_extracted";
                    Directory.CreateDirectory(outputPath);
                    ow.writeSpecifiedObjFile(vList0, ref bfi, ref bfi, 1, bfi.Name, "_" + j.ToString() + "_" + sTable1[i][0].ToString("X"));
                }

            }
        }

        //USE FOR TEXTURE DATA MAYBE
        //bfs.Seek(sAddress4, SeekOrigin.Begin); //Texture Data

        bp++;

        bfs.Close();
    }
}
cornal
beginner
Posts: 39
Joined: Sat Oct 25, 2014 3:31 am
Has thanked: 3 times
Been thanked: 9 times

Re: Gran Turismo 6 Models

Post by cornal »

Hi, I'm new here only a question GTTools runs on Win8.1? because I can't run it.
And other thing I decompress some .pkg's from GT6 updates this shows directories similar to the game directory, but in a folder named USRDIR shows more folders containing files without extensions.
I like somebody can help with this. Thanks.
User avatar
Ferrari formula 1
advanced
Posts: 72
Joined: Mon Aug 11, 2014 11:42 am
Has thanked: 28 times
Been thanked: 11 times

Re: Gran Turismo 6 Models

Post by Ferrari formula 1 »

EcheloCross wrote:Here is my code so far for handling the MDL3 files. If you read through it you can either copy it to a c# program of your own, or re-write it in the language of your choice.

This code handles both the 2nd highest lod, and the vertices only of the highest lod. The faces for the highest lod are edge compressed, I need to spend some more time with edge to get them figured out.
So,as far as i understand,i use offzip to extract data from body_s,and then your script should do the job and make an .OBJ file of a car like this one? :)
Image

If so,could you tell me please,in which programm should I run this C# script?

Also,I've been sucsessfully using offzip many times before,but right now I'm making a mistake,can you help me to slove it? :roll:
Image
Image
EcheloCross
veteran
Posts: 88
Joined: Sat Feb 27, 2010 6:57 pm
Has thanked: 40 times
Been thanked: 77 times

Re: Gran Turismo 6 Models

Post by EcheloCross »

No you do not use offzip. You need to make a new c# program (with Visual Studio) and use that function in it. It will not work right out of the box either, you must provide your own objWriter method, and add DotNetZip's compression namespace to your program as well. Also, make a public byte[] called ArrayReverse and make it return the reversed byte[] that is passed to it. (Just for endianness).

The body_s sections can be compressed, and can be raw. The code will get all the compressed and raw chunks out and merge them to a body_s.bin file. The offzip method will miss the raw chunks.

Here is the ArrayReverse method:

Code: Select all

public byte[] ArrayReverse(byte[] array)
{
    Array.Reverse(array);
    return array;
}
Here are some of my objWriter methods: (the ones this code calls)

Code: Select all

//generic
public void writeSpecifiedObjFile(
    List<List<float>> posList,
    List<List<ushort>> idxListUshort,
    List<List<ulong>> idxListUlong,
    ref FileInfo vfi,
    ref FileInfo ffi,
    int vertexOrderIndex,
    string outputName,
    string meshName,
    int facesMethod)
{
    StreamWriter objSw = new StreamWriter(
        vfi.DirectoryName + "\\" +
        Path.GetFileNameWithoutExtension(outputName) + "_extracted\\" +
        Path.GetFileNameWithoutExtension(outputName) + meshName +
        ".obj");
    foreach (List<float> lf in posList)
    {
        string x, y, z;
        if (lf[0].ToString().Contains("E") == true)
        {
            x = lf[0].ToString("F9");
        }
        else
        {
            x = lf[0].ToString();
        }
        if (lf[1].ToString().Contains("E"))
        {
            y = lf[1].ToString("F9");
        }
        else
        {
            y = lf[1].ToString();
        }
        if (lf[2].ToString().Contains("E"))
        {
            z = lf[2].ToString("F9");
        }
        else
        {
            z = lf[2].ToString();
        }
        if (vertexOrderIndex == 0)
        {
            objSw.WriteLine("v " + x + " " + y + " " + z);
        }
        if (vertexOrderIndex == 1)
        {
            objSw.WriteLine("v " + x + " " + z + " " + y);
        }
        if (vertexOrderIndex == 2)
        {
            objSw.WriteLine("v " + y + " " + x + " " + z);
        }
        if (vertexOrderIndex == 3)
        {
            objSw.WriteLine("v " + y + " " + z + " " + x);
        }
        if (vertexOrderIndex == 4)
        {
            objSw.WriteLine("v " + z + " " + x + " " + y);
        }
        if (vertexOrderIndex == 5)
        {
            objSw.WriteLine("v " + z + " " + y + " " + x);
        }
    }
    objSw.WriteLine("g " + ffi.Name);
    //objSw.WriteLine("usemtl " + matList[(int)objGeoSubCountCounter].ToString()); //Add .mtl generation in the future
    if (facesMethod == 0 || facesMethod == 2 || facesMethod == 3) //USHORT or TRI-STRIP or Generated faces
    {
        foreach (List<ushort> lS in idxListUshort)
        {
            objSw.WriteLine("f  " + (lS[0] + 1).ToString() + "/" + (lS[0] + 1).ToString() + "/" + (lS[0] + 1).ToString() + " "
                                  + (lS[1] + 1).ToString() + "/" + (lS[1] + 1).ToString() + "/" + (lS[1] + 1).ToString() + " "
                                  + (lS[2] + 1).ToString() + "/" + (lS[2] + 1).ToString() + "/" + (lS[2] + 1).ToString());
        }
    }
    if (facesMethod == 1 || facesMethod == 4) //ULONG or (24bit as ULONG)
    {
        foreach (List<ulong> lL in idxListUlong)
        {
            objSw.WriteLine("f  " + (lL[0] + 1).ToString() + "/" + (lL[0] + 1).ToString() + "/" + (lL[0] + 1).ToString() + " "
                                  + (lL[1] + 1).ToString() + "/" + (lL[1] + 1).ToString() + "/" + (lL[1] + 1).ToString() + " "
                                  + (lL[2] + 1).ToString() + "/" + (lL[2] + 1).ToString() + "/" + (lL[2] + 1).ToString());
        }
    }
    objSw.Close();
}


//generic no faces
public void writeSpecifiedObjFile(
    List<List<float>> posList,
    ref FileInfo vfi,
    ref FileInfo ffi,
    int vertexOrderIndex,
    string outputName,
    string meshName)
{
    StreamWriter objSw = new StreamWriter(
        vfi.DirectoryName + "\\" +
        Path.GetFileNameWithoutExtension(outputName) + "_extracted\\" +
        Path.GetFileNameWithoutExtension(outputName) + meshName +
        ".obj");
    foreach (List<float> lf in posList)
    {
        string x, y, z;
        if (lf[0].ToString().Contains("E") == true)
        {
            x = lf[0].ToString("F9");
        }
        else
        {
            x = lf[0].ToString();
        }
        if (lf[1].ToString().Contains("E"))
        {
            y = lf[1].ToString("F9");
        }
        else
        {
            y = lf[1].ToString();
        }
        if (lf[2].ToString().Contains("E"))
        {
            z = lf[2].ToString("F9");
        }
        else
        {
            z = lf[2].ToString();
        }
        if (vertexOrderIndex == 0)
        {
            objSw.WriteLine("v " + x + " " + y + " " + z);
        }
        if (vertexOrderIndex == 1)
        {
            objSw.WriteLine("v " + x + " " + z + " " + y);
        }
        if (vertexOrderIndex == 2)
        {
            objSw.WriteLine("v " + y + " " + x + " " + z);
        }
        if (vertexOrderIndex == 3)
        {
            objSw.WriteLine("v " + y + " " + z + " " + x);
        }
        if (vertexOrderIndex == 4)
        {
            objSw.WriteLine("v " + z + " " + x + " " + y);
        }
        if (vertexOrderIndex == 5)
        {
            objSw.WriteLine("v " + z + " " + y + " " + x);
        }
    }
    objSw.WriteLine("g " + ffi.Name);
    objSw.Close();
}
DotNetZip is open source and is easily addable to any c# program. You can also use anything that supports Deflate.

Have fun. :)
barti
veteran
Posts: 148
Joined: Sun Apr 01, 2012 12:44 pm
Has thanked: 51 times
Been thanked: 102 times

Re: Gran Turismo 6 Models

Post by barti »

Thanks, but what about the ReadString method?
EcheloCross
veteran
Posts: 88
Joined: Sat Feb 27, 2010 6:57 pm
Has thanked: 40 times
Been thanked: 77 times

Re: Gran Turismo 6 Models

Post by EcheloCross »

barti wrote:Thanks, but what about the ReadString method?

Code: Select all

//Read a zero terminated string at specified address
public string readString(ref FileStream fs, uint specifiedAddress)
{
    string stringToBuild = String.Empty;
    bool endReached = false;
    fs.Seek(specifiedAddress, SeekOrigin.Begin);
    fs.Read(infoBuffer1, 0, 1);
    stringToBuild += Encoding.ASCII.GetString(infoBuffer1);
    while (endReached == false)
    {
        fs.Read(infoBuffer1, 0, 1);
        if (infoBuffer1[0] == 0)
        {
            endReached = true;
        }
        else
        {
            stringToBuild += Encoding.ASCII.GetString(infoBuffer1);
        }
    }
    return stringToBuild;
}
barti
veteran
Posts: 148
Joined: Sun Apr 01, 2012 12:44 pm
Has thanked: 51 times
Been thanked: 102 times

Re: Gran Turismo 6 Models

Post by barti »

Thank you, it works now :D

Image
Image

Here's a simple pre-built converter in case anyone needs it (requires .NET Framework 4.0):

Code: Select all

http://speedy.sh/3hJvz/gt6.zip
User avatar
Ferrari formula 1
advanced
Posts: 72
Joined: Mon Aug 11, 2014 11:42 am
Has thanked: 28 times
Been thanked: 11 times

Re: Gran Turismo 6 Models

Post by Ferrari formula 1 »

Great progress,guys! :)

Now,let's see if we can get semi-standart car out in highest lod! :)

Standart:Cars ported to GT6 from GT3\4 (Low-poly,about 4000 polygons,poor detail nowadays,no interior)
Elite:Cars made for GT5\GT6 (High-poly,incredeble detail,Interior)

And in GT6 they have kinda semi-standart cars:Remastered cars from GT3\GT4(Mid-High poly,Very good detail,no interior,look at page 7)

As I can see,there's no problem with getting highest lod from a standart car(Mazda rx-8 from previous post) so I'm curious to see if It's the same for semi-standarts(Like Nissan gt-r from page 7)

So,can anybody try it out with this car?

Code: Select all

RecNo      ModelCode	  LabelID	 Name
230	      30109   836    Nissan       SKYLINE 2000GT-R (KPGC110) '73

There's a lot of remastered,semi-standart cars,I'll provide list soon (:
TomWin
veteran
Posts: 146
Joined: Sun Apr 11, 2010 7:46 pm
Has thanked: 16 times
Been thanked: 9 times

Re: Gran Turismo 6 Models

Post by TomWin »

Hm that pre-built extractor doesn't work for me. What do I do wrong?

Image

great progress and thanks to all for the hard work
barti
veteran
Posts: 148
Joined: Sun Apr 01, 2012 12:44 pm
Has thanked: 51 times
Been thanked: 102 times

Re: Gran Turismo 6 Models

Post by barti »

TomWin wrote:Hm that pre-built extractor doesn't work for me. What do I do wrong?

great progress and thanks to all for the hard work
Load "body", not "body_s".
User avatar
Ferrari formula 1
advanced
Posts: 72
Joined: Mon Aug 11, 2014 11:42 am
Has thanked: 28 times
Been thanked: 11 times

Re: Gran Turismo 6 Models

Post by Ferrari formula 1 »

barti wrote:
TomWin wrote:Hm that pre-built extractor doesn't work for me. What do I do wrong?

great progress and thanks to all for the hard work
Load "body", not "body_s".
Same happens to me,no matter if it's body or body_s :?

Image
barti
veteran
Posts: 148
Joined: Sun Apr 01, 2012 12:44 pm
Has thanked: 51 times
Been thanked: 102 times

Re: Gran Turismo 6 Models

Post by barti »

Ferrari formula 1 wrote:Same happens to me,no matter if it's body or body_s :?
Your error message is different. It says it can't open / find the "body_s" file. Are you sure it's there?
User avatar
Ferrari formula 1
advanced
Posts: 72
Joined: Mon Aug 11, 2014 11:42 am
Has thanked: 28 times
Been thanked: 11 times

Re: Gran Turismo 6 Models

Post by Ferrari formula 1 »

barti wrote:
Ferrari formula 1 wrote:Same happens to me,no matter if it's body or body_s :?
Your error message is different. It says it can't open / find the "body_s" file. Are you sure it's there?
Aaaahh,now I see the problem...
Well,it made up a bunch of obj files,but i can"t open them all together(at once)
I tried about 10 separated files,but they were blank or strange flat surfaces :?
EDIT:
Still doesn't works for me,i have no parts of car in result.

Got only BIN (donno what to do with it) and a lot of OBJ(1-11 kb each,can't open in 3ds max,in cinema 4d it's strange surfaces or nothing at all.however,it tells me that data contains 240 polygons)
barti
veteran
Posts: 148
Joined: Sun Apr 01, 2012 12:44 pm
Has thanked: 51 times
Been thanked: 102 times

Re: Gran Turismo 6 Models

Post by barti »

From what I understand, high LOD cars are stored in different format. So far only vertices can be extracted from them (no faces), and they're scaled incorrectly. I accidentally forgot to include the code for extracting them, but this may be the reason why there are only flat surfaces on some models. If you have a "hq" and "race" folder, try the "body" file from both of them.

I'll see how I can edit the OBJ Writer to reduce the number of .obj files.
User avatar
Ferrari formula 1
advanced
Posts: 72
Joined: Mon Aug 11, 2014 11:42 am
Has thanked: 28 times
Been thanked: 11 times

Re: Gran Turismo 6 Models

Post by Ferrari formula 1 »

barti wrote:From what I understand, high LOD cars are stored in different format. So far only vertices can be extracted from them (no faces), and they're scaled incorrectly. I accidentally forgot to include the code for extracting them, but this may be the reason why there are only flat surfaces on some models. If you have a "hq" and "race" folder, try the "body" file from both of them.

I'll see how I can edit the OBJ Writer to reduce the number of .obj files.
There's a problem with that:If I write to open body from hq\race folder,it extracts body_s anyway.
I can't open obj files in 3ds max.

This is what happens when I open body (not body_s)
None of extractet OBJ files can't be opened in 3ds max
Image
Post Reply