[x3d-public] BVH to X3D import working; right-handed coordinate system
Don Brutzman
brutzman at nps.edu
Tue Jan 10 06:51:33 PST 2017
Thanks for helpful feedback Joe.
On 1/9/2017 10:32 AM, Joe D Williams wrote:
> [...]
> Good work on the degrees to radians conversion steps.
> Always fun to apply some pi to it.
>
> Still wondering about that zxy to xyz order change from euler to fixed.
> Does 'fixed' really mean 'fixed' in this conversion context?
Am avoiding use of term 'fixed' since it is ambiguous.
Reference links:
X3D Scene Authoring Hints: Coordinate Systems
http://www.web3d.org/x3d/content/examples/X3dSceneAuthoringHints.html#CoordinateSystems
There were a few twists in the trail for figuring out right-handed (please) versus left-handed (shudder) coordinate system. Lack of clear documentation greatly exacerbated this problem.
Notes:
a. All recorded rotations were right-handed orientation about corresponding axis for phi (X axis), theta (Y axis) and psi (Z axis).
b. All recorded rotation values for 1.bvh were in degrees. I don't know (yet) if all BVH files are like that, not well documented and might be inconsistently applied.
c. BVH statement "CHANNELS 3 Zrotation Xrotation Yrotation" indicates order that data appears in the file (not a left-handed coordinate system).
d. Looking at BVH skeleton, first inspection might (incorrectly) indicate left-handed coordinate system since "Right" values are negative while height values are positive and z values are positive in forward direction of humanoid. However it is important to remember that the humanoid is facing along the Z axis towards the default viewpoint, so it is rotated around. Thus the negative Right values are OK, the Right side of the Human has been rotated 180 degrees (about vertical Y axis) to face the viewer.
Rephrased: the humanoid's local coordinate system is right handed, both for individual angles and for axes. If you stand at origin and face Z axis (out of screen) then Y is up, right hand is -X axis, left hand is +X axis, +Z is forward.
e. Here are some code excerpts. Sharp readers will see strict right-handed X Y Z ordering throughout.
=========================================================================
if (channelNamesString.equalsIgnoreCase("Zrotation Xrotation Yrotation") || // JOINT
channelNamesString.endsWith ("Zrotation Xrotation Yrotation")) // ROOT channels 0, 1
// Xposition Yposition Zposition Zrotation Xrotation Yrotation // ROOT channels 0, 1
{
phi = values[3*channelIndex+1]; // Euler angle about X axis, second channel
theta = values[3*channelIndex+2]; // Euler angle about Y axis, third channel
psi = values[3*channelIndex+0]; // Euler angle about Z axis, initial channel
}
AxisAngle4d axisAngle = getAxisAngleRotation( // computation is also order dependent
phi * Math.PI / 180.0, // degrees to radians
theta * Math.PI / 180.0,
psi * Math.PI / 180.0);
outputX3D.append(fourDigitFormat.format(axisAngle.x)).append(" ")
.append(fourDigitFormat.format(axisAngle.y)).append(" ")
.append(fourDigitFormat.format(axisAngle.z)).append(" ")
.append(fourDigitFormat.format(axisAngle.angle));
=========================================================================
/**
* Compute local AxisAngle4d SFRotation from Euler-angle rotations
* @see Joint#getAxisAngleRotation
*/
public AxisAngle4d getAxisAngleRotation (double phi, double theta, double psi)
{
// javax.vecmath conversions (boy is this a convoluted API or what!)
AxisAngle4d axisAngleX = new AxisAngle4d(1.0, 0.0, 0.0, phi);
AxisAngle4d axisAngleY = new AxisAngle4d(0.0, 1.0, 0.0, theta);
AxisAngle4d axisAngleZ = new AxisAngle4d(0.0, 0.0, 1.0, psi);
AxisAngle4d axisAngleIdentity = new AxisAngle4d(0.0, 0.0, 1.0, 0.0);
Quat4d quaternionIdentity = new Quat4d (); quaternionIdentity.set(axisAngleIdentity);
Quat4d quaternionX = new Quat4d (); quaternionX.set(axisAngleX);
Quat4d quaternionY = new Quat4d (); quaternionY.set(axisAngleY);
Quat4d quaternionZ = new Quat4d (); quaternionZ.set(axisAngleZ);
Matrix4d matrixCurrent = new Matrix4d();
Matrix4d matrixRotated = new Matrix4d(); matrixRotated.set(quaternionIdentity);
matrixCurrent.set(quaternionZ);
matrixRotated.set(quaternionIdentity); // TODO check order!
matrixCurrent.set(quaternionZ); matrixRotated.mul(matrixCurrent);
matrixCurrent.set(quaternionX); matrixRotated.mul(matrixCurrent);
matrixCurrent.set(quaternionY); matrixRotated.mul(matrixCurrent);
Quat4d quaternionRotated = new Quat4d (); quaternionRotated.set(matrixRotated);
AxisAngle4d axisAngleRotated = new AxisAngle4d(); axisAngleRotated.set(quaternionRotated);
return axisAngleRotated;
}
=========================================================================
Anyway, of course it is straightforward once we have something working.
Unnoticed symptom while debugging: wild angle value changes are always a clue that degree values are being interpreted as radians. (Conversely, unmoving/minimal angle changes are a clue that radians are being interpreted as degrees.)
Important lesson re-learned: you get what you inspect, not what you expect. I hadn't noticed any large-angle values until verbosely computing & reporting bounds on the BVH column data. This is a good lesson to keep in mind, our converters should get pretty verbose and we should record conversion parameters as metadata so that we know what is actually contained in somebody else's BVH file.
Having fun with H-Anim mocap!
all the best, Don
--
Don Brutzman Naval Postgraduate School, Code USW/Br brutzman at nps.edu
Watkins 270, MOVES Institute, Monterey CA 93943-5000 USA +1.831.656.2149
X3D graphics, virtual worlds, navy robotics http://faculty.nps.edu/brutzman
More information about the x3d-public
mailing list