Sorry your browser is not supported!

You are using an outdated browser that does not support modern web technologies, in order to use this site please update to a new browser.

Browsers supported include Chrome, FireFox, Safari, Opera, Internet Explorer 10+ or Microsoft Edge.

DarkBASIC Discussion / .x files and Quaternion keyframes - help!

Author
Message
Robert The Robot
17
Years of Service
User Offline
Joined: 8th Jan 2007
Location: Fireball XL5
Posted: 26th Jul 2008 22:44 Edited at: 26th Jul 2008 22:45
I'm trying to read a .x file's animation by converting the animation keyframes (which are stored as quaternions) to euler angles (the nice easy, 0..360 axes we use when rotating objects).

I've basically been using a (modified) DBPro function I found here, which does appear to be correct based on what I've seen on wikipedia and a few other places on the net. Unfortunately, when I specify limb angles using my program Lightning Limbs, and then test the quaternions it generates, the calculated angles aren't the ones I set.

Help???

"I wish I was a spaceman, the fastest guy alive. I'd fly you round the universe, in Fireball XL5..."
Robert The Robot
17
Years of Service
User Offline
Joined: 8th Jan 2007
Location: Fireball XL5
Posted: 27th Jul 2008 12:19 Edited at: 27th Jul 2008 12:20
I just remebered, I didn't post any code . This is what I'm working with:


The best I'm getting is when all original (euler) angles were <180, as then the function seems to return the correct angles but makes them negative. When I did X=190, y=0 and z=0, the converted quaternion returned angles -10, 0, 0.

By the by, I've got two sets of equations pulled from different parts of the forum, but as far as I can tell they amount to the same thing.

"I wish I was a spaceman, the fastest guy alive. I'd fly you round the universe, in Fireball XL5..."
Latch
17
Years of Service
User Offline
Joined: 23rd Jul 2006
Location:
Posted: 27th Jul 2008 16:58 Edited at: 27th Jul 2008 17:02
Well, from what I calculate your initial quaternions are off. Seem to be rotated in the opposite direction. I also had to change the order of operations a bit in the equations ((1 - (2*(x#*x# + y#*y#))) so that the calculations were correct. I commented out the middle set of equations and didn't bother with them.
You'll notice for the first quaternion (rotation of 190) the resulting euler angle will be -170 . That is correct because the angles run 0 to 180 and -180 to 0. Use wrapvalue to return 190.



Enjoy your day.
Robert The Robot
17
Years of Service
User Offline
Joined: 8th Jan 2007
Location: Fireball XL5
Posted: 31st Jul 2008 21:04
Hi Latch! Sorry I've been a few days answering, but it took me a little longer than I thought to read the animation data from a .x file into DB, and I've had some trouble with the internet.

I've tried out what you suggested, but while it worked on those particular examples it didn't appear to work on any others. I ported over another example I'd found on the GDK board, and it seems to work fine (which strikes me as odd, since for all its complexity I think it boils down to the same equations you showed me).

Anyway, I've got the animation loading (it works almost perfectly, just a few rounding errors on the 5th and 6th significant figures). The only snag is when it comes to y-rotating a limb 180 degrees. If I specify a keyframe where the limb was rotated 0, 180, 0, loading it back into LL produces a rotation of 180, 0, 180. It looks exactly the same, but the code I use to generate the 'in-between' frames as keyframes behaves strangely - instead of rotating the limb around the y-axis, the limb twists awkwardly.

Is there a really simple answer, like "If x-angle = z-angle then y-angle = x-angle : x-angle = 0 : z-angle = 0"? But if that is the case, how do I handle animations where there have been transformation about the x- and z- axes?

Here's my code, in case you need it:


"I wish I was a spaceman, the fastest guy alive. I'd fly you round the universe, in Fireball XL5..."
Robert The Robot
17
Years of Service
User Offline
Joined: 8th Jan 2007
Location: Fireball XL5
Posted: 2nd Aug 2008 17:38
Hi, it's me again.

I've been doing a few more experiments, and I've found a way to correct the 180,0,180 angles returned by my quaternion function to give 0,180,0. If the conversion states that the x-angle increases by 180, then:

x-angle = x-angle at last frame
y-angle = 180-current y-angle (i.e. angle algorithm says y-axis should be at)
z-angle = 180+current z-angle (i.e. angle algorithm says y-axis should be at)

Unfortunately, there's a downside. Original X- and Z- angles of 180 are calculated correctly, but original Y-angles of 180 produce a rotation of 180 about the X-axis (there's also a transformation about the y- and z- axes). So I can't figure out how to tell the difference between an original rotation of 180 about the y-axis or the x-axis.

All other animation sequences seem to load perfectly, as far as I can tell, it's just this one problem I can't get rid of. Any ideas?

"I wish I was a spaceman, the fastest guy alive. I'd fly you round the universe, in Fireball XL5..."
Latch
17
Years of Service
User Offline
Joined: 23rd Jul 2006
Location:
Posted: 2nd Aug 2008 20:33
Wow, you've done some great work! I like the approach of converting the quaternion to a matrix then to a euler (as opposed to quaternion to euler directly - which does amount to pretty much the same thing). The tricky thing is knowing if the original quaternion is the right one so to speak. I've tried a few methods of creating my own quaternions. While the rotations look ok in the model, converting them to euler gives back varying results. The main problem I'm having is with the order of rotations. What is the order of rotations DB is using in calculating it's quaternions in the animation file? Anyway, I think the singularity you are experiencing may be happening at +-90. Try making a rotation with the values
xang#=50
yang#=90
zang#=100

and see what the result is using your conversion algorithm. I'm gonna look at your code ( I think it's great and very helpful ) and try and figure out what's going on.

Enjoy your day.
Robert The Robot
17
Years of Service
User Offline
Joined: 8th Jan 2007
Location: Fireball XL5
Posted: 2nd Aug 2008 20:58
I think DBC uses the order XYZ to calculate the quaternions - I'm not entirely sure as it all goes on behind the scenes with "Save Object Animation". I'll try your example angles and see what I get later on - at the moment, I want to see what I can find about Quaternion Slerps.

I'm thinking it might not be a problem with converting the Quaternions to Euler, but rather the way I generate the "in-between" frames. If I can follow the same method that DirectX uses to create the animation, that should automatically take care of the y-rotation problem.

"I wish I was a spaceman, the fastest guy alive. I'd fly you round the universe, in Fireball XL5..."
Robert The Robot
17
Years of Service
User Offline
Joined: 8th Jan 2007
Location: Fireball XL5
Posted: 3rd Aug 2008 22:06 Edited at: 3rd Aug 2008 22:08
Just tested your suggested angles - rotating a limb 50,90,100 producces a quaternion that converts back to 150, 90, 0. (It's actually highlighted a typo in the algorithm, it originally returned 180. Oops!).

I've been slerping and it's solved most of my problems - and created one or two new ones. I've revised my code a little for reading in the animation quaternions from directx animation, and this is what I've got:



In LL, at first glance it loads everything perfectly. The problem is that when generating the inbetween frames, certain animations (and Dark Dragon's sample animations are perfect examples) get their limbs rotated the wrong way round. For example, in the punch animation when the body spins back round again, the lower arm gets bent back on itself as though the figure were double-jointed - but the original animation was not.

I've isolated the problem (I think) to this part of QuaternionSlerping Function:


When the angle between the two quaternions is 180deg (so SinTheta is zero), the function can't choose the shortest route because there isn't one. I could be mistaken (I don't really understand all this) but I think the code above returns a quaternion that moves the limb in a particular direction but unfortunately, DirectX actually expects a quaternion that spins the limb in the opposite direction.

I've attached a demo of LL (1.65MB download) including DarkDragon's kick animation so you can see what I mean - start a new project, load the object and click Yes to load the animation. If you switch between frames 11 and 13, you'll see that Limb 0 (actually the whole object) rotates very little. However, when you look at frame 12 the object has been spun right round, which is clearly wrong. Frame 12 should have the object rotated partway between frames 11 and 13, to tie in with all the following frames.

Any ideas how to reverse the direction of a quaternion?

"I wish I was a spaceman, the fastest guy alive. I'd fly you round the universe, in Fireball XL5..."

Attachments

Login to view attachments
Latch
17
Years of Service
User Offline
Joined: 23rd Jul 2006
Location:
Posted: 4th Aug 2008 04:04
What I did was create my own quaternion function (I had my order of rotations YZX which you could imagine made things difficult to deal with in DBC). I stored the original euler in an array then generated my quaternion for the ouput of a custom anim file that mimicked the one created by save object animation. This also allows me to use negetive values for my angles so I know which direction I intend the rotation to be (clockwise or counter).

If you are calculating your own quaternions, the signed angle should convert to a quaternion rotating in the desired direction.

Enjoy your day.
Robert The Robot
17
Years of Service
User Offline
Joined: 8th Jan 2007
Location: Fireball XL5
Posted: 6th Aug 2008 17:19
Hi Latch!

What you said was very interesting, but I'm afraid I hadn't explained myself properly. According to what I've read, quaternions represent points on the surface of a 4-dimensional sphere, centered about an origin. Since any 3 points may be linked by a triangle (origin, quaternion a and quanternion b) there will be an angle theta between the two quaternions. If theta<180, the slerp function finds the shortest route between the quaternions. But if this angle theta = 180 then there is no shortest route and so the algorithm chooses a route - unfortunately for me (or so I thought) the wrong one.

It turns out that I was barking up the wrong tree - the function I wrote used a variable called CosTheta but if this is <0 then I have to invert one of the quaternions (invert the signs of all the vector's components) and CosTheta. From what I've read, it's because (w,x,y,z) and (-w,-x,-y,-z) are the same rotation. Since cosTheta = qa.w * qb.w + qa.x * qb.x + qa.y * qb.y + qa.z * qb.z inverting either of the quaternions (qa or qb) will invert cosTheta, but then aCos is called. This returns 0 to 90deg for +ve inputs and 90 to 180deg for -ve inputs, so to return the shortest angle (as DirectX does) we need CosTheta to be positive, which can be achieved by inverting one of the quaternions. So the only error was a minus sign!

In case you're interested, here's the code that will load a DirectX animation into DB, converting the Quaternions to Euler angles, generating all the inbetween frames, and also handling the limb offsets. Thanks for all your help!



"I wish I was a spaceman, the fastest guy alive. I'd fly you round the universe, in Fireball XL5..."
Latch
17
Years of Service
User Offline
Joined: 23rd Jul 2006
Location:
Posted: 6th Aug 2008 20:25 Edited at: 7th Aug 2008 01:02
Quote: "What you said was very interesting, but I'm afraid I hadn't explained myself properly. According to what I've read, quaternions represent points on the surface of a 4-dimensional sphere, centered about an origin"


I am by no means any kind of expert on this type of math! I can kinda get by with a few formulas in front of me and about a dozen books for reference!

Let me preface by saying I'm gald you found a solution that is working. I'm very interested in the code and will probably mess around with it to get some ideas! Thanks! But, I also just want to say where I was coming from...

I probably didn't explain myself very well. I was looking at the goal of creating expected rotations in the anim file that would be used for a direct x model. The problems, just to restate them, in DBC 1.20 are:

1. A strange "flip" happens at rotations between 119 and 120 - the rotation direction is reversed

2. There doesn't seem to be any easy way to retrieve the world direction angles, or the angles at which limbs are rotated at any given point - at least not all of the angles. Also getting the relative limb angle isn't much help. In both cases, angle z seems to be absent.

3. The output data in the anim file created by the SAVE OBJECT ANIMATION command outputs quaternions that represent rotations in one direction; though the internal SLERPing accomodates by finding the most likely closest interpolated rotation. I suspect in DBC 1.20 there is another limiter that tries to determine the rotation quaternion by comparing the current position to the next rotation key and if it is > than 120, the angle is to be reversed. However, I think there is an error that always measures the start angle from 0 instead of the previous key to the next key.

My suggestion is to NOT use the anim file created by DBC and create your own. DBC 1.20 will rotate the limbs in the correct directions and in a full 360 degrees if the rotation quaternions provided are correct in their indications of rotation. So the goal is to create more universal quaternions.

Quote: "it's because (w,x,y,z) and (-w,-x,-y,-z) are the same rotation. "


I don't think that is stated correctly. They represent the same destination, but they represent two different rotations.
Quote: "Latch- If you are calculating your own quaternions, the signed angle should convert to a quaternion rotating in the desired direction."


If I create two rotations that should end up at the same destination but in opposite directions, by what I understand you to be saying, the rotation should be towards the angle that is closet to start angle. Starting from 0, let's take -182 and 178 as the same destination. Just looking at them, the rotation should be towards 178 because it is closer. But, one's quaternion from euler function should result in two different quaternions representing the direction of rotation. My algorithm uses YZX rotation and it is modified to work with DBC limbs so if you enter a specific angle, the limb will rotate in an expected direction based on DBC behavior. Anyway, the resulting quaternions around y are:



And if you plug those in as an anim key, you'll see rotation in the opposite direction for each. In DBC, -182 anticlockwise and 178 clockwise.

Perhaps I'm not understanding and that is what you are saying.

Quote: "In case you're interested, here's the code that will load a DirectX animation into DB, converting the Quaternions to Euler angles, generating all the inbetween frames, and also handling the limb offsets. Thanks for all your help!"


The x file animation, is the import from a direct x file that already has animation or is it from the output file of SAVE OBJECT ANIMATION? My feelings are to avoid that output file and make your own.

And thank you! I'd been planning on going down this road but just never had the gumption. You've given me an excuse to study!

Even though my functions seem to work, I have to do a lot more testing because I'm sure there's something that'll bite me that I have overlooked, but so far so good. I also decided to look at direct x functions that have all this stuff in them. Basically, multiple quaternion rotations are just multiplications from one quaternion to the next. Do you have the DLL d3drm.dll ? If so I'll post some code I was messing around with to create roations keys using that dll.

[EDIT]

One other thing, a euler angle does not necessarily represent a quaternion rotation. The only real reason to convert the quaternion back to a euler is to make it easy to understand and use. DB is also deceptive in that it only accepts + valued angles which does not necessarily indicate the direction of rotation.

Enjoy your day.
Robert The Robot
17
Years of Service
User Offline
Joined: 8th Jan 2007
Location: Fireball XL5
Posted: 8th Aug 2008 12:55 Edited at: 8th Aug 2008 17:56
Quote: "I am by no means any kind of expert on this type of math!"

Really???? You could have fooled me

Quote: "The output data in the anim file created by the SAVE OBJECT ANIMATION command outputs quaternions that represent rotations in one direction"

I'm not so sure, actually. Just been doing some tests with Lightning Limbs. With LL running in 1.20 (LL1.20) I opened a .Lim project and the animation played strangely. I saved the object+animation to a .x file (which uses "Save Object Animation") and the animation then loaded correctly in LL1.13. It even plays fine in the Media Browser that came with DB!

These were the quaternions exported using LL1.20 for the only limb that moved:


and these were the quaternions exported using LL1.13:


There's no difference at all, so I think the error must lie in animation playback only.


Quote: "Perhaps I'm not understanding and that is what you are saying."

It wasn't quite what I was saying, though I think it makes more sense . I think the variable I called CosTheta should more properly be HalfCosTheta. 2*ACos(CosTheta) will be 0..180 for +ve inputs, and 180..360 for -ve inputs. If CosTheta is negative, the angle between the two quaternions is >180 so we have move in the other direction - which can be achieved by inverting one of the quaternions (it doesn't matter which one, though I don't understand why).


Quote: "The x file animation, is the import from a direct x file that already has animation or is it from the output file of SAVE OBJECT ANIMATION? My feelings are to avoid that output file and make your own. "

It's from the output file of Save Object Animation. I wanted to be able to read the animation data of .3ds files and binary .x file as well, but didn't like the idea of having to study the file formats!

Quote: "I also decided to look at direct x functions that have all this stuff in them. Basically, multiple quaternion rotations are just multiplications from one quaternion to the next. Do you have the DLL d3drm.dll ? If so I'll post some code I was messing around with to create roations keys using that dll."

I do have the dll, and I'd be very interested to see your code.

"I wish I was a spaceman, the fastest guy alive. I'd fly you round the universe, in Fireball XL5..."
Latch
17
Years of Service
User Offline
Joined: 23rd Jul 2006
Location:
Posted: 9th Aug 2008 20:15
Quote: "With LL running in 1.20 (LL1.20) I opened a .Lim project and the animation played strangely."


That's my point... there are quaternions that will play as expected in both DBC 1.13 and DBC 1.20, but the quaternions have to be generated representing the direction of rotation. DBC 1.13 calculates based on the closet angle so the quaternions it generates seem to be based on the rotation between keys. If it's greater than 180, it's considered an opposite rotation. That's why if you set a key to rotate a limb 300 degrees, it won't loop around 300 in the positive direction, it will rotate 60 degrees in the negetive direction. Anyway, I'll send you an email to the address from your website with some code that uses the direct x dll. I haven't really benchmarked it so I don't know if it is actually faster than using math in DBC. Check your spam folder in case it automatically get's dumped!

Enjoy your day.
Robert The Robot
17
Years of Service
User Offline
Joined: 8th Jan 2007
Location: Fireball XL5
Posted: 10th Aug 2008 15:52
Quote: "That's my point... there are quaternions that will play as expected in both DBC 1.13 and DBC 1.20, but the quaternions have to be generated representing the direction of rotation."

Ah, I see!

I'm looking forward to getting your e-mail

"I wish I was a spaceman, the fastest guy alive. I'd fly you round the universe, in Fireball XL5..."

Login to post a reply

Server time is: 2024-04-18 12:51:24
Your offset time is: 2024-04-18 12:51:24