   Camera with Angular Velocity or Angular Momentum
  Hi All,I'm trying to add Angular Velocity (or possibly Angular Momentum) with a clamped Angular Acceleration to my camera system and have begun to bang my head against a brick wall.  So I thought I might shout for help from those of you with a better understanding than myself.The reason I only say possibly Angular Momentum is because the Moment of Inertia would be uniform and constant.I have a camera system that currently stores its orientation (and position in a matrix.  Each Step I calculate an ideal "lookat" matrix.  Rather than Slerp between the two what I want to do maintain an Angular Velocity for the camera, and accelerate the camera (using a maximum acceleration) towards the ideal orientation.My thinking was:1. Get the Angular Displacement between the Ideal and Current orientations (this would be the Angular Velocity we would need to have to make change the orientation to the ideal orientation in one time step.)2. Get the direction of this angular velocity.3. Apply an Angular Acceleration to the Angular Velocity in this direction, but limiting the Angular Acceleration to some maximum constant.4. Apply this new Angular Velocity to the Current orientation to get the new orientation.The part I'm having the biggest problem with is the direction of the Angular Acceleration, but the whole solution would be great.This calculation is done in a fixed timestep Update function, and the Current Orientation is stored as 4x4 Matrix.  The Angular Velocity can be stored as whatever, and the maximum Angular Acceleration would be a constant float.I have conversions to and from Euler/Quaternions at my disposable.  And I have tried the Quaternion equations based around dQ/dT = 0.5WQ(t) etc on my journey so far.  This needs to be fairly quick as well.This is all to create the effect of the camera having inertia, so that when the target suddenly changes direction, the camera will overshoot a bit, before catching back up to the target.  So if there is a better way to achieve this effect, I'm all ears.Would appreciate your thoughts,Thanks.   
  No takers?  Starting to think this is actually quite a difficult thing to work out, considering how quiet it is in this thread :)   ;Quote:No takers?  Starting to think this is actually quite a difficult thing to work out, considering how quiet it is in this thread :)I read the post, but didn't understand everything in it. Perhaps you could describe the problem in a little more detail. What do you mean by the camera 'overshooting'? What kind of camera is it exactly? Does the camera always remain 'upright', or can it be arbitrarily oriented? Can you tell us anything more about the context?   ;  If all you are trying to get is a non-uniform blend from the start location to the finish location, try using a non-uniform blending parameter for your slerp.  In effect, apply the acceleration to the blending parameter that you send into the slerp function.You can think of f(t) as a kind of blend velocity.If you want to start slow, and end fast, you can use a quadratic functionIf you want to start fast and end slow, you can use this function;Quote:Original post by jykQuote:No takers?  Starting to think this is actually quite a difficult thing to work out, considering how quiet it is in this thread :)I read the post, but didn't understand everything in it. Perhaps you could describe the problem in a little more detail. What do you mean by the camera 'overshooting'? What kind of camera is it exactly? Does the camera always remain 'upright', or can it be arbitrarily oriented? Can you tell us anything more about the context?Thanks for the response.What I mean by overshooting is that lets say the camera was initially pointing straight down the X axis, but the ideal orientation had it pointing directly down the Y axis.  So to begin with the camera would gain velocity starting to turn and gather rotational velocity towards the Y axis.  As the camera approaches the Y axis, lets now suddenly change the ideal orientation back to pointing down the X axis.  The camera will of course accelerate back towards pointing down X axis, but as its got Angular Velocity in the direction of the Y axis, it will actually get closer to the Y axis before the acceleration towards the X axis overcomes the built up velocity towards the Y axis.  With a Slerp the camera would immediately have moved towards the Y axis.Hope that made sense, its that "appears to have inertia" effect I want to capture.Camera can be arbitrarily orientated.This is for a camera system for a game, which I want to make look as realistic as possible.Many thanks.;  I've seen a few games (fps) where the gun acts in the same way as you would like your camera, when you move the mouse to look around you can notice the guns slightly trailing behind (and overshooting if you whip back in the other direction).I don't have much useful to say on this subject unfortunatly but if you treat this as a linear problem then you have a position, current velocity and acceleration (acceleration being found from current position and desired position).Translating this into rotational and you have current position being the current orientation, velocity being angular velocity and it just leaves the problem of how to deal with acceleration :/.Eric Brown's idea is nice, changing how the time increases when you use slerp but I don't think it will give you the overshoot effect you desire (as it no longer uses previous velocity).I have my doubts that this will work but:if I have 3 quaternions,current - represents no rotation at presentangularVelocity - this is a 90 degree rotation about an axisangularAccel - this is a -45 degree rotation about the same axisthen if I do:angularVelocity = angularVelocity * angularAccel;current  = current*angularVelocity;current now represents a 45 degree rotation about the same axis.In effect we've increased the current velocity by an acceleration and then increased the current position by that velocity.Some problems (appart from being maths pretty much plucked randomly out the air and maybe making no real mathematical sense :P) time isn't considered, if the update occurs every 0.5 seconds instead of every second. You could maybe convert acceleration back to axis angle form, create a new temp acceleration where you scale the angle by time (perfect oppotunity to cap angular acceleration) and then create the temp acceleration from that. Apply it to the velocity and then do the same for velocity to scale it by time (and cap as needs be) Finally apply it to the orientation of the camera.I haven't tested this (as I can't) and I probably have my quaternion multiplication order the wrong way around etc (this is using physX quaternions) but hopefully it should demonsttrate my idea(as bad as it may be :P)Quaternion m_CurrentOrientation;Quaternion m_CurrentAngVelocity;// per secondvoid ScaleByTime(Quaternion q, float seconds){float angle;Vector axis;q.getAngleAxis(angle, axis);angle *= seconds;q.fromAngleAxis(angle, axis);}void ClampAngle(Quaternion &q, float max){float angle;Vector axis;q.getAngleAxis(angle, axis);if(angle > max){angle = max;}q.fromAngleAxis(angle, axis);}void Update(Quaternion desired, float seconds){// Work out a quaternion which rotates m_CurrentOrientation to desired// I can't recall how to do this off the top of my head but its needed for slerp right?Quaternion acceleration;// Scale it by timeScaleByTime(acceleration, seconds);// make sure we're not accelerating too rapidlyClampAngle(acceleration, MAX_ACCEL_ANGLE_PER_SECOND * seconds);// Work out new velocitym_CurrentAngVelocity = m_CurrentAngVelocity*acceleration;// make sure velocity isn't too large, keep it as a per second valueClampAngle(m_CurrentAngVelocity, MAX_VELOCITY_ANGLE_PER_SECOND);// Now we need to scale velocity by time before applying itQuaternion velocity = m_CurrentAngVelocity;ScaleByTime(velocity, seconds);// clamp itClampAngle(velocity, MAX_VELOCITY_ANGLE_PER_SECOND * seconds);// apply itm_CurrentOrientation = m_CurrentOrientation*velocity;} [Edited by - Nanoha on April 7, 2010 7:50:18 AM];  Thanks very much for the response, seems like you put alot of effort into that, much appreciated.I am trying out some code based on what you said, and whilst its not working, its not pointing the camera at random locations!  It broadly seems to be doing something right.  Any other suggestions please let me know, but I will post how I get on...Also your right about Eric Brown's suggestion, I meant to thank him.  I have the camera Slerping at the moment, and in fact will probably put both methods as options into the final code.  I'm planning to try out Eric's suggestion for the Slerp option, so thanks Eric.   ;  Here is a solution that might work for you.  I haven't tried this, but it seems to work on paper.  Sorry, it's kind of long :(If you were dealing with positions, instead of rotations, you may try a damped spring approach, where each frame you calculate the spring force between your current location and your desired location.  You would also calculate some damping that is opposed to your velocity so that you don't wildly oscillate.Here is the rotational version of a damped spring force using quaternions.You need to store a "position" (q) and "velocity" (v) quaternion to represent your rotational state.  You are going to calculate a rotational acceleration (a) that is analogous to a damped spring.  I'll discuss later how to calculate a, but once we have it, we will step the state forward like this:If your time step is small you should replace the expensive Slerps with NLerps.  If your time step is equal to 1 then you can remove the slerps altogether and the equations simplify toThere are two components to a.  One applies a spring force to push you toward your desired rotation.  The other dampens the motion so that you don't start wildly oscillating.The linear spring force is proportional to the difference between your current and desired positions.  For rotations, this difference is the rotation that rotates your current "look at" vector into your desired "look at" vector.  We will call this rotation Δq.  Here is a function based on the half angle method that will quickly calculate this quaternion, without employing any trig or inverse trig functions.Quat getRotationQuat(const Vector& from, const Vector& to){Quat result;Vector H = VecAdd(from, to);H = VecNormalize(H);result.w = VecDot(from, H);result.x = from.y*H.z - from.z*H.y;result.y = from.z*H.x - from.x*H.z;result.z = from.x*H.y - from.y*H.x;return result;}Once you have calculated Δq, you need to "scale" it by a constant that represents the springs stiffness.  The analogue of scaling in quaternion land is slerping between 1 and the given quaternion by the scale parameter.  The acceleration due to the spring is given byThe acceleration due to damping is proportional and opposed to the current velocity.  Again, you just need to "scale" the velocity quat using a slerp between 1 and the velocity.Since quaternion multiplication does not commute, it is not clear if the final acceleration quat should be composed with the spring acceleration first, or with the damping acceleration first.  My guess is that you should just pick one, and then tweak the k and μ parameters until it behaves correctly.  At any rate, the total acceleration can be given by the product of these two acceleration componentsAs before, if your k and μ paramters are small enough, you may want to consider replacing the expensive slerps with normalized lerps.  You may just want to do this anyway - I would!If you decide to try this, let me know how well it works.  I've often contemplated if it was possible to do rotational "dynamics" in this way.   ;  Thanks Eric, I'll give it a go in the morning and I'll let you know the outcome.   ;  Angular momentum and angular momentum acceleration can be described by 3 element vectors.Integrating the angular momentum with angular momentum acceleration is just a mater of simple linear integration (ex. using euler Am = Am + Ama * dt). You want to dampen the acceleration somehow (Am = Am * e^(-dt*k), or while integrating Am = Am + (Ama - Am *k) * dt).Integrating the rotation using the angular momentum are a little bit more difficult:  A simple way would be to create a rotation matrix using an angle and an axis ( Rn+1 = Rn * matrixFromAngleAxis(length(Am) * dt, normalized(Am)).  Another way of calculating next rotation would be to look at how the rotation matrix axes changes during rotation. Integrating the rotation axis using euler would become Xn+1 = Xn + cross(Xn, Am * dt), Yn+1 = Yn + cross(Xn, Am * st), ...  You can also convert these things to quaternions. This is probably the best way of doing things, but I cant remember it right now.You must always renormalize/ortogonalize your matrix/quaternion for making sure it does not get skewed or resized.The hardest thing is to find the angular momentum acceleration. You need to find the axis of rotation between the two rotations, and then scale it by the angular difference and some k. I cant remember how to do this effectively, but it can be achieved by examining the quaternion representation of the rotations. There is probably some direct way of getting an angle/axis from a pair of matrices.For limiting the rotation velocity and the rotation acceleration velocity you only need to clamp the lengths of the angular momentum and angular momentum acceleration vectors.Hope that helps.   