iDevGames Forums

Full Version: skeletal animation...the next step
You're currently viewing a stripped down version of our content. View the full version with proper formatting.


ok i tweaked the MeshworkImporter code so it loads bones, and stores a list of vertices attached to each bone. the setup is...

a bone structure
typedef struct
const char *parentBone,*primaryBoneCode,*secondaryBoneCode;
float bone_x,bone_y,bone_z;
float bone_rx,bone_ry,bone_rz;
float def_bone_x,def_bone_y,def_bone_z;
float def_bone_rx,def_bone_ry,def_bone_rz;
int attached_vertices[2000];
int vertex_count;
} bone;

a materials structure (as in MeshworkImporter)
struct {
float color[4];
BOOL smoothed;

int mapping;
int axis;

float center[3];
float extent[3];

unsigned numTriangles;
float *normals;

unsigned short *triangles;
float *texCoords;
} materials[8];

an array for bones
bone *modelBone;

an array vertices, an array for normals (as in MeshworkImporter)
float *vertices;
float *normals;

the attached_vertices array in the bone struct contains the index of each vertex in the vertices array that is connected to the bone.

this is the only way i can think of drawing the model using its bones:
trueBones is the number of bones in the model

glVertex3f(vertices[modelBone[i].attached_vertices[a]*3], vertices[modelBone[i].attached_vertices[a]*3+1], vertices[modelBone[i].attached_vertices[a]*3+2]);

now this would draw all the vertices, as it should, but the result is not as it should be (as should happen). i noticed that MeshworkImporter doesnt make use of the EDGES section of the Meshwork file format (or does it?), so i was thinking that this is probably my problem. my first question would be: does using glVertexPointer() automatically determine edges? if so, can this be applied to skeletal modeling? thanks.
No, vertexpointer does not do edge detection. There is, in general, no way to automatically do meshwork-style soft-skin skeletal animation in GL.

Meshwork specifies bones by vertex, so you'll have to transform all the vertices to their posed location and then draw the triangles. I'm doing this "manually" with GL feedback mode, but you could also do your own matrix math.


after thinking about it for a while, i think i came up with a solution.

i have an array of all the vertices in the model

i have an array of all the edges in the model
each item is the index # of the edge vertex

i have an array of all the bones in the model

now i want to draw the model. if i scan through the edges array, would this work?
for(every other item in edges array [+=2])
1)find bone that edge vertex A is connected to
2)find bone that edge vertex B is connected to
3)save matrix
4)translate to the bone position that vertex A is connected to
5)rotate to the bone orientation that vertex A is connected to
6)draw vertex A
7)restore matrix
8)repeat steps 3-7 for vertex B

it seems like it would, but i wanted to get a 2nd opinion before i start changing things. thanks for your help.
It may or may not work, but it'll be dog-slow Smile

Unfortunately, ARB_matrix_palette doesn't seem to be available on Mac OS X (though ARB_vertex_blend is?!?!), so the easy way's down the drain Sad

In the absence of ARB_matrix_palette, you could write a vertex program, or transform all your vertices on the CPU:

For each bone:
&nbsp;&nbsp;&nbsp;&nbsp;figure out the transform matrix
For each vertex:
&nbsp;&nbsp;&nbsp;&nbsp;multiply by the matrix for bone 1 to get v1
&nbsp;&nbsp;&nbsp;&nbsp;multiply by the matrix for bone 2 to get v2
&nbsp;&nbsp;&nbsp;&nbsp;linearly interpolate v1 & v2 by the bone weights to get the final vertex
Use a vertex array to submit the vertices to the card


i have a working bone model setup made, now i just need to figure out how to properly draw everything. heres what im working with:

typedef struct
const char *parentBoneCode,*primaryBoneCode,*secondaryBoneCode;
int parentBone,primaryBone,secondaryBone;
float bone_x,bone_y,bone_z;
float [b/]bone_rx,bone_ry,bone_rz[/b];
float def_bone_x,def_bone_y,def_bone_z;
float def_bone_rx,def_bone_ry,def_bone_rz;
unsigned short triangles_buf[2000];
int triangle_count;
} model_bone;
parentBone is the index number of the bone's parent (in the mbone_buffer[] array, below)
bone_x... is the bone's x-y-z position
bone_rx... is the bone's x-axis, y-axis, z-axis orientation
triangles_buf[] is the geometry array of the bone
every 3 items is a triangle. every item is a index number of a vertex in the model_vertices or vrtb arrays (below).

@interface Model : NSObject
float *model_vertices;
float *vrtb;

model_bone mbone_buffer[1000];
int model_bone_count;
model_vertices is the default vertex array (coordinates are as they are in the Meshwork model file). every 3 items is a vertex.
vrtb is the vertex relative to bone array. it is the same setup as the model_vertices, except each vertex is converted to its position relative to the (default) position of the bone that the vertex is connected to (vertex_x - bone_x, vertex_y - bone_y, ...).

now my problem is stepping through the bones logically. i basically need to go through each bone, and translate/rotate based on bone position and orientation, and bone parent position and orientation, then draw the geometry for the bone. here is what im trying:

int index,index2;
unsigned short *current_triangle,*current_triangles;

current_triangle = (unsigned short *)malloc(1 * sizeof(unsigned short) * 3);

glVertexPointer(3, GL_FLOAT, 0, vrtb);

//go through bones, and display its geometry
current_triangles = (unsigned short *)malloc(mbone_buffer[index].triangle_count * sizeof(unsigned short) * 3);

//go through each triangle in the bones geometry, and add it to current triangles array (note: im aware that this shouldnt be done for each frame, but this is just a development thing)
current_triangle[0] = mbone_buffer[index].triangles_buf[index2*3+0]; //x
current_triangle[1] = mbone_buffer[index].triangles_buf[index2*3+1]; //y
current_triangle[2] = mbone_buffer[index].triangles_buf[index2*3+2]; //z
current_triangles[index2*3+0] = current_triangle[0];
current_triangles[index2*3+1] = current_triangle[1];
current_triangles[index2*3+2] = current_triangle[2];


//transform to parent bone
//(this will only allow bones to be linked to 1 other
//bone, the rest will be implemented once i figure this out)


//transform to bone

//draw triangles
glDrawElements(GL_TRIANGLES, mbone_buffer[index].triangle_count*3, GL_UNSIGNED_SHORT, current_triangles);



if i don't transform to parent bone, as shown above, then everything is drawn as it should be. if i add a spin to one of the bone's, its triangles spin independently of the other bones geometry. but if i do transform to parent bone, the bone geometry is rotated properly, but its position is off. ive tried translating before rotating, transforming to bone parent after transforming to bone, etc, to no avail. any ideas? thanks.

i tried implementing this using the setup on but i still cant get it quite right. its a step closer but theres still something im not getting.


this is what i think i need:

Quote:Each bone is a 4*4 matrix, a list of it's child bones and a list of polys attached to that bone. Then do this:

Load identity matrix
//the following recurses through all bones
*multiply bone-matrix by modelview matrix
*draw vertices attached to this bone
*visit children and draw them

The coordinates for the vertices are supposed to be relative to the bone-origin. The translation in each bone's 4*4 matrix is then the offset from the parent bone's origin to the current bone's origin.

now, i have everything implemented except for the 4*4 matrix. i was wondering if someone could explain to me how i would set up a 4*4 matrix based on the position and orienation of a bone, and then multiply the bone-matrix by the modelview matrix (glMultMatrixf(bone-matrix) i presume?). im really hoping this is it. thanks.
Reference URL's