Fly from one camera to another

Started by
8 comments, last by alh420 10 years, 12 months ago

I'm looking for a way to smoothly transition between two arbitrary camera positions/orientations. Ideally, I would like it to appear as though the camera is flying from one place to the other, such that the camera moves forward at a constant rate and there is a limit to how quickly it can yaw and pitch and roll. At first I thought a bezier curve or a spline might do the trick, but neither really has an adequate way to control curvature along the path.

Any ideas?

Advertisement

Sounds like a fun little task.
Well first off, I would attach a target vector to the camera class, as well as some sort of maximum speed limit to act as a scalar value for each axis.
Next, I would have an update function in the camera class which took the delta time between frames as a parameter, and call that function each frame.

In the update function, I would use the typical formula of:


camPos.x += ((camTarget.x - camPos.x) * deltaTime) * speedScalar.x;
camPos.y += ((camTarget.y - camPos.y) * deltaTime) * speedScalar.y;
camPos.z += ((camTarget.z - camPos.z) * deltaTime) * speedScalar.z;

This will animate the camera's current position to eventually match the target camera's position, at a speed based upon the scalar value. You can raise or lower this value as needed until it feels right for you.

As for making the camera "point" in the direction it needs to go, just do a simple "LookAt" transformation (ie, "gluLookAt" or "Matrix.LookAt*" functions) from your camera's current position to the target camera's position, and either set that as the first target camera (to animate the rotation sequence) or determine at which points along the animation you would like to "combine" these animations, and I believe you should get the effect you're looking for. Or at least get you on a pretty good start.

Of course, this is just one way to do it, though.

That will move from the 1st camera to the 2nd in a straight line, which is not what I want. I want the camera to always move forward but turn gradually to reach the eventual position and orientation.

Suppose that there's a Camera class with Position (Vector) and Rotation (Matrix or Quaternion)

The first part of the update should be something like:


camera.Position += Speed * camera.Rotation * Vector.Forward 

The next part needs to change the camera rotation (within the limits set for speed of rotation) so that in subsequent updates it will reach its destination and be at the appropriate orientation when it gets there.

It would be ideal if the only information needed was the current Camera and the destination Camera, but it would also be okay to calculate a path from Camera1 to Camera2 and step along it, so long as the speed requirments can still be met.

I wouldn't do this via a gradual advancement of the state, instead I'd write a pure function that takes the two input cameras (initial/target) and a fraction, and blends them to spit out a new camera setup each frame.

When initializing this "transition camera", you record the start time, then calculate the end time for the transition. You can do this by looking at each of the components to be interpolated (positions, rotations, FOV values, etc) and each of their max rates (max metres/s, degrees/s), etc to find the minimum amount of time that it would take each individual component to be interpolated, then take the maximum of all those times as your actual time that the inerpolation should take.

e.g. if you can move from A->B in 1s, but it will take 3s to rotate from looking at C to looking at D, then the movement should be slowed down so that it also takes 3s.

You then add this to your starting time to calculate the ending time.

Each frame, you then look at the current absolute time, and the start/end time to calculate a fractional value of how far through the transition you should be (e.g. (end-now)/(end-start) ) If this is 1.0 or greater, you're done with the transition camera and you can just start using the target camera. Otherwise you pass the two cameras and this fraction into your pure function to calculate a blended camera.

For parameters like FOV, you'd just lerp them using the fraction. For rotation, you can just slerp them using the fraction.

For position, you could also just lerp them using the fraction, but this would move in a straight line between the two. If you want the camera to move forwards in a curving arc, you could define a spline using the two positions, and the two forward vectors as the tangents at those positions.

For parameters like FOV, you'd just lerp them using the fraction. For rotation, you can just slerp them using the fraction.
For position, you could also just lerp them using the fraction, but this would move in a straight line between the two. If you want the camera to move forwards in a curving arc, you could define a spline using the two positions, and the two forward vectors as the tangents at those positions.

This is the part of the solution that eludes me. Yes, I could define a spline to lay out the path of motion, but if at the same time I SLERP the rotation, the two will be out of sync and the camera will not appear to be moving forward. I could instead use the derivative of the spline to determine the forward direction of the camera, but there would be nothing to indicate the associated roll. In either case, how would I limit the curvature of the spline and regulate the speed along it?

Just a curious thing to note.... How would you handle situations where the target camera's orientation is a polar opposite of the current camera's orientation?

For example, camera A is rotated at 90 degrees while camera B is rotated at 270 degrees...

Seems lengthy to create a spline which keeps this transition "moving forward" since it would have to first choose a direction and then fulfil a 180 degree "S-spline" interpolation.

Just something to keep in mind

That being said, I do agree with Hodgman's suggestion over my own, but depending on what this is for, there may be certain scenarios where a more 'immediate' response to orientation could benefit the whole package.

It may be helpful to come up with a more concrete specification of how you want the camera to behave. There's some straightforward cases, like the top left one in the scribbling below, but what about when the next camera is just next to you (do you go forward, do a u-turn, go behind it, do another u-turn? do you do a spiral? or do you just slide sideways instead of going forward?), or just behind you? There may be some cases where you do want the direction of movement to not match up with the viewing direction.

6tdLZ3o.png

I'd say first construct a Hermite/Catmull Rom spline from a series of positions. Next, calculate the derivatives/tangents for every key point along the curve. Then, from an initial orientation (matrix/quaternion) keep correcting the orientation to 'point' in the same direction as the tangents on the curve.

At this point you'll have a series of matching positions and orientations. You can then either modify the roll of the orientation by restricting rotation around the tangent axis or allow rotation on all axes to allow for scenarios as Hodgman mentioned them.

Ideally, you would have some graphical environment to set this up. Most existing 3D modelers/animators will have means for this.

I think Rectangle and Hodgman have pointed out the inherent problem with splines: that given the right endpoints, they can produce some really acute turns up to and including pivoting on a point.

Like I said, I want constant forward speed with only gradual turns. Think of the camera as having momentum in the direction it is facing and that the only forces that can be applied are centripetal (and those have a maximum magnitude). This way, the camera will never speed up or slow down but will change direction to match the desired end condition.

To make it explicit, I'll use Rectangle's example where the start and end cameras are at the same position but with opposite orientations. The solution I imagine would probably look like a car turning around in a cul de sac.

Sounds like you might want to implement it like you would implement an ai agent, with some steering behaviours?

http://www.red3d.com/cwr/steer/

This topic is closed to new replies.

Advertisement