• Advertisement
Sign in to follow this  

Need help with my skeletal animation system

This topic is 2440 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I've been working on this skeletal animation thingy for fun, and am having some problems.

The first is when rotating a child bone, it "spins" in the correct direction as its parent, but it "orbits" in the opposite.

The other is when calculating the absolute coordinates of child bones, they're being transformed by its parents pose coordinates.

For example, if a root bone's pose coordinates is at (0, 0, -1) with no local transformation, the absolute coordinates will be at (0, 0, -1). That's correct. If its child bone is at pose (0, 0, 0) with no local transformation, it's absolute will be at (0, 0, -1), when it should be at (0, 0, 0). It's the same with rotations as well. It doesn't seem to affect the vertex transformation, but rendering the bone structure will be useless.

EDIT: Forgot to ask: How are weights calculated? I have the weights in the data file and class structure, they're just not implemented.

Class Declarations

class bone {
//unimportant modifiers, accessors, and constructors
//This should be a nested class instead of just friend'ing actor
friend actor;
//Locally transform a bone
void transform(const vector3<double>& pos, const quaternion<double>& rot);
//Recurse into each child and deform it depending on this bones deformation
void child_transform();
//Keep a copy of the bone's pose translation/rotation and local/global translation/rotation
const vector3<double> _b_orig_pos;
vector3<double> _b_loc_pos, _b_abs_pos;
const quaternion<double> _b_orig_rot;
quaternion<double> _b_loc_rot, _b_abs_rot;
//Map each vertex with a weight
//Ignoring the weights for now
std::map<const vector3<double>*, double > _verts;
//Keep track of each vertex's copy for bone deformation
std::map<const vector3<double>*, vector3<double>* > _b_verts;
bone* _parent;
std::vector<bone*> _children;

class actor {
//unimportant modifiers, accessors, and constructors
void anim_render();
void transform_abs_coords();
std::string _name;
//Original vertex locations for rendering the skin in pose
std::vector<const vector3<double>* > _verts;
//Don't directly modify the original verticies, instead create a copy and map them. This is used for animations
std::map<const vector3<double>*, vector3<double>* > _b_verts;
//Keep a list of faces for rendering
std::vector<face<const vector3<double>* >* > _faces;
//Bones that have parents and bones that do not (root bones)
std::vector<bone*> _bones;
std::vector<bone*> _root_bones;

Main function

actor act("Cube.skan");
int main(int argc, char** argv) {

while(getInput()) {

return 0;

Member functions

void bone::transform(const vector3<double>& pos, const quaternion<double>& rot) {
_b_loc_pos += pos;
_b_loc_rot *= rot;

void actor::transform_abs_coords() {
//Loop through the root bones, set their absolute deformation, and deform its children
for(auto i = _root_bones.begin(); i != _root_bones.end(); i++) {
bone& b = (**i);
b._b_abs_pos = b._b_loc_pos + b._b_orig_pos;
b._b_abs_rot = b._b_loc_rot * b._b_orig_rot;
for(auto j = b._children.begin(); j != b._children.end(); j++) {

void bone::child_transform() {
_b_abs_pos = _b_loc_pos;
_b_abs_pos *= _parent->_b_abs_rot;
_b_abs_pos += _parent->_b_abs_pos;

_b_abs_rot = _b_loc_rot * _parent->_b_abs_rot;
for(auto i = _children.begin(); i != _children.end(); i++) {

void actor::anim_render() {
//Reset all the vertex locations
for(auto i = _verts.begin(); i != _verts.end(); i++) {
*_b_verts[*i] = **i;
//Loop through the bones and deform its attached verticies
for(auto i = _bones.begin(); i != _bones.end(); i++) {
for(auto j = (**i)._verts.begin(); j != (**i)._verts.end(); j++) {
const vector3<double>& vert = *j->first;
const bone& b = **i;
vector3<double>& b_vert = *(**i)._b_verts[&vert];
const quaternion<double>& bone_rot = b._b_abs_rot;

quaternion<double> result = bone_rot * quaternion<double>(0, vert.x(), vert.y(), vert.z()) * bone_rot.conjugate();
b_vert += vector3<double>(result.x(), result.y(), result.z()) + b._b_abs_pos - b_vert;
//Render to the screen
for(auto i = _faces.begin(); i != _faces.end(); i++) {
const face<const vector3<double>* >& f = **i;
glNormal3d(f.nX(), f.nY(), f.nZ());
for(unsigned int j = 0; j < (**i).size(); j++) {
const vector3<double>& v = *_b_verts[f[j]];
glVertex3d(v.x(), v.y(), v.z());

Quaternions & Vectors

template <typename T> void vector3<T>::operator *= (const quaternion<T>& quat) {
quaternion<T> temp = quat.conjugate();
temp *= *this;
temp *= quat;
_x = temp.x();
_y = temp.y();
_z = temp.z();

template <typename T> void vector3<T>::operator += (const vector3<T>& v) {
_x += v._x;
_y += v._y;
_z += v._z;

template <typename T> vector3<T> vector3<T>::operator + (const vector3<T>& v) const {
return vector3<T>(_x+v._x,_y+v._y,_z+v._z);

template <typename T> vector3<T> vector3<T>::operator - (const vector3<T>& v) const {
return vector3<T>(_x-v._x,_y-v._y,_z-v._z);

//I should just restrict the typenames in quaternions to float/double. Why would you use anything else?
template<typename T> void quaternion<T>::operator *= (const vector3<T>& vert) {
quaternion<T> q = *this;
_x = q._w * vert.x() + q._y * vert.z() - q._z * vert.y();
_y = q._w * vert.y() - q._x * vert.z() + q._z * vert.x();
_z = q._w * vert.z() + q._x * vert.y() - q._y * vert.x();
_w =-q._x * vert.x() - q._y * vert.y() - q._z * vert.z();

template<typename T> quaternion<T> quaternion<T>::operator * (const quaternion<T>& i) const {
return quaternion<T>(
_w*i._w - _x*i._x - _y*i._y - _z*i._z,
_w*i._x + _x*i._w + _y*i._z - _z*i._y,
_w*i._y + _y*i._w + _z*i._x - _x*i._z,
_w*i._z + _z*i._w + _x*i._y - _y*i._x);
template<typename T> quaternion<T> quaternion<T>::conjugate() const {
return quaternion<T>(_w, -_x, -_y, -_z);

Share this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement