Jump to content

Soul Calibur 1 - Arcade and Dreamcast models


spaztron64

Recommended Posts

Early last year I worked with mariokart64n with the goal of converting Soul Calibur 1's Arcade models into a usable format in other software. I spent many months reverse engineering the arcade game and documenting my observations, which MK used to write his script in only a few days. We've been largely successful in getting geometry, UVs, and bone transforms to import into Max for both characters and weapons:


image.thumb.png.9c345e2a39fc85f713c3e03537eea12a.png


For a long time I thought that the Dreamcast model format, seeing how much higher quality the port's modeling work is, is completely different, and ditto for the custom LZSS compression scheme. Turns out I was completely wrong. The compression scheme is completely unchanged from Arcade, and much of the overall *structure* of the model format has been carried over from Arcade. Of course, some obvious changes like the switch from unsigned shorts to floats for vertices and normals were made, but also the face/triangle format.

The latter requires some further explanation. See, Namco elected to embed PSX GPU GP0 commands directly into the command list, not too dissimilar to Sony's standard TMD format, with the major difference being that references to vertices in the transformation buffer are done through bitpacked indices: Three 10-bit indices for triangles (largely used by characters), four 8-bit indices for triangle pairs (largely used by weapons), both of which fit into a single 32-bit word, with the caveat of each being limited to 1024 and 256 vertices respectively. These limits are breached in the DC port, and naturally GP0 commands are not compatible with the PVR, so this part of the format has received the most drastic changes. VincentNL has also confirmed that the game uses the low-level Kamui API for interfacing with the PVR.

Unfortunately, I am not familiar with the intricacies of Dreamcast rendering whatsoever, so I'd appreciate any help in refactoring the script to be DC compatible. Right now bone transforms will import, although it seems they're a bit screwed in the data itself:image.thumb.png.94531346875f551923fe7bbb5fda0fa3.png

Attached below are the script, and samples of Xianghua's 1P model from Arcade and Dreamcast respectively.

sc1_mxs.zip

Link to comment
Share on other sites

Some initial observations I made while examining the command packets during a MAME debugging session:

image.thumb.png.74e845218b10503263bb3733201a70dd.png

image.thumb.png.a79357b80dc86a3f5e1e5f40264c17a6.png

 

 

Red - Vertex counter (how many double words follow)
Orange - Vtx1 Color
Blue - Vtx1 Index
Unmarked word - Unknown, potentially UVs??
Violet - Vtx2 Color
Scarlet - Vtx2 Index
and the cycle repeats until the next Vertex Counter is hit

There doesn't appear to be any more bitpacking of vertex indices.

Link to comment
Share on other sites

Well, even after referencing the original Arcade documentation and combining it with the new DC discoveries, I'm still at a dead end:
image.thumb.png.9e5af92bc2d03cbdf0b60bc5e82b0d11.png

If I'm doing something wrong, I can't tell what that is. Here's the docs:

Main header:

char[23]            filename; // 24 character filename that doesn't really contain anything useful
uint32_t            triangle_strip_table_pointer; // points to the first triangle_strip_t;
uint8_t             unk1;
uint8_t             unk2;
uint8_t             unk3;
uint8_t             submesh_count; // How many model_submesh_t instances exist;
model_submesh_t[n]  model_submesh_table; // One or more submesh headers. Usually no more than 17

typedef struct{
    uint8_t     bone_id0; // NULL on weapons?
    uint8_t     bone_id1;
    uint32_t    vertex_list_pointer; // points to a vertex_list_t
    uint32_t    unknown; // Always 0x00000000?
    uint16_t    vertex_count;
    uint16_t    normal_count;
    int16_t     bone_rotation_x;
    int16_t     bone_rotation_y;
    int16_t     bone_rotation_z;
    int16_t     unknown;
    int16_t     bone_position_x;
    int16_t     bone_position_y;
    int16_t     bone_position_z;
    int16_t     parent_bone_id;
} model_submesh_t;

typedef struct{
    float       vertex_x;
    float       vertex_y;
    float       vertex_z;
    uint16_t    vertex_index;
    uint16_t    flags: // It's not clear what these do
} vertex_list_t;

typedef struct{
    float       normal_x;
    float       normal_y;
    float       normal_z;
    uint16_t    normal_index;
    uint16_t    flags: // It's not clear what these do
} normal_list_t;

typedef struct{
    uint16_t    vertex_index;   // Reference to a vertex index fetched from a vertex_list_t;
    uint16_t    vertex_color;   // Influences shading
    uint32_t    uv_coordinates; // UVs  
    
} triangle_t;

typedef struct{
    uint16_t                    strip_length;
    uint8_t                     uv_coordinate;  // Why are there three UV coordinates?
    uint8_t                     unknown;
    triangle_t[strip_length-1]  triangles;  // Array of triangle_t elements;
} triangle_strip_t;

The current import script is attached below.

soul_calibur_1_importer.py

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...