|
|
Line 1: |
Line 1: |
− | {{OldWikiEntry}} ===GMDC Model Data File Specs===
| + | #REDIRECT [[AC4F8687]] |
| | | |
− | These are most likely the actual 3D models since they tend to be the largest files (besides textures and animations).
| + | [[Category:Modding]] |
− | | + | [[Category:InternalFormats]] |
− | ==this file type uses the Resource Collection format [[RCOL]].==
| + | [[Category:FormatsByName]] |
− | | + | |
− | Examples found in ""The Sims 2\TSData\Res\Sims3D\sims03.package""
| + | |
− | | + | |
− | | + | |
− | This file type uses the standard RCOL header, generally having no file links and only 1 block.
| + | |
− | | + | |
− | The simplified header looks like this but a program should probably use the more general form.
| + | |
− | 4 new ID flag: This may or may not be there(see [[RCOL]])
| + | |
− | 4 file link count (0)
| + | |
− | 4 index itemcount (1)
| + | |
− | 4 block id (0xAC4F8687)
| + | |
− | | + | |
− | followed by the GMDC block
| + | |
− | [[AC4F8687]] | + | |
− | [[cGeometryDataContainer]]
| + | |
− | | + | |
− | cGeometryDataContainer (GMDC) written 6-jan-2005 (WesHowe)
| + | |
− | latest update: 03-Feb-2005
| + | |
− | | + | |
− | The GMDC contains the actual shape (mesh) data that defines an object in the game. It uses the standard RCOL format, described elsewhere. What this page will describe is the data model it follows and the known usage of these elements within TS2.
| + | |
− | | + | |
− | There are three top-level structures; the General Header, Block Header and the Contents Section. The first two relate closely to the general RCOL format. The Content section was designed to support 3D object data.
| + | |
− | | + | |
− |
| + | |
− | | + | |
− | <pre>
| + | |
− | struct GeneralHeader {
| + | |
− | short ghLang; '' =1, a default value Note: some files do not have this or the next item
| + | |
− | short ghStringStyle; ''=0xffff, default value
| + | |
− | long ghRepVal; ''=0, default value - One some files, this is the first item
| + | |
− | long ghIndexValue; ''=1. This could mean more than one GMDC, but not verified.
| + | |
− |
| + | |
− | }
| + | |
− | struct BlockHeader {
| + | |
− | char bhNameLen; '' this byte will tell how many text characters follow
| + | |
− | char bhName[bhNameLen]
| + | |
− |
| + | |
− | long bhVersion; '' =1||2||4
| + | |
− | char bhResNameLen; '' This value indicates how many chars follow
| + | |
− | char bhResName[bhResNameLen]
| + | |
− | long bhResID; '' =0 (always this)
| + | |
− | long bhResVersion; '' =2 (seems to always be this)
| + | |
− | char bhFilenameLen; '' shows how many characters of name follow
| + | |
− | char bhFilename[bhFilenameLen]; ''the internal filename
| + | |
− | }
| + | |
− | struct Contents {
| + | |
− | long ElemCt; '' how many copies of struct
| + | |
− | '' Elements follow
| + | |
− | struct Elements[ElemCt]; '' just appended end-to-end
| + | |
− | long LinkCt; '' how many Links
| + | |
− | struct Linkage[LinkCt]; '' and then the Linkage copies
| + | |
− | long GroupCt; '' how many are coming
| + | |
− | struct Group[GroupCt]; '' placed one after the other
| + | |
− | struct ModelData; '' only one of these
| + | |
− | long SubsetCt; '' how many subsets are appended
| + | |
− | '' (0=none)
| + | |
− | struct Subset[SubsetCt]; '' appended to here
| + | |
− | }
| + | |
− | </pre>
| + | |
− | Almost all of the first two structures, except for the version and the filename, seem to be invariant in TS2. When I create a GMDC I just copy a fixed block of everything up to the filename length in one fwrite() [I only output as version 4].
| + | |
− | The remainder here is a data definition and values discussion, up to the limits of what I know.
| + | |
− | <pre>
| + | |
− | struct Elements { '' P1 - this holds the vertices,
| + | |
− | '' normals and UV values
| + | |
− | long NumRecs; '' # of records (item count)
| + | |
− | long Identity; '' a typing value, discussed
| + | |
− | '' later
| + | |
− | long RepeatCt; '' how many times type was used
| + | |
− |
| + | |
− | long Mod1; '' related to the type, but what
| + | |
− | '' it means is unknown
| + | |
− | long Mod2; '' also related to type (these
| + | |
− | '' are discussed later)
| + | |
− | long BlockSz; '' This is NumRecs times two
| + | |
− | '' or three times item size (float=4 bytes)
| + | |
− | float Block[NumRecs][x]; '' Vertices, etc., depending
| + | |
− | '' on type (P1Identity)
| + | |
− | long ExItemCt; '' either 2 or 4 bytes times
| + | |
− | '' this to follow (per version)
| + | |
− | short ExtensionArray; '' if (version==4)
| + | |
− | long ExtensionArray; '' if
| + | |
− | '' ((version==1)||(version==2))
| + | |
− | }
| + | |
− | </pre>
| + | |
− |
| + | |
− | 0x1c4afc56 :mod1=2 mod2=0
| + | |
− | 0x3b83078b :mod1=2 mod2=1,3 - Normals list (3 x float)
| + | |
− | 0x3bd70105 :mod1=0,1,2 mod2=0,3 - Bone weights (1, 2 or 3 floats per vertice)
| + | |
− | 0x5b830781 :mod1=2 mod2=0,3 - Vertices list (3 x float)
| + | |
− | 0x5c4afc5c :mod1=0 mod2=0
| + | |
− | 0x5cf2cfe1 :mod1=2 mod2=3 - Morph Vertex Deltas
| + | |
− | 0x7c4dee82 :mod1=2 mod2=1
| + | |
− | 0x89d92ba0 :mod1=2 mod2=3 - Bump map normals (3 x float)
| + | |
− | 0xcb6f3a6a :mod1=2 mod2=3 - Morph normal deltas
| + | |
− | 0xbb8307ab :mod1=1 mod2=2,3 - UV coordinates (2 x float)
| + | |
− | 0xdb830795 :mod1=4 mod2=2,3
| + | |
− | 0xdcf2cfdc :mod1=4 mod2=3 - Morph vertex map
| + | |
− |
| + | |
− | | + | |
− | Identities are used to identify data list type
| + | |
− | | + | |
− | Mod1 and Mod2 - valid values are 0,1,2 or 4.
| + | |
− | Mod 1 values 0,1,2 mean floats 1, 2 or 3 times #records, 4 means dword 1 time # records (credit darkmatter)
| + | |
− | If identity=0x7c4dee82 mod1 will be 2 and mod2 will be 1 but the above rules sometimes don't apply
| + | |
− | | + | |
− |
| + | |
− |
| + | |
− |
| + | |
− |
| + | |
− | 0x3bd70105 :mod1=0,1,2 mod2=0,3 - Bone weights (1, 2 or 3 floats per vertice) (matching above assignments)
| + | |
− | 0xdcf2cfdc maps each vertex to a small int, which then keys into the morph vertex and normal data lists (1 for first pair, 2 for second, etc.) to find float values to be added to the original vertices and normals to modify the mesh for fatbelly, pregnant, etc.
| + | |
− | | + | |
− | It also appears that most of these types must be there, even if empty, to satisfy the game loader.
| + | |
− | <pre>
| + | |
− | struct Linkage { '' P2
| + | |
− | long LkIndexCt; '' # of entries to follow
| + | |
− | short LkIndexData[LkIndexPtrCt]; '' if (version==4)
| + | |
− | long LkIndexData[LkIndexPtrCt]; '' if
| + | |
− | '' ((version==1)||(version==2))
| + | |
− | long LkVerticeCt; '' number of vertices in the model
| + | |
− | long LkActiveCt; '' This seems to be the same as P2IndexCt
| + | |
− | long LkBlockBCt; '' number of entries that follow
| + | |
− | short LkBlockB[LkBlockBCt]; '' if (version==4)
| + | |
− | long LkBlockB[LkBlockBCt]; '' if ((version==1)||(version==2))
| + | |
− | long LkBlockCCt; '' number of entries that follow
| + | |
− | short LkBlockC[LkBlockCCt]; '' if (version==4)
| + | |
− | long LkBlockC[LkBlockCCt]; '' if ((version==1)||(version==2))
| + | |
− | long LkBlockDCt; '' number of entries that follow
| + | |
− | short LkBlockD[LkBlockDCt]; '' if (version==4)
| + | |
− | long LkBlockD[LkBlockDCt]; '' if ((version==1)||(version==2))
| + | |
− | }
| + | |
− | </pre>
| + | |
− |
| + | |
− | <pre>
| + | |
− | struct Group { '' P3 - the group/face definition data is in here
| + | |
− | long Whatzit; '' =2, seems to be invariant
| + | |
− | long LinkIndex; '' use this value to index into LkIndexData for
| + | |
− | '' vertices and other parts
| + | |
− | char NameLen; '' number of name chars to follow
| + | |
− | char GroupName[NameLen]; '' the name of our model group (e.g. body)
| + | |
− | long FaceCt; '' number of faces (triangles), times 3
| + | |
− | short FaceData[FaceCt]; '' if (version==4)
| + | |
− | long FaceData[FaceCt] '' if ((version==1)||(version==2))
| + | |
− | long Opacity; '' 0xffffffff for solid, much smaller values
| + | |
− | '' for shadows
| + | |
− | if(version!=1) {
| + | |
− |
| + | |
− | '' are indices to ModelSubset
| + | |
− | short SubsetIndices[SubsetCt]; '' if (version==4)
| + | |
− | long SubsetIndices[SubsetCt]; '' if (version==2)
| + | |
− | } '' if()
| + | |
− | }
| + | |
− | </pre>
| + | |
− |
| + | |
− | <pre>
| + | |
− | struct ModelData { '' P4 - this is a composite or subset model
| + | |
− | long TransformCt; '' number of 28-byte values that follow
| + | |
− | char Transform[TransformCt][28]; '' set of 7 floats, see below
| + | |
− | long mdNamePairsCt; '' number of len+name pairs that follow
| + | |
− | char mdNameALen; '' length of first name
| + | |
− | char mdNameA[mdNameACt]; '' first name
| + | |
− | char mdNameBLen; '' length of second name
| + | |
− |
| + | |
− | long mdVerticeCt; '' if zero, end, else number of vertices (12
| + | |
− | '' bytes each)
| + | |
− | long mdFaceCt; '' number of faces times 3
| + | |
− | float mdVertices[mdVerticeCt][3]; '' list of all the vertices in the model
| + | |
− | short mdFaces[mdFaceCt]; '' if (version==4)
| + | |
− | long mdFaces[mdFaceCt]; '' if ((version==1)||(version==2))
| + | |
− | }
| + | |
− | </pre>
| + | |
− |
| + | |
− | The Transform count, if present, matches the total number of Subset structures. Each is a set of 7 floats. The first 4 are a quaternion (X,Y,Z,W) and the last 3 are translation values (X,Y,Z). Usage discussed in the Subset section below.
| + | |
− | <pre>
| + | |
− | struct Subset { '' P5 - structured following bone assignments
| + | |
− | long VerticeCt; '' if zero, empty Subset
| + | |
− | long FaceCt; '' number of subset faces times 3
| + | |
− | float Vertices[VerticeCt][3]; '' data block
| + | |
− | short Faces[FaceCt]; '' if (version==4)
| + | |
− | long Faces[FaceCt]; '' if ((version==1)||(version==2))
| + | |
− | }
| + | |
− | </pre>
| + | |
− | This section contains subsets of vertices and faces for the model for animated models. When this section is used, the ModelData section may or may not contain a full or partial set of name pairs, but seems to be empty of Vertices and Faces. It will contain a set of transforms, to relocate each subset to match the main model. To apply the transform, you subtract the X,Y,Z values (last 3 floats) from each vertice, then use the quaternion to build a matrix and apply a rotation to the vertex.
| + | |
− | | + | |
− | I have found that you can build a usable non-animated object GMDC by using Vertices, Normals, UVs, faces and building a composite model. Animated models can be built by adding in Bone assignments and bone weights, adding the appropriate ModelData Transform data (P4), and building a subset model (p5) by bone assignment. All the other parts can be empty, but certain morph data will not be available.
| + | |
− | [[Category:Modding]]
| + | |