Switching between Camera Types (TrackBall -> First Person -> etc.)

Started by
2 comments, last by haegarr 11 years, 3 months ago

Hi to everyone,

I'm trying to build a generic camera class (so just one class) that with few simple operators can allow one to create any type of high level camera.
I'd like to do it this way because I think that, then, switching for example between a first person and a trackball like camera will be easier.
For now I've successfully implemented the usual 1st person camera by defining few simple operators on the camera class and creating orientation using quaternions.

Operators/Methods:

moveXCameraRelative
moveYCameraRelative

rotateXCameraRelative
rotateYCameraRelative

The thing is that I can't figure out how to switch between (say) a 1st person and a trackball without screwing everything. What I mean is flying a bit with a 1st person and then from that exact pov switch to trackball and use it and then back to 1st person transparently (like in a DCC tool).
What I thought is that I should accumulate orientations etc. but I guess that my current method is not very correct because instead of accumulating orientations deltas I accumulate the angle and calculate the orientation of accumulated angles instead of defining an offset quaternion. I saw some implementation they do something like:

Quaternion q(axis,delta) //the offset quaternion (relative rotation quaternion)

I do something like:

angle += delta;

Quaternion q(axis,angle); //the absolute rotation quaternion

should I use the first solution and accumulate quaternions instead of accumulate the absolute angle to have the possibility to implement the behaviour that I described before tongue.png ?

Thanks in advance for your help smile.png

Advertisement

There are several problems mentioned in the OP. My advices are:

1. You should stay away from using Euler angles if possible.

2. You should apply delta rotations and translations, but store the current placement as either a matrix or a pair of position vector and orientation quaternion.

3. You should not integrate too much responsibility into a single class. E.g. the camera class stores and grants read access to the placement of the camera as well as some simple manipulators (in extreme just a setter) for this placement, but it should not provide higher level control like a concept of 1st person and 3rd person camera. Instead, provide a basic CameraControl class and derive FPCameraControl and others from it.

4. When switching the active CameraControl, the next active control may need to alter the camera's placement to get it into a prescribed state. If you want to avoid sudden changes, then make a soft transition so that the current placement (i.e. those stored in the camera object, usually as left from the previous control) and the new required placement are interpolated over a short time, e.g. a second or so, before actually granting control to the following CameraControl object. Notice please that this can be integrated into the schema nicely: Define a TransitionalCameraControl class that is parametrized with the CameraControl that should become active. Let the former one do the interpolation (it asks the camera for the current placement and the given CameraControl for the required placement), and let it replace itself by the given CameraControl when done.

There are several problems mentioned in the OP. My advices are:

1. You should stay away from using Euler angles if possible.

2. You should apply delta rotations and translations, but store the current placement as either a matrix or a pair of position vector and orientation quaternion.

3. You should not integrate too much responsibility into a single class. E.g. the camera class stores and grants read access to the placement of the camera as well as some simple manipulators (in extreme just a setter) for this placement, but it should not provide higher level control like a concept of 1st person and 3rd person camera. Instead, provide a basic CameraControl class and derive FPCameraControl and others from it.

4. When switching the active CameraControl, the next active control may need to alter the camera's placement to get it into a prescribed state. If you want to avoid sudden changes, then make a soft transition so that the current placement (i.e. those stored in the camera object, usually as left from the previous control) and the new required placement are interpolated over a short time, e.g. a second or so, before actually granting control to the following CameraControl object. Notice please that this can be integrated into the schema nicely: Define a TransitionalCameraControl class that is parametrized with the CameraControl that should become active. Let the former one do the interpolation (it asks the camera for the current placement and the given CameraControl for the required placement), and let it replace itself by the given CameraControl when done.

So that means that there is no way to switch from one camera control to another without interpolating between them ?

I thought it was possible to just accumulate in the right order (based on the current camera control type) to be consistent to one camera control or

another without sudden changes to show up.

Plus, currently I'm calculating my orientation like this and it works stable with no gimbal lock or numerical instabilities, but I do not understand why I should work with delta rotations instead of absolute angles (it works anyway).

Here is a code snippet:


//create orientation
QuatfFromAxisAngle(Vec3f(1.f,0.f,0.f),mPitch,&mRotX);
QuatfFromAxisAngle(Vec3f(0.f,1.f,0.f),mYaw,&mRotY);
QuatfFromAxisAngle(Vec3f(0.f,0.f,1.f),mRoll,&mRotZ);
QuatfMult(mRotX,mRotY,&mRotXY);
QuatfMult(mRotZ,mRotXY,&mOrientation);	

//normalize quaternion
QuatfNormalize(mOrientation,&mOrientation);
						
//now extract the orientation part of the view matrix
Mat44fInitFromQuaternion(mOrientation,&mViewMatrix.mat44f);


mViewMatrix.mat44f.v03 = -Vec3fDot(cameraPos,mRight);
mViewMatrix.mat44f.v13 = -Vec3fDot(cameraPos,mUp);
mViewMatrix.mat44f.v23 = -Vec3fDot(cameraPos,mForward);	

It works smooth and perfect (I keep Roll == 0 all the way).

Pitch, Yaw are just accumulated absoulte angles:

Pitch += dPitch; same for yaw

What I'm thinking is It possible to make just one class that gives just very bare bones operators to implement different camera behaviours without having to implement a class for every camera type ?

I saw some implementation showing something like:

rotateXCameraRelative

or rotateXWorldRelative blabla

which leads me to think they are just basic operators and there is no reference to first person or third or track ball ... and the idea is that a very specific combination of them can implement for example a first person behaviour or a trackball if you use a different combination of them.

I

You could of course switch camera control without interpolation. However, that may introduce abrupt changes. Think for example of switching from a 1st person camera to a 3rd person camera. The former one is obviously located much closer to the avatar (if any, but let us think so) than the latter one. Notice that both kinds of camera control have their own idea of how to locate (especially position) the camera. Switching without interpolation lets the camera position jump. If you want it that way ... no problem. For pleasure, however, it is usual to interpolate just to avoid abrupt changes.

Even with the system described you have the choice of whether to interpolate or not, simply by using a TransitionCameraControl or don't doing so. The TransitionCameraControl may also terminate immediately if it detects the both placements to be already identical.

[quote name='MegaPixel' timestamp='1358435075' post='5022532']
I thought it was possible to just accumulate in the right order (based on the current camera control type) to be consistent to one camera control
[/quote]

Notice please that this would work exactly only for non prescribed parts of placement. As written above, e.g. the position of a 1st person and a 3rd person camera is prescribed by the control. When switching from 4rd person to 1st person than the 1st person control sees the position of the camera out-of-range. But this out-of-range isn't an accident, because being left by the former control. Why should each and every CameraControl have the need to correct what was left by its predecessor?

[quote name='MegaPixel' timestamp='1358435075' post='5022532']
why I should work with delta rotations instead of absolute angles
[/quote]

Using delta rotations gives you a sequence like

Ry(hn) * Rx(pn) * Ry(hn-1) * Rx(pn-1) * ... * Ry(h0) * Rx(p0)

while accumulating heading and pitching for each other gives you

Ry(hn + hn-1 + ... + h0) * Rx(pn + pn-1 + ... + p0) = Ry(hn) * Ry(hn-1) * ... * Ry(h0)* Rx(pn) * Rx(pn-1) * ... * Rx(p0)

what is obviously not the same in general. However, the former one is usually what ones expects to get.

[quote name='MegaPixel' timestamp='1358435075' post='5022532']
which leads me to think they are just basic operators and there is no reference to first person or third or track ball ... and the idea is that a very specific combination of them can implement for example a first person behaviour or a trackball if you use a different combination of them.
[/quote]

That idea is close to what I meant with "the camera class ... grants ... some simple manipulators" in the previous post. However, what manipulators do you expect to need? You need a setter for sure. All others depend on the kinds of controls you want to implement. It is likely that another kind of control will need another kind of manipulator. Even if not ... even doing look-at computations and friends is not strictly a domain of a camera. Why aren't they part of the vector math package? Then all the controls can still use shared code without burdening the camera class, and tracking and path following and so on will be available for other game objects, too.

This topic is closed to new replies.

Advertisement