Animating 3D Polygon Meshes

CS 481 Lecture, Dr. Lawlor

The basic ideas are:
It's actually really a simple idea.  But implementing it isn't as easy.

This has changed dramatically in Blender 2.6, so the documentation is really nearly useless.  What finally worked for me was:
  1. Create a meshed polygon object (see last lecture).
  2. Create an "Armature" containing "Bones" for each part of the mesh you want to move.  Start by Add -> Armature -> Single Bone, and then enter edit mode and hit shift-A to make new bones in that armature.  Line up the bones with the major parts of the mesh, and add names for the bones.
  3. Select the mesh in Object mode, and add an Armature modifier to the mesh.  Set the "Object" to the armature you just created.  Bind to Vertex Groups, not Envelope.   DON'T HIT APPLY!  This will bake the bone deformations into the mesh--you want to leave the armature modifier active to be able to move the bones around and have the mesh follow it.
  4. Enter Weight Paint mode, and paint the parts of the mesh you want to move with each bone.  This is the proportion of each bone to use to transform each vertex, and so it ranges from zero (bone does not affect vertex) to one (bone totally defines location of vertex).  Feather the edges, so the mesh deforms smoothly.  Name the vertex groups (paint colors) the same as each of your bones--Blender matches bones to vertex groups using the names.  (It would probably be better to use the 'bone envelopes' to initially create the vertex weights, and then tweak them as needed, but I haven't figured out how to do this yet.)
  5. Finally, to move the parts of the meshed object, select the armature, enter 'Pose Mode', and move the bone around.  The mesh should move with the bones!  You can still go back and tweak the bone weights.
You can export bone weights via Collada format (they come out as a big "weights" array), and in theory you can then animate the bones and then apply their transformations to the mesh in C++.  This gets fairly complex, however.

Vertex Buffer Object

Vertex Buffer Objects (VBOs) are a way to store geometry information on the graphics card, just like Textures let you store raster information on the graphics card.  VBOs are described in the ARB_vertex_buffer_object extension.

A VBO describes a series of glVertex (and optionally glColor, glNormal, and glTexCoord) calls.  The parameters for the calls start in a CPU array, and get copied into graphics card memory.  Depending on the CPU load and OS, VBOs can be a 10x speedup, or no faster than a bunch of bare glVertex calls--you've just got to try 'em to be sure!

You create a Vertex Buffer Object with (guess what!) glGenBuffersARB.  You then have to glBindBufferARB the buffer, and then you can then copy data in with glBufferDataARB.    You describe what your data contains using calls to glVertexPointer (and optionally glColorPointer, glNormalPointer, and glTexCoordPointer), which each take the same four parameters:
Here's how you'd create a vertex buffer object to store vertex locations and colors, then render it:
	static GLuint vb=0; 
if (vb==0) { /* set up the vertex buffer object */
glGenBuffersARB(1,&vb); /* make a buffer */
glBindBufferARB(GL_ARRAY_BUFFER_ARB,vb);
/* Copy our vtx array (on the CPU) into our new GPU buffer */
glBufferDataARB(GL_ARRAY_BUFFER_ARB,sizeof(myVertex)*vtx.size(),
&vtx[0],GL_STATIC_DRAW_ARB);

/* Tell OpenGL how our array is laid out */
glEnableClientState(GL_VERTEX_ARRAY);
  glVertexPointer(3,GL_FLOAT,sizeof(vtx[0]), (void *)0); /* myVertex.xyz is first thing in struct */
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer (3,GL_FLOAT,sizeof(vtx[0]), (void *)12); /* myVertex.color starts 12 bytes after struct start */
glBindBufferARB(GL_ARRAY_BUFFER_ARB,0); /* back to plain OpenGL */
}
/* Draw all our (GPU) points.
This is way faster than looping over vtx and calling glVertex many times! */
glBindBufferARB(GL_ARRAY_BUFFER_ARB,vb);
glDrawArrays(GL_POINTS,0,vtx.size());
glBindBufferARB(GL_ARRAY_BUFFER_ARB,0);
You can also create an "element buffer" to store vertex indices.  For example, to make a triangle from vertices zero, seven, and thirteen, you'd put {0,7,13} into an element buffer.  Element buffers allow many triangles to point to the same vertex, which saves that vertex many trips through your vertex shader.  You upload the index data with glBufferDataARB (just like vertex buffer objects), and then use glDrawElements to look up your indices into your (already bound) vertex array:
	static GLuint eb=0; 
if (eb==0) { /* set up the element buffer object */
glGenBuffersARB(1,&eb); /* make a buffer */
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB,vb);
/* Copy our idx array (on the CPU) into our new GPU buffer */
glBufferDataARB(GL_ARRAY_BUFFER_ARB,sizeof(int)*idx.size(),
&idx[0],GL_STATIC_DRAW_ARB);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB,0); /* back to plain OpenGL */
}
glBindBufferARB(GL_ARRAY_BUFFER_ARB,vb); /* vertex data */
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB,eb); /* index data */
glDrawElements(GL_TRIANGLES,idx.size(),GL_UNSIGNED_INT,0);
glBindBufferARB(GL_ARRAY_BUFFER_ARB,0);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB,0);
The advantage of vertex buffer objects is they're a little bit faster than plain glBegin/glVertex calls.  The disadvantage is all this code!