| Version 2 (modified by osg, 6 years ago) |
|---|
Positioning a Camera with a User-Defined Matrix
TracNav
- About
- Screenshots
- News
- Developer Blog
- Mailing Lists
- Forum
Documentation
- Getting Started
- Platform Specifics
- Tutorials
- Examples
- User Guides
- Programming Guides
- Reference Guides
- LatestDevelopments
- Porting
- CMake
- CDash
- CPack
- FAQ
- Tips And Tricks
- Maths
- Knowledge Base
- Trac Usage Examples
- TracGuide Documentation
- Software Patents
- Software Patents Europe
- Downloads
- Community
- Links
(Wiki editing note: Code needs conversion to osgViewer)
(Wiki editing note: Add link to complete source code at bottom)
Goal
Manually position a camera to view a scene.
Overview
To position a camera manually, we can use the viewer class setViewByMatrix() method. This call should be placed between the viewer.update and viewer.frame calls within the simulation loop. The following guidelines are useful:
- Producer and all classes below osgGA::MatrixManipulator (in terms of abstraction) use 'Y' up coordinates. All others -including the Viewer class matrix manipulators - use 'Z' up.
- The inverse of a position/orientation matrix can be used to orient a camera.
With these guidelines, the only steps required to position a camera manually are:
- Create and initialize a matrix with the correct world position and orientation.
- Get the inverse of this matrix and...
- Provide a world up orientation. In this case by rotating from 'Y' up to 'Z' up.
The code
Set up position & orientation of matrix
To setup a matrix we can use the methods of the osg::Matrix class. In this case we’ll use a double-precision type, or osg::Matrixd. To position and orient this matrix, we can use the Matrix class methods makeTranslate() and makeRotate(). Both of these methods have a number of overloads for convenience. For this example we’ll use the version of makeRotate() that takes 3 degree/vector pairs. Rotation will be by the number degrees (in radians) about the axis specified by the vector. For translation we’ll use the version that simply takes x, y and z values. We’ll create a single matrix that represents a rotation and translation by post-multiplying the rotation matrix by the translation matrix. The code to achieve this is as follows.
Here's the code to set up a scene. The scene has a small terrain model and a tank at position (10,10,8).
int main()
{
osg::Node* groundNode = NULL;
osg::Node* tankNode = NULL;
osg::Group* root = new osg::Group();
osgProducer::Viewer viewer;
osg::PositionAttitudeTransform* tankXform;
groundNode = osgDB::readNodeFile("\\Models\\JoeDirt\\JoeDirt.flt");
tankNode = osgDB::readNodeFile("\\Models\\T72-Tank\\T72-tank_des.flt");
// Create green Irish sky
osg::ClearNode* backdrop = new osg::ClearNode;
backdrop->setClearColor(osg::Vec4(0.0f,0.8f,0.0f,1.0f));
root->addChild(backdrop);
root->addChild(groundNode);
tankXform = new osg::PositionAttitudeTransform();
root->addChild(tankXform);
tankXform->addChild(tankNode);
tankXform->setPosition( osg::Vec3(10,10,8) );
tankXform->setAttitude(
osg::Quat(osg::DegreesToRadians(-45.0), osg::Vec3(0,0,1) ) );
viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS);
viewer.setSceneData( root );
viewer.realize();
Declare and set a matrix to be used for the camera. Set the position of this matrix to be 60 units behind and 7 units above the tank model. We'll also set the orientation of the matrix.
osg::Matrixd myCameraMatrix;
osg::Matrixd cameraRotation;
osg::Matrixd cameraTrans;
cameraRotation.makeRotate(
osg::DegreesToRadians(-20.0), osg::Vec3(0,1,0), // roll
osg::DegreesToRadians(-15.0), osg::Vec3(1,0,0) , // pitch
osg::DegreesToRadians( 10.0), osg::Vec3(0,0,1) ); // heading
// 60 meters behind and 7 meters above the tank model
cameraTrans.makeTranslate( 10,-50,15 );
myCameraMatrix = cameraRotation * cameraTrans;
Using the matrix to position the viewer’s camera
Using osgProducer::Viewer default settings, a call to a viewer instance’s update() method results in the viewer’s cameraGroup instance calling its setViewByMatrix method. Normally the argument to this method will be the inverse of the current matrix manipulator’s (trackball, drive, or fly) matrix. One way to change this behavior is to manually set the viewer’s matrix immediately after the viewer update() method is called. To use the camera position/orientation matrix we created above to manually position and orient the Viewer’s camera matrix, we need to first invert the matrix.
In addition to inverting the matrix, we also need to provide world orientation. Normally osgGA::MatrixManipulator matrices (used by osgProducer::Viewer class) represent a ‘Z’ up coordinate system. Producer and osg::Matrix class matrices (like those created above) normally represent a ‘Y’ up coordinate system. So after inverting the matrix from above, we also need to provide a rotation from ‘Y’ up to ‘Z’ up. This can be done by rotating -90 degrees about the x-axis. The code to do this is as follows:
while( !viewer.done() )
{
viewer.sync();
viewer.update();
if (manuallyPlaceCamera)
{
osg::Matrixd i = myCameraMatrix.inverse(myCameraMatrix);
viewer.setViewByMatrix( (
Producer::Matrix(i.ptr() ))
* Producer::Matrix::rotate( -M_PI/2.0, 1, 0, 0 ) );
}
viewer.frame();
}
Note: Pressing the 'v' key switches to the manual camera.
