Intro

Working with the Decompilation Project I worked on a plugin for blender to view 3D models from the game Chameleon Twist.

Chameleon Twist uses the F3Dex N64 graphics format which is a modified version of the F3D format used in Super Mario 64. The plugin is able to read the display lists and render the models in blender.

The plugin is currently in a working state but is not yet ready for release. The plugin is being worked on by me and another member of the team.

How it Works

The N64 draws models to the screen using graphics macros in gfx. The macros call information stored in RAM for a given model. To generate the models in Blender we will try to emulate the N64 RDP (gpu) and feed it the same data per model.

I wrote some sections for Decompilation Project to extract gfx, vtx, mtx and in some instances lights data for each model in the game into include c files. These files are read and interpreted by the plugin to generate the models.

Here is a description of each type:

Graphics files contain high level macros that tell the RDP (gpu) of the N64 what to do. For example, this is the lilypad shown at the header of this page (ignoring texture stuff for now):

gsSPMatrix(&JungleLand_Identity, G_MTX_PUSH | G_MTX_MUL |G_MTX_MODELVIEW),
gsDPPipeSync(),
gsDPSetCycleType(G_CYC_1CYCLE),
gsDPSetRenderMode(G_RM_AA_ZB_OPA_SURF, G_RM_AA_ZB_OPA_SURF2),
gsSPClearGeometryMode(G_SHADE | G_CULL_BOTH | G_FOG | G_LIGHTING |G_TEXTURE_GEN | G_TEXTURE_GEN_LINEAR | G_SHADING_SMOOTH),
gsSPSetGeometryMode(G_ZBUFFER | G_CULL_BACK),
gsSPVertex(&D_03013628_JungleLand[0], 8, 0),
gsSP1Triangle(0, 5, 6, 0),
gsSP1Triangle(1, 0, 6, 0),
gsSP1Triangle(2, 1, 6, 0),
gsSP1Triangle(3, 2, 6, 0),
gsSP1Triangle(4, 3, 6, 0),
gsSP1Triangle(7, 6, 5, 0),
gsSPPopMatrix(G_MTX_MODELVIEW),
gsSPEndDisplayList(),

Matrix data is stored as a Mtx[4][4], though the N64 models use 3 dimensions - matrices used in the N64 have dimension 4; they are affine matrices which means they can be rotated, scaled and translated and used for 3d data.

Vertex data for models is stored as a Vtx[], the struct layout is as follows:

typedef struct {
    short int pos[3]; //Vertex Position
    short flag;
    short tc[2]; //Texture Coordinates
    unsigned char col[4]; //RGBA
} Vtx;

Lights data is stored as a LightsM[], where M is the number of lights in the model. M = 0 is an ambient light, and any other number is another directional light. The structs are built into eachother so LightsK is a Lights(K-1) with an extra directional light. Directional lights have a colour and a vector that points towards the camera.

For example, every model in the level JungleLand uses:

Lights1 jlScope = gdSPDefLights1(
    /* ambient color */
    13, 13, 13,
    /* colored light direction */
    255, 255, 255,	69, 69, 69
);

The Blender Script

The blender script is written in python. It interprets the graphics.inc.c file in order to emulate the RDP in response to the given macros. So that the correct data is given when a macro requests a specific instance of a data type mentioned above - I wrote some code to hook into the Decompilation Project’s files and replace the variable names in the graphics.inc.c file with the names of our local files.

As an example of how the script emulates the RDP, we can look at the gsSPVertex and gsSP1Triangle macros. The gsSPVertex macro tells the RDP to load a vertex array into the RDP’s memory. The gsSP1Triangle macro tells the RDP to draw a triangle using the vertices in the vertex array. The blender script loads the vertex position vector’s into a list. The triangles macro then tells blender which vertices to use to draw a face.