OSG Navigation System.

Started by
10 comments, last by sun-tracker 17 years, 9 months ago
Hello all, New to the forums here. Seems an excellent resource and source of information! I'm hailing from the University of Michigan's 3D Lab. A former employee (who now is at Apple), left an incomplete navigation system for use in our CAVE environment and on our GeoWall. Over the past few weeks I've been going through and A: Understanding his logic, and B: (trying to) make it better. The code is written for OSG which then passes the scene inforamation and general control over to VRJuggler. One of the few outstanding and unresolved issues I cannot negotiate is a matter with our camera. His version relied purely on matrix transformations on the local 4x4 matrix, which were then multiplied to the global matrix just before being passed off to VRJuggler. The camera rotation matrix was then reset to the identity. To put it simply, his code carried with it the problem of rotating along the vertical axis. If you tilt the camera up, and then wish to look left or right, the camera does not stay level with the ground. Instead, it will rotate based on the camera's orientation/matrix, and thusly move in a diagonal path instead of the desired horizontal rotation. I decided to replace his code with a quaternion-based representation, and it works quite elegantly with many fewer lines of code. The only problem that remains is the issue with this non-horizontal rotation. I spent about an hour looking through the past pages of this forum but haven't found any that relate to this specific problem yet. So to put it as simply as I can, and before I start posting snippets of code, here are my specific Q's: 1) Is this problem easily negotiable under a quat-based camera system? 2) Are there any glaring troubles I may find myself in because I have chosen to use a quat-based system for camera orientation? Ultimately, a world matrix is what gets passed to VRJuggler. 3) If Yes to 1 and No to 2, are there any resources on the web or on these forums which address my problem specifically? If not, could someone provide some direction? To give a very brief idea of my implimentation: I set the local quat for the direction I want to rotate. For example, if I want to tilt the camera up, the local quat will be set to (W=rads,X=1,Y=0,Z=0). I then normalize it, and it gets passed off to pre-frame where it's converted into a matrix and multiplied by the world matrix. I apologize for the long-winded post! -Austin [Edited by - sun-tracker on July 3, 2006 12:44:14 PM]
Austin BakerUniversity of Michigan 3D Lab
Advertisement
Quote:Original post by sun-tracker
Hello all,

New to the forums here. Seems an excellent resource and source of information!
Welcome to the forums :)
Quote:1) Is this problem easily negotiable under a quat-based camera system?
The problem is easily fixed, either with quaternions or without them. Personally though I would not use quaternions in this case, as they offer no benefits to speak of in the given context and only serve to make a fairly simple problem more complex.
Quote:2) Are there any glaring troubles I may find myself in because I have chosen to use a quat-based system for camera orientation? Ultimately, a world matrix is what gets passed to VRJuggler.
No problems per se, but again, it's not necessary; a matrix- or vector-based approach would most likely serve you just as well.
Quote:3) If Yes to 1 and No to 2, are there any resources on the web or on these forums which address my problem specifically? If not, could someone provide some direction?
Based on your description of the problem I gather (perhaps incorrectly) that you want a camera of the sort often associated with a character in a first-person game, the salient feature being that the orientation always remains 'upright' regardless of what rotations are applied. More specifically, pitch always takes place about the local side axis, while yaw always takes place about the world up axis.

This has been addressed a few times; I've discussed it and/or offered example code here and here. Of the two links I think the first might be of the most immediate use to you.

If you get stuck on any of the details, please post back; I'll be happy to help you get this working if I can.
Thanks Much. I'll read through those links and post here my findings/questions/conclusions.

As for your question about the camera, we have several modes we need to be able to switch between on the fly. The main ones are: Fly (aka freecam), Orbit, and Walk.

I also have a "keep_cam_level" variable in there for the purpose of preventing the tilt I'm trying to get rid of. Setting this variable to false would result in a flight-sim type camera (the way it currently behaves).
Austin BakerUniversity of Michigan 3D Lab
Quote:Original post by sun-tracker
As for your question about the camera, we have several modes we need to be able to switch between on the fly. The main ones are: Fly (aka freecam), Orbit, and Walk.
In that case you might look at the second link, which includes code to support both 'free' and 'walk' modes (the first link includes additional info on a 'walk' mode camera).

The code in the second link has some OpenGL-specific aspects, but it should be easy to adapt it for another API.
Thanks -- I'll take a look.
Very irritating that I have 90% of the functionality I desire with only 30-40 lines of code. It seems my "elegant" implimentation needs to become less elegant to get that last 10%.
Austin BakerUniversity of Michigan 3D Lab
I have read both threads and your jykOpenGLObjct.h and .cpp files.

I apologize if I'm blind, but I don't quite see the way to make my quat problem "easily fixed". It looks like the end result in both of those threads was that they ditched their quat based systems.

The code I am writing in addition to the entire collection of files we have created are intended to be distributed freely for others to use on their CAVE setups. Because of this, I am beginning to think that for the sake of understanding and ease-of-implementation, perhaps I should scratch my quat-based system as well and go back to something like what you have written. Hmm...

I would really prefer to make the quat-based system work first, though. For my own benifit / comfort, and so I can make the best decision on whether or not to keep it or go back to matrix/vector operations.

One thing I forgot to mention is that we will definately have to impliment camera-animation capabilities in the future... moving & aiming the camera along an OSG Path. SLERP would probably very convenient to use there.

-Austin
Austin BakerUniversity of Michigan 3D Lab
Quote:Original post by sun-tracker
I apologize if I'm blind, but I don't quite see the way to make my quat problem "easily fixed".
Well, maybe 'easily fixed' isn't precisely the right phrase :-) Let me try to give a bit more detailed reply that, I hope, will address some of the issues you mention.

As you might guess, a 'walking' camera and a 'free' camera (especially one that needs to follow a curved path or to interpolate between orientations) have somewhat different requirements.

However you manage the details, a 'walking' camera is best implemented (IMO) as in the examples I linked to. Specifically, the orientation for the camera should be constructed from scratch each frame, rather than by using incremental rotations. Though oft-maligned, Euler angles are perfectly appropriate for this. Alternatively, you can think of the problem in terms of spherical coordinates and manual basis vector construction.

Interpolating between two orientations in this case can be done via simple linear interpolation of the two angles in question (i.e. yaw and pitch); although it would certainly work, 'slerp' is not required in this case.

A 'free' (6DOF) camera has different requirements. It is best handled via incremental rotations, and slerp may be necessary for smooth interpolation of orientations. A quaternion is perfectly suited (although not strictly necessary) for this, while Euler angles are in this case particularly ill-suited. Note also that a quaternion is a nice representation to use when following of a curved path is required.

Also keep in mind that it's possible to convert between all the representations under consideration, so you can easily switch back and forth between them if needed.

So it may be that a quaternion is a reasonable fundamental representation for your camera's orientation. For 'walk' mode though I would build the quaternion from scratch rather than incrementally.

Well, I guess I apologize for the 'easily fixed' comment. Although the particular problem you mentioned is easily fixed, creating a well-designed camera class that offers multiple types of motion and control requires a bit of thought.
Ah.

I should be more specific about the different 'modes'. For the walk mode I was really intending to simply use fly mode but turn on gravity / collision and restrict any upward motion (leaving the ground). I didn't think they would have to be fundamentally different, and were actually quite similar excluding the collision/gravity component.

(i don't know how to make quote boxes yet)
"Although the particular problem you mentioned is easily fixed, creating a well-designed camera class that offers multiple types of motion and control requires a bit of thought."

I will most likely refine and/or rewrite our navigation class in the future, but for right now I would really like to get that one issue fixed. So, may I poke you for the solution to my 'particular problem'? Or at least a push in the right direction?

Here are the two functions that handle my rotation currently.

[SOURCE]//======================================================================//! Rotation Functions:void JNavigator::rotLocal(gmtl::Quatf transform){	gmtl::setRot(*m_local_xform, currentG); //Update Rotation	m_redrawFlag = true;}void JNavigator::rotLocal(enum rotation rotation, const float rads) //Overloaded rotLocal for simple user input commands (pitch,yaw,roll){	gmtl::Quatf quat;	quat[Welt] = rads;	//Set Quat According to User Input	if (rotation == pitchUp) quat[Xelt] = -0.0010f;	if (rotation == pitchDown) quat[Xelt] = 0.0010f;	if (rotation == yawRight) quat[Yelt] = -0.0010f;	if (rotation == yawLeft) quat[Yelt] = 0.0010f;	if (rotation == rollClk) quat[Zelt] = 0.0010f;	if (rotation == rollCClk) quat[Zelt] = -0.0010f;	// Normalize the Rotation Quat:	float mag = sqrt((quat[Welt]*quat[Welt])+(quat[Xelt]*quat[Xelt])+(quat[Yelt]*quat[Yelt])+(quat[Zelt]*quat[Zelt]));	quat[Welt] /= mag;	quat[Xelt] /= mag;	quat[Yelt] /= mag;	quat[Zelt] /= mag;	rotLocal(quat); //Send off to primary rotLocal function for implimentation}


In another file, appropriate keypresses & input from other devices calls the overloaded rotLocal with the appropriate direction.

Just like this:

if(m_key_left.KeyDown()) { getNav()->rotLocal(yawRight,0.1);}
if(m_key_right.KeyDown()) { getNav()->rotLocal(yawLeft,0.1);}
Austin BakerUniversity of Michigan 3D Lab
Quote:Original post by sun-tracker
I should be more specific about the different 'modes'. For the walk mode I was really intending to simply use fly mode but turn on gravity / collision and restrict any upward motion (leaving the ground). I didn't think they would have to be fundamentally different, and were actually quite similar excluding the collision/gravity component.
I'm not familiar enough with the context to comment on the code directly, but part of the confusion may be what is meant by 'fly' mode.

To me, 'fly mode' can mean a couple of things; the first would be a full 6DOF camera like in the game Descent, while the latter would be a free (but fixed-up) camera similar to Quake's spectator mode.

If you mean the former, it doesn't seem to me that walk mode could simply be derived by restricting upward motion, as it would still be possible to roll, which I'm guessing isn't what you want. If this is in fact the case and you're intent on implementing this mode as a modification of fly mode, it may be possible to convert the quaternion to its corresponding basis vectors, re-orient the frame so that the world up vector remains fixed, and convert it back to a quaternion.

Personally I would find it easier to implement the camera system you describe from scratch, using whatever methods were most appropriate for each mode, rather than trying to modify one mode to mimic another (apologies if this isn't particularly helpful).
Sorry for the delay in responding. Fireworks and shuttle launches and such!
Back to work though!

In our system, the camera does not represent the orientation of the user as a whole, but rather it is fixed only to their head, so head tilt (roll) should still be possible.

When in fly mode, in most cases we would probably desire a spectator type of movement (i'm afraid I don't know quake very well so I don't remember exactly how their fly-cam behaved), but I don't really want to close any doors by not allowing 6DOF.

One of my big hang-ups comes when trying to picture the whole thing. I dislike that the world is what eventually gets moved and rotated -- not the camera.

I'll try and re-explain the general way in which our system works:

Upon key-presses, our navigator code will be called. The navigator files purpose is to operate on the local (camera) xform (4x4 OpenGL style matrix). The world matrix is then multiplied by the local xform, and then sent back up. Because the local xform is reset after every frame, it only represents the changes in translation/rotation for that particular frame. There is no cummulative matrix that represents the position and orientation of the camera. As soon as the navigator code is called, the camera is located at 0,0,0 with zero rotation.

I chose to use quats for rotation because it provided a very simple interface. After determining which direction to rotate in, that quat is incorporated into the local matrix with the line:
gmtl::setRot(*m_local_xform, currentG);
Which takes the quat and sets the local cameras matrix to match that rotation.

The Quat stuff is really only the interface for the rotation.
I didn't mean to say it was a quat-based camrea, because in all the other functions and in every other place, the camera is represented as, and operated on, as a matrix -- "m_local_xform".
Austin BakerUniversity of Michigan 3D Lab

This topic is closed to new replies.

Advertisement