The NVSGSDK follows a simple camera model for defining the view frustum.
The camera has the following characteristics associated with it:
Defining all these values described above can be very easy. Suppose you have a nvsg::Scene with a bounding sphere sphere
you want to look at with a nvsg::PerspectiveCamera pCamera
. The following code snippet does all the work:
pCamera->zoom( sphere );
This takes the camera from it's default position (0,0,1), view direction (0,0,-1), and up direction (0,1,0), and moves it along the view direction until the bounding sphere of the whole scene is inside the view frustum, using the default field of view of about 53° and an aspect ratio of 1. The center of the sphere will be in the view plane. The near and far distances are automatically determined to fit the frustum around the scene. Taking that as a starting point, the camera can be easily manipulated with calls to move
, orbit
, rotate
, and zoom
.
To specify the camera orientation (that is, a viewing direction and an up direction), you can use one of the following two code snippets:
pCamera->setDirection( dir ); pCamera->setUpVector( up ); pCamera->zoom( sphere );
pCamera->setOrientation( orientation ); pCamera->zoom( sphere );
Here again, the center of the sphere is in the view plane. Use a similar method to specify the field of view, the aspect ratio, and the near and far distances. Note that in the first snippet dir
and up
must not be collinear. In the second snippet, orientation
is the Quatf that rotates the default direction (0,0,-1) to the desired direction.
Usually, to prevent distortions, the aspect ratio of the view window in the view plane should be the same as the aspect ratio of the viewport on the screen. Assuming that your viewport is w
pixels wide and h
pixels high, you would do the following:
pCamera->setAspectRatio( (float) w / h );
This keeps the height of your view window constant and adjusts the width accordingly, thus keeping the field of view constant. If you prefer to keep the width constant, call the following instead:
bool keepWidth = true; pCamera->setAspectRatio( (float) w / h, keepWidth );
The zoom()
method used earlier automatically fits the near and far clipping plane as well as the target distance. You can switch this automation off and set these values explicitly as follows:
pCamera->setAutoClipPlanes( false ); pCamera->setNearDistance( near ); pCamera->setTargetDistance( targ ); pCamera->setFarDistance( far );
Keep in mind, here, that all distance values are positive, near
is less than far
, and targ
is somewhere in between.
Setting Position and Window Size Explicitly
The zoom()
method also automatically adjusts the position and the window size. Again, you can switch this automation off and set these values explicitly as follows:
pCamera->setPosition( pos );
pCamera->setWindowSize( size );
The first snippet sets the camera at the given position. No other setting of the camera is changed. The second snippet makes the view window extend from the target point out to the right and left by size[0]/2, and out to the top an bottom by size[1]/2. Note that the window size is given in world coordinate units. Setting the window size in this way might change both the field of view and the aspect ratio. Use zoom operations to keep these values constant.
Defining an Asymmetric Frustum
The previous examples always results in a symmetric view frustum. In some cases, such as for multi-screen solutions, you might need an asymmetric frustum. This can be achieved as follows:
pCamera->setWindowRegion( lowerLeft, upperRight );
This function sets the part of the view window to be used for the view frustum. By default, lowerLeft is (0,0) and upperRight is (1,1), which means that the whole view window is used.
To use just a part of the view window, set these values to the desired fractions. For example, to adjust the n times m cameras of a regular n x m multi-screen solution, call the following for the camera corresponding to the jth screen in the ith row:
pCamera->setWindowRegion( Vec2f( (float)i/n, (float)j/m ), Vec2f( (float)(i+1)/n, (float)(j+1)/m ) );
This defines the relative part of the view window and no other member function of the camera changes it. For this reason, as long as the desired part of the window doesn't change, you need to set this only once.