I've read that the xyz vectors provided in the tag structure are actually quaternions. Since I don't know much about what they are or how to use them, I've read up on a bit of it here: http://www.cprogramming.com/tutorial/3d/quaternions.html
My understanding from reading this is that I would create a quaternion with x=0, y=0, z=0, w=1, then multiply this by the x-rotation quaternion provided it the md3. Then multiply the result by the y-rotation, then finally the z-rotation. The final quaternion could be converted to a 4x4 matrix, and the transformation could be placed in the last row.
Here is some of the code for it:
struct quat_t { float x, y, z; float w;};void quat_init(struct quat_t* q) { struct quat_t i = { 0, 0, 0, 1 }; *q = i;}void quat_normalize(struct quat_t* q) { float r = ((q->x * q->x) + (q->y * q->y) + (q->z * q->z) + (q->w * q->w)); if ((1.0f - r) <= 0.0000001) /* already nomalized */ return; r = sqrt(r); q->x /= r; q->y /= r; q->z /= r; q->w /= r;}void quat_mult(struct quat_t* a, struct quat_t* b, struct quat_t* c) { struct quat_t r; r.x = ((a->w * b->x) + (a->x * b->w) + (a->y * b->z) - (a->z * b->y)); r.y = ((a->w * b->y) - (a->z * b->z) + (a->y * b->w) + (a->z * b->x)); r.z = ((a->w * b->z) + (a->x * b->y) - (a->y * b->x) + (a->z * b->w)); r.w = ((a->w * b->w) - (a->x * b->x) - (a->y * b->y) - (a->z * b->z)); *c = r;}void quat_rotate(struct quat_t* q, float ang, float x, float y, float z) { float ha = sinf(ang / 2); q->x = x * ha; q->y = y * ha; q->z = z * ha; q->w = cosf(ang / 2);}void quat_matrix_4x4(struct quat_t* q, struct vec3_t* origin, float* m) { m[0] = 1 - 2*(q->y)*(q->y) - 2*(q->z)*(q->z); m[1] = 2*(q->x)*(q->y) + 2*(q->w)*(q->z); m[2] = 2*(q->x)*(q->z) - 2*(q->w)*(q->y); m[3] = 0; m[4] = 2*(q->x)*(q->y) - 2*(q->w)*(q->z); m[5] = 1 - 2*(q->x)*(q->x) - 2*(q->z)*(q->z); m[6] = 2*(q->y)*(q->z) - 2*(q->w)*(q->z); m[7] = 0; m[8] = 2*(q->x)*(q->z) + 2*(q->w)*(q->y); m[9] = 2*(q->y)*(q->z) - 2*(q->w)*(q->z); m[10] = 1 - 2*(q->x)*(q->x) - 2*(q->y)*(q->y); m[11] = 0; m[12] = origin->x; m[13] = origin->y; m[14] = origin->z; m[15] = 1;}
And the tag structure:
struct md3_tag_t { struct md3_tag_t* next; /* next tag in the list */ char name[MAX_QPATH]; /* name of tag object */ struct vec3_t origin; /* coordinates */ struct vec3_t axis[3]; /* orientation */};
Here is the code for rendering the models head:
/* render head */ glPushMatrix(); tag = model_head->tag_ptr; struct quat_t local; struct quat_t total; quat_init(&total); float angle = 90; quat_rotate(&local, angle, tag->axis[0].x, tag->axis[0].y, tag->axis[0].z); quat_mult(&local, &local, &total); quat_rotate(&local, angle, tag->axis[1].x, tag->axis[1].y, tag->axis[1].z); quat_mult(&total, &local, &total); quat_rotate(&local, angle, tag->axis[2].x, tag->axis[2].y, tag->axis[2].z); quat_mult(&total, &local, &total); quat_normalize(&total); quat_matrix_4x4(&total, &tag->origin, trans_matrix); glMultMatrixf(trans_matrix); md3_render(model_head); glPopMatrix();
The same code is used for the model body.
I have a few questions about this though, since it doesn't seem to work.
The model is squished togther so I must be doing some math wrong - am I missing a step or am I just completely wrong with how I'm doing this?
Also these calculations require an angle or rotation which I don't have (I simply set it to 90 degrees for testing). Where does this angle come from? It's not in the model frame information. At this point I'm not concerned with rendering more than one frame (animation will come later), so this angle is a bit confusing.
Thanks.