Notifications
Clear all

[Closed] Converting rotation values for BVH

 S-S

eek:

Thanks for links eek! Today i had a little bit of time, and i cleaned up the exporter code, and it think the same problem is still the cause.

I fixed all other bugs (position of root joint was offset by one frame…) and such with one joint BVH file, i guess i’ll have to read a bit more about eulers and angles… at this point it
s only choice as otherwise exporter works fine.
I checked my rotation code, it’s nearly identical to what you suggested.

3 Replies
 eek
(@eek)
Joined: 11 months ago

Posts: 0

So i did a very quick test, loading the same matrix transform onto the same object with different rotation orders. My initial hunch was correct, it produced the same result each time.

I’d ask how you guy’s are passing the values, and whether or not the axis order is changing either through the animation or per bvh.

I think what might be happening is that your not compensating for the objects intial rotation relative to world space in respect to its pivot.

(@takuandaikon)
Joined: 11 months ago

Posts: 0

At the risk of sounding dense, I’d like to ask for clarification here… If you have a limb that rotates only 90 degrees along a single axis (we’ll pick X for example) and apply that to a second limb with a different axis order, you only get the same result so long as you apply X in the correct order, right? I mean, a rotation from a limb with XYZ rotation order and [90,0,0] rotation would be applied to a limb with ZXY order as [0,90,0], right?

Or am I getting this wrong?

.

 eek
(@eek)
Joined: 11 months ago

Posts: 0

Your’ll get the same value with each different axis order, axis order doesnt matter in the end, only the orientation and position of the pivot. When this changes your’ll need the ‘space’ difference.

This is why i said you have to take into acount the intial rotation of the object and its pivot. Axis order from my research doesnt affect anything other than the order of the interpolation of the matrix not the actual matrix order.

And to your last past yes – but this is automatic. I havent tried this but if you set an object rotation order to say ZYX and then ask for its first value i.e $.rotation.controller[1].controller

does it return its xSubcontroller or Z – my hunch is X because its transformation matrix i dont think changes only the order of actions inside it.

I did as well, and despite my earlier enthusiasm and report of success, I seem to have been premature. I can export basic animations, but only within a very limited range. I don’t know what I have done wrong, but there are a great many movements such as reaching with the hand across the body to the opposite shoulder that simply won’t work.

  I've decided to give up on creating a .bvh exporter for Max, for the time being.  I did some "proof of concept" experiments last night, and managed within just a couple of hours to create an exporter that outputs the quaternion rotation values in a manner that I can easily and accurately read them back in using a matching importer I created for another program, apply them to a similar figure, and re-export them from there as .bvh using an exporter I had written previously.  It's an added tool in the chain and more steps than I would like, but it only took a couple of hours, whereas I've been working on .bvh export in Max for over a week with no success.
  
  I'd love to eliminate the extra steps and do it all in Max, but I simply don't have the time to invest or the knowledge to do so.  I'll keep watching this and other threads, and I do hope to pick up on the missing pieces eventually.
  
  Thanks for the info and links eek and PEN, it's very much appreciated, and best of luck to you Sami.  I hope you manage where I have not :)
  
  .
 S-S

EEK:

Thanks for interest. This is what i have done to test this problem

A. I have created simple ideal bvh file manually. It contains root, joint and “end site”. It has two frames of animation,a neutral pose frame and a frame with rotations. Rotation values are float, i just wrote them as integer for the sake of clarity:


HIERARCHY
ROOT Hips
{
  OFFSET 0.0 0.0 0.0
  CHANNELS 6 Xposition Yposition Zposition Zrotation Xrotation Yrotation
  JOINT Chest
  {
    OFFSET 0.0 5.0 0.0
    CHANNELS 3 Zrotation Xrotation Yrotation
    End Site
    {
      OFFSET 0.0 10.0 0.0
    }
  }
}
MOTION
Frames: 2
Frame Time: 0.0333333
0 0 0 0 0 0 0 0 0
1 2 4 1 2 4 1 2 4

B. Then, after i import this file i export it again, and this is the result:
(Now i have to guess that my importer works ok, but i have compared my imported joints to one imported with 3rd party importer and i think it’s accurate)


HIERARCHY
ROOT Hips
{
  OFFSET 0.0 0.0 0.0
  CHANNELS 6 Xposition Yposition Zposition Zrotation Xrotation Yrotation
  JOINT Chest
  {
    OFFSET 0.0 5.0 0.0
    CHANNELS 3 Zrotation Xrotation Yrotation
    End Site
    {
      OFFSET 0.0 10.0 0.0
    }
  }
}
MOTION
Frames: 2
Frame Time: 0.0333333
0.0 0.0 0.0 0.0 -6.83019e-006 0.0 0.0 0.0 0.0 
1.0 2.0 4.0 1.13706 1.9254 3.99835 1.13705 1.92541 3.99835 

This is the way i’ve tried to convert euler values to angles:


a_points_parent_node = (getNodeByName (a_points_parent.name + "_ref"))		
rx = (quatToEuler ((the_ref_points[a_ref_point].transform * inverse a_points_parent_node.transform).rotation)).x
ry = (quatToEuler ((the_ref_points[a_ref_point].transform * inverse a_points_parent_node.transform).rotation)).y
rz = (quatToEuler ((the_ref_points[a_ref_point].transform * inverse a_points_parent_node.transform).rotation)).z
format "% % % "  -ry rx rz to:outfile

 S-S

I’d like to add one thing – In exported file you’ll see those “inaccuracies” like rotation of 1.0 degrees is 1.13706 and rotation of 2.0 degrees is 1.9254.

This wasn’t that obvious until i compared BVH imported skeleton + animation to imported-exported-imported skeleton + animation.
Run cycle for example is nearly there but it’s obvious this ain’t acceptable and it only gets uglier further down the hierarchy, thanks to cumulative errors

I did a BVH exporter recently. To get around the rotation order and things, I went with a temporary object.

Create the temporary object, parent it, set the rotation, and get the angles in gimbal.


tempbox.rotation.controller.axisorder = 2
tempbox.parent = lshoulder
tempbox.rotation = lfore.rotation
na = in coordsys gimbal tempbox.rotation.y_rotation as float
nb = in coordsys gimbal tempbox.rotation.z_rotation as float
nc = in coordsys gimbal tempbox.rotation.x_rotation as float

A bit long-winded, but I haven’t had anything go wrong with it yet. Maybe some day I’ll know enough about MaxScript to refine it.

One little thing that I ran into is that the rotation order in the BVH files I was doing is actually in reverse order from what you tell Max the rotation order is. If the order in the BVH is YZX, then I had to tell Max that the rotation order is XZY. Then output the order in the same order as in the BVH. Threw me for a serious loop.

1 Reply
(@takuandaikon)
Joined: 11 months ago

Posts: 0

I tried that exact same code, having gotten it from the SL forums, and it works for a lot of cases but unfortunately not all of them. In particular, there were several animations I tried where the results were way off, such as drawing a hip or back-mounted sword. For walk and run cycles and a lot of common anims it seems to work fine though.

Yeah, I finally noticed that after bunch of tinkering with the script, though it took a while to discover because it wasn’t commented

I wonder if one of the MaxScript/Maths gurus here could explain why this is?

.

 eek

You guys tried build a matrix?

Get the order from the bvh eg. ZXY from readLine:


Line = filterstring (readLine inFile) ” , “ splitEmptyTokens:false

ZRot = line[4] as float
XRot = line[5] as floatYRot = line[6] as float

Turn those in rotation Matrices:

ZRotationMatrix = rotateZMatrix zRot
XRotationMatrix = [size=2]rotateXMatrix xRot[/size]
[size=2]YRotationMatrix = [size=2]rotateZMatrix yRot[/size][/size]
[size=2][size=2][/size][/size]
[size=2][size=2]build this matrix, in an opposite order.[/size][/size]

FinalRotMatrix = YRotationMatrix * XRotationMatrix * ZRotationMatrix

Then apply this to the joint:

Joint[1].transform = Joint[1].transform * FinalRotMatrix

Before this, build an identity matrix with the offset as row4 and multiply this by the parent transform:

joint[1].transform = (matrix3 [1,0,0] [0,1,0] [0,0,1] jointOffsets[1]) * jointArray[1].parent.transform

cheers,

[size=2][size=2][/size][/size]
[size=2][size=2]
[/size][/size]

Speaking for myself, the biggest part of the problem (and the only reason for using .bvh format) is that I have absolutely no control over the destination environment and no visibility on how it applies the rotations from the file to the joints. For me the task is all about export, and import is completely out of my control.

The target application is a third-party application that has provided the .bvh specification they use (which includes the rotation orders for each joint), and that’s all I get. The challenge is to create an exporter that properly conforms to that specification. I was able to do so without any problems in DAZ|Studio, which is kind of like a free Poser clone (but uses Javascript for plugins), and it works great aside from the fact that the animation tools in DS are nowhere as capable or sophisticated as 3ds Max.

So I’d love to be able to develop a Max exporter that can do the same, I just find myself unable to understand how to extract and write the rotation information in a way that it comes across unaltered in the target program. I am quite sure it’s possible, I’m just missing some critical understanding of how Max and MaxScript work

.

Page 2 / 2