Another small update.
Maybe it is all only working in my mind, or maybe I'm just a single step away from having a working solution.
Sorry if I get into technical details, but the problem I'm stuck on is pretty technical.
The concept a BVH file relies on is:
- a hierarchy of joints whose distances are stored as relative XYZ offsets
- each joint starts as "non rotated"
- each frame rotates each joint by a certain roll, pitch and yaw angles
Now to get this into anim8or I could either:
- go with the best, longer way of converting each joint to a bone and recompute all the motion angles, frame by frame;
- go with the work-it-around, shorter way of recreating non-rotated joints with zero-length rotating bones, interleaving them with fixed bones to represent offsets, and direct-stream copy the RPY angles from BVH motion into AN8 sequence;
I took the workaround way, and as I said above, I miss one single step to close the process.
The thing I miss is converting joint offsets to quaternion orientation, in order to set it into the figure section, inside of the an8 project. Or better, I have a chunk of code for that, but the quaternions I'm getting seem to be wrong, when I feed them to anim8or.
To have an example of the final result, take a look to the bvh and an8 files attached, they show the same skeleton and the same animation in both programs (bvhacker and anim8or), but the orientation of the anim8or bones is the result of manual editing - hence the name, "desired result.an8".
This is the code I'm using to convert XYZ offsets to RPY angles, which get then converted to a quaternion. Anyone has enough trig and quat knowledge to tell me what's going wrong with it?
/*
Radians(x, y) returns the angle between the positive X axis and the
line connecting origin and P(x,y).
This function work correctly, hence I'm not reporting it here
*/
/*
heading, attitude and bank are only other names for roll, pitch and yaw
I'm using this function as taken from
http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToQuaternion/index.htm
*/
quaternion RadRPYtoQuat(float heading, float attitude, float bank) {
// Assuming the angles are in radians.
float c1 = cos(heading/2);
float s1 = sin(heading/2);
float c2 = cos(attitude/2);
float s2 = sin(attitude/2);
float c3 = cos(bank/2);
float s3 = sin(bank/2);
float c1c2 = c1*c2;
float s1s2 = s1*s2;
quaternion result;
result.w = c1c2*c3 - s1s2*s3;
result.x = c1c2*s3 + s1s2*c3;
result.y = s1*c2*c3 + c1*s2*s3;
result.z = c1*s2*c3 - s1*c2*s3;
return result;
}
point3 BoneRPY(point3 p) {
float roll, pitch, yaw;
yaw = -Radians(p.y, p.x);
p.y = p.y * cos(yaw) - p.x * sin(yaw);
roll = Radians(p.y, p.z);
pitch = 0;
return point3(roll, pitch, yaw);
}
int main() {
/*
parse the BVH file, get nodes and so on
then:
*/
point3 p = BVH_Node.Offset;
p = BoneRPY(p);
quaternion q = RadRPYtoQuat(p.x, p.y, p.z);
AN8_Bone.orientation = q;
/*
store bone into figure hierarchy, print out the an8 file and so on
end of the story
*/
}
The BoneRPY() function is the part I'm not sure about. In my mind, I'm getting the yaw from a mere projection, I'm rotating a coordinate to avoid angle misrepresenting and I'm getting roll. Two euler's angles should be enough to get every possible orientation, isn't it?
I feel lost, really, hope somebody could help me sorting this out.
PS: rename "test.bvh.txt" removing the ".txt" part, I've added it to let the forum accept it as attachment. It's a trivial issue, just matter of clarity.
[Edit: Anim8or expects quaternions to be stored in xyzw order, am I right? It seems to be so, but I ask to be sure]