Start with the snake laid out in a straight line along say, the Z axis (it can be any axis you want). We'll call this pose the 'bind pose'. Compute the world space matrix for each joint, and then invert those matrices. You'll be wanting to store them in an array for later!
Now. Given a vertex V, figure out which are the two closest joints (which since your snake is laid out along the Z axis, you should be able to figure out easily using the 'z' values)
You now need to figure out how far (in the Z axis) the vertex is from each joint, and the distance between the joints:
DistanceBone1 = getDistFromBone1( Vertex );
DistanceBone2 = getDistFromBone2( Vertex );
DistanceBetweenBones == DistanceBone1 + DistanceBone2
From that we can compute some weights....
Weight1 = DistanceBone1 / DistanceBetweenBones
Weight2 = DistanceBone2 / DistanceBetweenBones
You'll probably want to store that information in a structure for later, e.g.
struct Vertex
{
uint32_t boneIndex1;
float weight1;
uint32_t boneIndex2;
float weight2;
Vec3 vertex;
};
And add to your 'bind pose' data you computed earlier:
Matrix InverseBindPose[ NUM_BONES ]
And you'll also need the current world space matrices of each bone:
Matrix currentWorldSpace[NUM_BONES ]
To compute the new position of the vertex V, we first transform into local space of the two bones:
VertexInLocalSpaceOfBone1 = V.vertex * InverseBindPose[ V.boneIndex1 ];
VertexInLocalSpaceOfBone2 = V.vertex * InverseBindPose[ V.boneIndex2 ];
Now they are in local space, we can transform them them into world space using the current pose:
VertexTransformedByBone1 = VertexInLocalSpaceOfBone1 * currentWorldSpace[ V.boneIndex1 ];
VertexTransformedByBone2 = VertexInLocalSpaceOfBone2 * currentWorldSpace[ V.boneIndex2 ];
And finally, interpolate to get the result:
FinalVertexPosition = VertexTransformedByBone1 * V.weight1 + VertexTransformedByBone2 * V.weight2;
Do that for each vertex, and you've skinned your snake....
As an optimisation, before computing the vertices, you can pre-multiply the two matrix arrays together into a single Transform:
for( i = 0; i < numBones; ++i)
SkinTransform = InverseBindPose * currentWorldSpace;
Which now means you only need to transform the vertex by one matrix instead of two:
VertexTransformedByBone1 = V.vertex * SkinTransform[ V.boneIndex1 ];
VertexTransformedByBone2 = V.vertex * SkinTransform[ V.boneIndex2 ];
There are slightly more general ways of doing this (google 'skinning'), and you'll probably find it's much more efficient in a shader (although the CPU will initially be ok for your purposes). If you attach a Skin or Physique modifier to your mesh in 3ds max, then you should be able to edit the skin weights in max directly (if you don't want to compute them manually). To export them, either use Fbx/Collada, or write your own exporter in either max script of the SDK. Hope that helps!