schteppe / cannon.js

A lightweight 3D physics engine written in JavaScript.
http://schteppe.github.com/cannon.js
MIT License
4.69k stars 712 forks source link

Maximum velocity of 16.5 units? #18

Closed unphased closed 12 years ago

unphased commented 12 years ago

I have to investigate further, maybe I am doing something stupid, but I wonder somebody could give me a hint for what this could be about, or if anybody's encountered a similar issue?

The feature set of this library as it stands is almost perfect for what I'm trying to do with it: A marble maze game where I have some geometry that I want to roll a ball around and collide with. Since there are boxes that makes it even better!!!

unphased commented 12 years ago

I think I found what it is. I'm pretty sure it's just reached terminal velocity because of the damping.

schteppe commented 12 years ago

You're right. By default, both linearDamping and angularDamping is set to 0.01. Try setting them to zero and things will work out better.

unphased commented 12 years ago

Could you tell me how you have your quaternions defined? I'm getting quite confused by quaternions now.

I'm implementing quaternion "difference" to compute the angular velocity to set when going from one orientation to another orientation.

According to here http://www.gamedev.net/topic/423462-rotation-difference-between-two-quaternions/ I need to compute the inverse quaternion of the current orientation to multiply with the target orientation to get a quaternion representing the "difference" rotation. Getting the axis-angle representation of this should provide me with a value I can scale and set to angularVelocity.

So I'm looking at CANNON.Quaternion.prototype.inverse and you're negating q.x, q.y, and q.z, while leaving q.w. This seems to indicate that in the representation used here: http://www.mathworks.com/help/toolbox/aeroblks/quaternioninverse.html your q.x is q_1, q.y is q_2, q.z is q_3, and q.w is q_0.

Is that correct?

Also, is this operation not the conjugate? The inverse of q is conj(q) / ||q||^2. Edit: Oh I see they are the same when q is normalized.

I'd like to also mention that this physics engine is amazing. keep up the good work. Which area of it are you working on now? The naive broadphase is already really fast! Boxes or convex hulls are probably the things to focus on for now. =)

unphased commented 12 years ago

I take it your q.w being the first (real) coordinate is from the convention here: http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm

So this makes it rather confusing since you have the quaternion set function taking args (x,y,z,w)... Shouldn't w be the first one?

schteppe commented 12 years ago

The current Quaternion inverse is not really the mathematical inverse, it is just the opposite rotation of the quaternion. I have no idea why I did it like that. It is not used in the rest of the code, so I've never thought of it either. If you'd like to contribute, you could add the correct inverse and the conjugate (and while you're at it, why not SLERP also? ^^).

The convention used is x,y,z for the axis of rotation and w for the rotation part; the order is x,y,z,w. This is very natural for me, that's why I chose that convention. It is also the alphabetical order so it is hard to forget it.

Thanks :) I am in fact doing convex hulls at the moment :)

unphased commented 12 years ago

Hmm you confused me some more with your second paragraph. The quaternion is made up of 4 components, the first one being real and the rest are 3 imaginary scalars, scaling the i, j, k imaginary bases. What is the mapping between this and CANNON.Quaternion's properties (x,y,z,w)?

An axis-angle representation (angle being in radians I presume) also happens to be 4 components but these values are quite different from the quaternion values... You even have the CANNON.Quaternion.prototype.setFromAxisAngle function which is correct and seems to indicate the w being q0 (the first, real component)

So I'm not sure what you mean when you say that the current Quaternion inverse isn't the mathematical inverse, it very much is the inverse, provided that the quaternion has been normalized!

This is actually my very first introduction to quaternions so I don't think you should trust me to implement SLERP but if I do implement it I will let you know for sure.

And lastly I'll point out that the alphabetical order is in fact w, x, y, z: w comes first just like the mathematical quaternion layout! It is only in 3D homogeneous coordinates that w is assigned to the last value, and I am pretty used to it as well from working with OpenGL and basing my software renderers on those conventions.

I'm not sure what the best representation is though. Having the components be properties w, x, y, z is fine, it's just the order that is (a little) strange to me. Don't know if making it an array would help at all, or if that would have performance implications.

schteppe commented 12 years ago

Sorry for confusing you. Damn it, I should get some sleep before writing on here....

x,y,z are the imaginary parts, which in a way corresponds to an axis of rotation. The w component is the real part which I often think of as an angle. One cannot dirctly use these components as an axis and an angle though.

I'll get back to you tomorrow.

unphased commented 12 years ago

Good night.

schteppe commented 12 years ago

Okay, let's get things clear.

w: multiplier of the real part, corresponds to a on the wikipedia page (q = a +bi +cj + dk), or q_0 on the mathworks page x,y,z: multipliers of the imaginary parts, corresponds to b,c,d on wikipedia or q_1, q_2, q_3 on mathworks

Cannon.js' quaternion inverse is not general enough to call it quaternion inverse. As you said already, it holds for normalized quaternions, but it should be redesigned so it works for all cases. I did not intend to construct the quaternion conjugate when making that function, though it seems to be it after all. What to do next is renaming the current inverse() function to conjugate() and making a new inverse function that does correct things.

Doing a quick research on some libraries that I like (three.js, Bullet Physics, AgX Multiphysics) that implements a Quaternion class gives me the answer that the order should be (x,y,z,w). On the other hand, all mathematical definitions I've looked at recently (Mathworks, Wikipedia, Paul Bourke) suggests the order (w,x,y,z). This was very interesting. How come the math suggests wxyz and softwares suggests xyzw? I'm not sure why, but personally I'd stick to the latter since I'm used to it.

A totally irrelevant question (though similar in a way): What axis do you think is better for the up direction? Y or Z? I assume you're not being mad using the X axis! (lol)

Passing an array of numbers to the constructor should not be much different, though I think that it looks better in the documentation to have separate parameters for the numbers.

unphased commented 12 years ago

Thanks for clarifying. That is interesting that the standard seems to be x,y,z,w. Being consistent with that is probably far more important than anything else, so please don't change anything.

I generally lean towards having Z be the up direction. It really does depend on the situation though. When defining world/static coordinates I always set it so that gravity is (0,0,-9.8) so +Z is up, so Z value is altitude.

It is almost always necessary to define a separate camera frame though and I wish W3C's CSS3 camera axes were consistent with OpenGL's but it is sadly not the case. Since -Z goes into the page, and -Y is up, I think that means it is actually a left-handed coordinate system. You see I bring this up because what i'm trying to do is make a hybrid CSS3+Canvas renderer for running on the iOS browser. If done right I think I can get really good performance, but I have to get all the coordinate systems and transformations lined up.

schteppe commented 12 years ago

No problem, thanks for your feedback. Good luck with that project of yours! It sounds really interesting.

unphased commented 12 years ago

Thanks, I have been doing my testing in your motionstates.js demo, so I think I'll be back with a pull request some time soon which will showcase a kinematic box whose pitch and roll are controlled by the mouse (with the sphere spawning above it of course): It's a much better demonstration of kinematic functionality (and overall behavior of the box-to-sphere contact) within the physics engine.

So far I'd gotten a version working where I directly set the quaternion based on these angles, and even that works great for slow, gentle motions: the penetration resolution in this physics engine is fantastic. Again, keep up the great work: full convex body support (which implies box collisions of course) will bring this to a whole new level. You'll probably be famous.