Mod:Model Files

The UESPWiki – Your source for The Elder Scrolls since 1995

This article documents the formats of 3D and 3DC files used in Redguard that contain 3D model data. Note that most of the format is experimental and may be incorrect. Particularly, the naming of sections is assumed and may be incorrect.

3D File Format[edit]

Overall Format[edit]

The overall format of a 3D file is:

    Header (64 bytes)
    FrameData (variable sized)
    FaceData (variable sized)
    VertexCoordinates (variable sized)
    FaceNormals (variable sized)
    UVOffsets (variable sized)
    UVCoordinates (variable sized)

All data is in Little Endian Byte Order unless specified.

Header Format[edit]

The header of a 3D/3DC file is a fixed size 64 byte section at the start of the file:

    byte Version[4]                // Unterminated string like 'v2.6', 'v2.7', 'v4.0', 'v5.0'
    dword NumVertices
    dword NumFaces
    dword Radius
    dword NumFrames
    dword OffsetFrameData
    dword NumUVOffsets
    dword OffsetSection4
    dword Section4Count
    dword Unknown4		    // Always 0?
    dword OffsetUVOffsets
    dword OffsetUVData
    dword OffsetVertexCoors
    dword OffsetFaceNormals
    dword NumUVOffsets2
    dword OffsetFaceData

All offsets are relative to the start of the file and data sections may be in any order (typically related to file version).

Version Differences[edit]

If the header version field is 'v2.7' or earlier the following changes to the header data have to be made:

  • NumUVOffsets — This is the offset to the UV Data which is just all 0s.
  • OffsetUVData — This is an offset to an unknown section of data.

Frame Data Format[edit]

The frame data section starts from the OffsetFrameData position in the file and has the following format:

    dword u1
    dword u2
    dword u3
    dword u4
    byte u5[]    // Variable sized, unknown format, may be 0 sized?

It is assumed to be animation data which in 3D files is always (?) omitted. 3DC files typically have large frame data sections.

Face Data Format[edit]

The face data section starts from the OffsetFaceData position in the header.

Note: faces in Redguard are typically not triangles.

FaceData struct[edit]

Name DataType Description
VertexCount u8 Number of vertices (FaceVertex structs) contained in this record
Unk_01 u8 Assumed to be flags, may also be alpha related - Values range from 0-63 (6 bits) - ~77% are 0
TextureData u16/u32 Contains the texture file identifier and image number or solid color index - This is a u16 value in v2.6/2.7 files and a u32 in v4.0/5.0
Unk_04 u32 Always blank (00000000)
FaceVertex struct[VertexCount] UV map data
VertexIndex
u32 Index for the target vertex - This is multiplied by 12 in v2.6/2.7 so this must be divided by 12 to get correct index for those versions
U
s16 U axis
V
s16 V axis

Texture Data[edit]

The TextureData can either contain a color index where a solid color is used or the ID for the texture file and subimage index. This psuedo-code illustrates how to parse this:

v2.6 & 2.7 (3DART)[edit]

   u16 TextureID = (TextureData >> 7);	// File extension of the BSI file located in 3DART (i.e. TEXTURE.123)
   // Check if solid color - Note:  TEXTURE.000/001 are not used
   if (TextureID < 2) {
   	u8 ColorIndex = TextureData;
   	return ColorIndex;
   }
   else {
   	u8 ImageID = TextureData & 0x7F;
   	return (TexureID, ImageID);
   }

v4.0 & 5.0 (FXART)[edit]

   // Check if solid color
   if ((TextureData >> 20) = 0x0FFF) {
   	u8 ColorIndex = TextureData >> 8;
   	return ColorIndex;
   }
   else {
   // Parse TextureID
   	u32 TempVal = (TextureData >> 8) - 4000000;
   	u32 One = (TempVal / 250) % 40;
   	u32 Ten = ((TempVal - (One * 250)) / 1000) % 100;
   	u32 Hundred = (TempVal - (One * 250) - (Ten * 1000)) / 4000;
   	u16 TextureID = One + Ten + Hundred;	// File extension of the BSI file located in FXART (i.e. TEXBSI.321)
   
   // Parse ImageID
   	One = (TextureData & 0xFF) % 10;
   	Ten = ((TextureData & 0xFF) / 40) * 10;
   	u8 ImageID = One + Ten;
   
   	return (TextureID, ImageID);
   }

Vertex Coordinate Format[edit]

The UV coordinate data section starts from the OffsetVertexData position in most files. In 3DC files of version 2.7 and earlier the start offset is given by:

    Offset = EndFaceDataOffset + FrameDataHeader.u3;

It has the following format:

    struct vertex_t {
          dword x
          dword y
          dword z
    } vertexdata[NumVertices]

Face Normal Format[edit]

The UV coordinate data section starts from the OffsetFaceNormals position in the file and has the following format:

    struct facenormal_t {
          dword x
          dword y
          dword z
    } facenormaldata[NumFaces]

UV Offset Format[edit]

The UV coordinate data section starts from the OffsetUVOffsets position in the file and has the following format:

    dword uvoffsetdata[NumUVOFfsets]

UV Coordinates[edit]

The UV coordinate data section starts from the OffsetUVData position in the file and has the following format:

   struct uvcoor_t {
         float x
         float y
         float z
   } uvdata[NumUVCoordinates]

Note that the UV coordinates don't appear to be plain UV coordinates as we would expect for a 3D model. Most values look fine, but a few don't seem to be the correct ones (for example, look at the XWANTED.3D file, which should be a simple rectangle, but the UV coordinates don't match that shape). This applies whether using the UV data in this structure or within the face data.

3DC File Format[edit]

3DC files have the same format as 3D files except for the following differences:

  • The frame data section in 3DC typically has much more data. Assuming this is animation data, this can be explained by 3D files containing static models and 3DC containing animated models.
  • In v2.7 3DC files, the start of the vertex coordinate data is different than what the header data says it should be.

See Also[edit]