Thursday, June 21, 2012

OpenGL Camera Class Tutorial Part 3: View Volume and Viewport

Introduction

This tutorial covers setting the viewport and the view volume, or frustum. This can be considered as defining the perspective angle of the camera lens and the size of the screen to draw on.

Member Variables

The first thing I will do is define a bunch of member variables. These will maintain the state of viewport and view volume for the camera.
  1. Aspect: The aspect ratio of the display window (can be changed for stretching effects).
  2. Perspective: The vertical viewing angle, in degrees(not radians) that can be seen through the camera (can be changed for zooming effects).
  3. Near: The near plane distance away from the eye of the camera (must be greater than 0).
  4. Far: The far plane distance away from the eye of the camera (should be greater than the near distance).
  5. Top: The y coordinate the top of the near plane.
  6. Bottom: The y coordinate of the bottom of the near plane.
  7. Left: The x coordinate of the left of the near plane.
  8. Right: The x coordinate of the right of the near plane.
  9. Window Size: The size (in pixels) of the display window.
This is how I've defined them these value (with temporary defaults):
private float m_aspect = 320.0f / 240.0f;
private float m_perspective = 30.0f;
private float m_near = 1.0f;
private float m_far = 100.0f;
private float m_top = 1.0f;
private float m_bottom = -1.0f;
private float m_left = -1.0f;
private float m_right = 1.0f;
private Size m_windowSize = new Size(320,240);

View Volume

The easiest way to manipulate the viewing volume / viewing frustum is to define a SetViewVolume method. This method will take the window size, the near plane distance, the far plane distance, and perspective as parameters. These parameters will be broken down and stored into all of the variables defined above.

The first step is to save of the near and far plane values.

The top and bottom variables are derived from the perspective by taking the tangent of the perspective angle and multiplying it by the distance to the near plane.

The window size is stored and the aspect ratio is automatically extracted. Then the left and right variables are set based aspect ratio multiplied by the top and bottom variables.

Here is my implementation:
public void SetViewVolume(Size windowSize, float near, float far, float perspective)
{
  //Z-clipping
  m_near = near;
  m_far = far;

  //Top / bottom (based on perspective)
  m_perspective = perspective;
  m_top = (float)Math.Tan(perspective * Math.PI / 360.0f) * near;
  m_bottom = -m_top;

  //Left / right (based on aspect of windowSize)
  m_windowSize = windowSize;
  m_aspect = (float)windowSize.Width / (float)m_windowSize.Height;
  m_left = m_aspect * m_bottom;
  m_right = m_aspect * m_top;
}

Helper Methods

While the SetViewVolume method sets all of the camera's view volume variables, it is also nice to tweak just a few of them. Here are some helper functions and my uses for them:

  • SetPerspective: Sets the perspective. This is useful for zooming effects. Ever wonder how they make a sniper rifle zoom? This is one way.
  • SetClippingPlanes: Different types of scenes need very different clipping planes. An indoor scene might have a relatively close far plane while an outdoor scene might warrant a much further far plane.
  • SetWindowSize: For windowed applications especially, if the user resizes the window, this is a great way to scale to new window sizes.
Here are my implementations (they just re-use SetViewVolume):
public void SetPerspective(float angle)
{
  SetViewVolume(m_windowSize, m_near, m_far, angle);
}

public void SetClippingPlanes(float near, float far)
{
  SetViewVolume(m_windowSize, near, far, m_perspective);
}

public void SetWindowSize(Size windowSize)
{
  SetViewVolume(windowSize, m_near, m_far, m_perspective);
}

Viewport Loader

Up until now, everything I've written in these tutorials has been about representation of a camera in OpenGL. This next method is the first in a series of methods that actually allow me to use them in code. This simply calls the GLViewport function and should be used any time the screen size is changed or SetViewVolume is called (on application startup and before the first render, and any time the window is resized).
public void LoadViewport()
{
  GL.Viewport(new Point(0, 0), m_windowSize);
}

Conclusion

This tutorial completes all of the fields and variables that are needed to represent the FreeCamera. The only thing for me to do now is write some methods that allow me to use the camera in a scene by manipulating matrices. The next tutorial will focus on loading matrices and using the camera to help render a simple scene: Part 4.

No comments:

Post a Comment