Model3 3D Model Format - Palm-Studios/sh2_source GitHub Wiki
The Model3 format (or so it is referred to in the source of SILENT HILL 2) is the model file format used throughout SILENT HILL 2 and 3. The file type is a binary format that contains data such as the skeleton, textures etcetera. Each file has the extension .mdl.
The first block of data is the Model's file header. It is described with the following struct:
IMPORTANT NOTE! The following are revision 3 model structures. Revision 4 (the PC version) may have slightly different data (the Part structure, for example, is different)
struct sh2gfw_Model_Header
{
unsigned char NoTextureID;
unsigned char padc[3];
unsigned int chara_id;
unsigned int texnum;
unsigned int toTexHead_offset;
unsigned int toClutsHead_offset;
unsigned int toModel_offset;
unsigned int toKg1_offset;
unsigned int pad;
void* pTexMAN[8];
};
The offsets in this struct are absolute.
These fields have the following meaning:
| Field | Description |
|---|---|
| NoTextureID | No Texture flag(??) |
| padc[3] | Pad bytes (always 0) |
| chara_id | Character ID number (used in engine to identify a character/SubCharacter). This looks like it could also be a "type" to determine if it's a drama model or not. |
| texnum | Number of textures stored in this .mdl file |
| toTexHead_offset | Offset to first texture (aka text block) |
| toClutsHead_offset | Offset to cluster (animation?) data |
| toModel_offset | Offset to model header |
| toKg1_offset | Offset to embedded KG1 file header |
| pads[2] | Padding words |
| void* pTexMAN[8] | Data for texman(???) |
The next struct contains information about the model data itself:
struct Model
{
unsigned int id;
unsigned int revision;
unsigned int initial_matrices_offset;
unsigned int n_skeletons;
unsigned int skeleton_structure_offset;
unsigned int n_skeleton_pairs;
unsigned int skeleton_pairs_offset;
unsigned int default_pcms_offset;
unsigned int n_vu1_parts;
unsigned int vu1_parts_offset;
unsigned int n_vu0_parts;
unsigned int vu0_parts_offset;
unsigned int n_texture_blocks;
unsigned int texture_blocks_offset;
unsigned int n_text_poses;
unsigned int text_poses_offset;
unsigned int text_pos_params_offset;
unsigned int n_cluster_nodes;
unsigned int cluster_nodes_offset;
unsigned int n_clusters;
unsigned int clusters_offset;
unsigned int n_func_data;
unsigned int func_data_offset;
unsigned int hit_offset;
unsigned int box_offset;
unsigned int flag;
unsigned int relative_matrices_offset;
unsigned int relative_transes_offset;
unsigned int reserved_1c;
unsigned int reserved_1d;
unsigned int reserved_1e;
unsigned int reserved_1f;
};
The offsets are relative to the beginning of this structure.
These fields have the following meaning:
| Field | Description |
|---|---|
| id | Magic Number. Always 0xFFFF0003 |
| revision | Version number of this .mdl. 3 on PS2, 4 on PC |
| initial_matrices_offset | Offset to the initi |
| n_skeletons | Number of skeletons contained in this file. It is probably more appropriate to call this the number of bones. |
| skeleton_structure_offset | Offset to the root shSkeleton structure |
| n_skeleton_pairs | Number of skeletons pairs (???) |
| skeleton_pairs_offset | Offset to the skeleton pairs |
| default_pcms_offset | ? |
| n_vu1_parts | Number of VU1 parts (sent to the VU1 on the PS2) |
| vu1_parts_offset | Offset to beginning of VU1 part structures (see below) |
| n_vu0_parts | Number of VU1 parts (sent to the VU1 on the PS2) |
| vu0_parts_offset | Offset to beginning of VU1 part structures (see below) |
| n_texture_blocks | Number of textures contained within this .mdl |
| texture_blocks_offset | Offset to texture data |
| n_text_poses | Pose data (???) |
| text_poses_offset | Offset to pose data (???) |
| text_pos_params_offset | |
| n_cluster_nodes | |
| cluster_nodes_offset | |
| n_clusters | |
| clusters_offset | |
| n_func_data | |
| func_data_offset | |
| hit_offset | Offset to hitbox (combat hitbox?) |
| box_offset | Offset to hitbox (movement hitbox?) |
| flag | No idea. Some kind of information related to model in game? |
| relative_matrices_offset | |
| relative_transes_offset; | |
| reserved_1c; | Reserved for future use |
| reserved_1d; | Reserved for future use |
| reserved_1e; | Reserved for future use |
The next structure of interest is a Part header. This describes a packet of data that, on the PlayStation 2, would be sent to the VU0. The format of the actual data itself (which I assume is vertex data) is currently unknown as of now.
The structure is as follows:
struct Part
{
unsigned int size;
unsigned int type;
unsigned int packet_offset;
unsigned int packet_qwc;
unsigned int xtop;
unsigned int n_cluster_data;
unsigned int cluster_data_offset;
unsigned int n_skeletons;
unsigned int skeletons_offset;
unsigned int n_skeleton_pairs;
unsigned int skeleton_pairs_offset;
unsigned int data_skeletons_offset;
unsigned int data_skeleton_pairs_offset;
unsigned int n_textures;
unsigned int text_pos_indices_offset;
unsigned int texture_params_offset;
unsigned char shading_type;
unsigned char specular_pos;
unsigned char equipment_id;
unsigned char hoge;
unsigned char backclip;
unsigned char envmap_param;
unsigned char reserved[2];
float phong_param_a;
float phong_param_b;
float blinn_param;
unsigned int padding[3];
float diffuse[4];
float ambient[4];
float specular[4];
};
| Field | Description |
|---|---|
| size | Size of the this packet, including header. |
| type | |
| packet_offset | |
| packet_qwc | |
| xtop | |
| n_cluster_data | |
| cluster_data_offset | |
| n_skeletons | |
| skeletons_offset | |
| n_skeleton_pairs | |
| skeleton_pairs_offset | |
| data_skeletons_offset | |
| data_skeleton_pairs_offset | |
| n_textures | |
| text_pos_indices_offset | |
| texture_params_offset | |
| shading_type | |
| specular_pos | |
| equipment_id | |
| hoge | |
| backclip | |
| envmap_param | |
| reserved[2] | |
| phong_param_a | |
| phong_param_b | |
| blinn_param | |
| padding[3] | |
| diffuse[4] | |
| ambient[4] | |
| specular[4] |