Home   Donators   Contact Us       

<< Previous Tutorial     Next Tutorial >>

Tutorial 14 - Lights, camera, action!


Similar to models, cameras have a position and orientation in your scene. The image below illustrates what a very basic scene might look like with two cameras pointing towards the same model. Each camera renders a different 2D view to the computer screen, depending on its rotation and position in 3D space.

Let's take a closer look at the "virtual" camera. You'll notice in the image below, our virtual camera consists of two primary components. The actual camera that is responsible for capturing our scene, and a dolly that assists with the movement dynamics of the camera in 3D space.

The following actions can be performed with our camera object:

Dolly In
Move the dolly and camera forward in the direction that the dolly is facing.
 Dolly Out
Move the dolly and camera backward, relative to the direction that the dolly is facing.
Truck Left
Move the dolly and camera left, relative to the orientation of the dolly. In 3D gaming this action is better known as strafe left.
 Truck Right
Move the dolly and camera right, relative to the orientation of the dolly. In 3D gaming this action is better known as strafe right.
Pedestal Up
Move the dolly and camera upward, relative to the orientation of the dolly.
    Pedestal Down
Move the dolly and camera downward, relative to the orientation of the dolly.
Turn Dolly
Turn the forward direction of the dolly left or right. This action is commonly used when moving your camera around in 3D space from a first-person perspective.
 Tilt Dolly
Tilt the forward direction of the dolly up or down.
Roll Dolly
Rotate the dolly around its forward direction.
Pan Camera
Turn the "look-at" direction of the camera left or right.
 Tilt Camera
Rotate the "look-at" direction of the camera up or down.
Roll Camera
Rotate the camera view left or right around its "look-at" direction axis (e.g. roll the camera 180° to view the scene upside down).
 Reset Camera
Realign the "look-at" direction of the camera with the dolly's forward direction.

Using the above actions or even just a subset of the actions, you can easily implement advanced viewing algorithms in your 3D application. It might not always be necessary to use all the actions. For example, in a very basic first person shooter game you might only need the dolly-in, dolly-out and turn-dolly actions. For more advanced 3D applications such as interactive engineering simulations you might have to use all the available camera actions.

The creative freedom with regard to how you decide to use the camera object in your 3D scenes is left at your discretion. You could also implement your own customized camera actions by directly manipulating the dolly and camera quaternions that defines the rotation of the camera. For more information on quaternions, have a look at Tutorial 11 - Quaternions.

Tutorial Steps
Tutorial created with Real Studio 2011 Release 4.3.
1. Open Real Studio.
2. Choose the "Desktop" project template.
3. Tick the MaximizeButton property of Window1.
4. Add an OpenGLSurface control to Window1.
5. Resize and position OpenGLSurface1 to fill the whole form.
6. Tick the LockRight and LockBottom properties of OpenGLSurface1.
7. Save your project.
8. Download the following files and save them next to your project file:
9. Import the classes and modules into your new project file. (Select File > Import... from the main menu)
10. Add a Timer control to Window1.
11. Change the Period property of Timer1 from 1000 to 100.
12. Add a property named "FrameIndex" of type Integer to Window1.
13. Add a property named "Scene" of type R3Scene to Window1.
14. Add the following code to the Action event of Timer1:
Dim i As Integer ' loop variable
Dim hand As R3Model ' hand model 
Dim cube As R3Model ' cube model

hand = Scene.Model(0) ' get the hand model
cube = Scene.Model(1) ' get the cube model

' rotate the cube

cube.Rotation.Rotate(1, 3, 2) ' yaw rotation

' are we within the first 10 frames?
if FrameIndex < 10 then
  ' yes, so close the hand

  ' close the pinky, index, middle and ring fingers
  for i = 0 to 3
    hand.RootJoint.Child(i).Rotation.Rotate(5, 0, 0)
    hand.RootJoint.Child(i).Child(0).Rotation.Rotate(6, 0, 0)
    hand.RootJoint.Child(i).Child(0).Child(0).Rotation.Rotate(7, 0, 0)
  next i

  ' close the thumb

  hand.RootJoint.Child(4).Rotation.Rotate(7, 0, 0)
  hand.RootJoint.Child(4).Rotation.Rotate(0, -2.2, 0)
  hand.RootJoint.Child(4).Child(0).Rotation.Rotate(8, 0, 0)
  hand.RootJoint.Child(4).Child(0).Rotation.Rotate(0, -2.2, 0)

  ' no, so are we in the second 10 frames?
  elseif FrameIndex < 20 then
    ' yes, so open the hand

    ' open the pinky, index, middle and ring fingers
    for i = 0 to 3
      hand.RootJoint.Child(i).Rotation.Rotate(-5, 0, 0)
      hand.RootJoint.Child(i).Child(0).Rotation.Rotate(-6, 0, 0)
      hand.RootJoint.Child(i).Child(0).Child(0).Rotation.Rotate(-7, 0, 0)
    next i

    ' open the thumb

    hand.RootJoint.Child(4).Rotation.Rotate(0, 2.2, 0)
    hand.RootJoint.Child(4).Rotation.Rotate(-7, 0, 0)
    hand.RootJoint.Child(4).Child(0).Rotation.Rotate(0, 2.2, 0)
    hand.RootJoint.Child(4).Child(0).Rotation.Rotate(-8, 0, 0)

  end if

  FrameIndex = FrameIndex + 1 ' go to next frame

  ' are we at the end of the frames?
  if FrameIndex = 20 then
    FrameIndex = 0 ' yes, so go back to the first frame
  end if

  OpenGLSurface1.Refresh ' render OpenGL surface
15. Add the following code to the Open event of Window1:
Dim model As R3Model ' tempory model object
Dim light As R3LightSource  ' light source
Dim cam As R3Camera

me.Maximize ' maximize the window
me.MouseCursor = REALbasic.System.Cursors.StandardPointer ' set mouse cursor

' instantiate the Scene object

Scene = new R3Scene
Scene.BackgroundColor.SetValue(1, 1, 1) ' white background

' add light source

light = new R3LightSource
light.Position.SetValue(1, 0, 3)
Scene.LightSource.Append light

' add cameras

cam = new R3Camera
cam.DollyOut 30 ' move back so that we can get the model in our view
Scene.Camera.Append cam

Scene.ActiveCamera = 0 ' set the index of the active camera

' instantiate a new hand model

model = R3_Model_Hand
Scene.Model.Append model ' add the model to our scene

' instantiate a new cube model

model = R3_Model_Cube
model.Scale.SetValue(1.2, 1.2, 1.2) ' enlarge cube
model.SetColor(1, 0, 0) ' change the color of the cube to red
model.Position.Translate(0.7, -2, 3) ' move the cube closer to us
Scene.Model.Append model ' add the cube to our scene

FrameIndex = 0 ' starting frame is 0

Timer1.Enabled = true ' enable the animation timer
16. Add the following code to the Paint event of Window1:
OpenGLSurface1.Render ' refresh the OpenGL surface
17. Add the following code to the KeyDown event of Window1:
' do we have a camera selected?
if Scene.ActiveCamera >= 0 then

  ' yes, so apply camera action based on key press

  select case Asc(Key)
  case 11 ' page up
    Scene.Camera(Scene.ActiveCamera).PedestalUp(1) ' active camera: pedestal up
  case 12 ' page down
    Scene.Camera(Scene.ActiveCamera).PedestalDown(1) ' active camera: pedestal down
  case 28 ' left arrow
    Scene.Camera(Scene.ActiveCamera).TurnDolly(-9) ' active camera: turn dolly left (camera locked)
  case 29 ' right arrow
    Scene.Camera(Scene.ActiveCamera).TurnDolly(9) ' active camera: turn dolly right (camera locked)
  case 30 ' up arrow
    Scene.Camera(Scene.ActiveCamera).DollyIn(1) ' active camera: dolly in
  case 31 ' down arrow
    Scene.Camera(Scene.ActiveCamera).DollyOut(1) ' active camera: dolly out
  case 32 ' space
    Scene.Camera(Scene.ActiveCamera).ResetCamera ' active camera: reset camera
  case 65, 97 ' A, a
    Scene.Camera(Scene.ActiveCamera).TiltCamera(-9) ' active camera: tilt camera up
  case 67, 99 ' C, c
    Scene.Camera(Scene.ActiveCamera).RollDolly(9) ' active camera: roll dolly left (camera locked)
  case 68, 100 ' D, d
    Scene.Camera(Scene.ActiveCamera).TiltDolly(-9) ' active camera: tilt dolly up (camera locked)
  case 69, 101 ' E, e
    Scene.Camera(Scene.ActiveCamera).TruckLeft(1) ' active camera: truck left
  case 70, 102 ' F, f
    Scene.Camera(Scene.ActiveCamera).TiltDolly(9) ' active camera: tilt dolly down (camera locked)
  case 81, 113 ' Q, q
    Scene.Camera(Scene.ActiveCamera).PanCamera(-9) ' active camera: pan camera left
  case 82, 114 ' R, r
    Scene.Camera(Scene.ActiveCamera).TruckRight(1) ' active camera: truck right
  case 83, 115 ' S, s
    Scene.Camera(Scene.ActiveCamera).TiltCamera(9) ' active camera: tilt camera down
  case 86, 118 ' V, v
    Scene.Camera(Scene.ActiveCamera).RollDolly(-9) ' active camera: roll dolly right (camera locked)
  case 87, 119 ' W, w
    Scene.Camera(Scene.ActiveCamera).PanCamera(9) ' active camera: pan camera right
  case 88, 120 ' X, x
    Scene.Camera(Scene.ActiveCamera).RollCamera(-9) ' active camera: roll camera right
  case 90, 122 ' Z, z
    Scene.Camera(Scene.ActiveCamera).RollCamera(9) ' active camera: roll camera left
  end select

  OpenGLSurface1.Render ' refresh OpenGL surface

end if
18. Add the following code to the Open event of OpenGLSurface1:
R3_OGLInitialize ' initalize OpenGL environment
19. Add the following code to the Resized event of OpenGLSurface1:
' set the viewport rectangle

OpenGL.glViewport 0, 0, OpenGLSurface1.Width, OpenGLSurface1.Height

' set up the perspective projection settings

OpenGL.glMatrixMode OpenGL.GL_PROJECTION
OpenGL.gluPerspective 60.0, OpenGLSurface1.Width / OpenGLSurface1.Height, 1, 100.0

' select and reset the modelview matrix

OpenGL.glMatrixMode OpenGL.GL_MODELVIEW
20. Add the following code to the Render event of OpenGLSurface1:
' is the scene object instantiated?
if Scene <> nil then

  ' render the modal normally
  R3_OGLRenderScene Scene

end if
21. Save and run the project.
22. Use the following keys to move the camera around in 3D space:
UP ARROW   Dolly In
DOWN ARROW   Dolly Out
E   Truck Left
R   Truck Right
PAGE UP   Pedestal Up
PAGE DOWN   Pedestal Down
LEFT ARROW   Turn Dolly Left
RIGHT ARROW   Turn Dolly Right
D   Tilt Dolly Up
F   Tilt Dolly Down
C   Roll Dolly Left
V   Roll Dolly Right
Q   Pan Camera Left
W   Pan Camera Right
A   Tilt Camera Up
S   Tilt Camera Down
Z   Roll Camera Left
X   Roll Camera Right
SPACE   Reset Camera
Code Analysis

The new R3LightSource class is used to represent a light source. For more information about the attributes of light sources, have a look at Tutorial 4 - Switch on the lights. On line 15 to 17 in the Window1.Open event we instantiate and add a light source to our scene. Note that only the first eight light sources in the Scene.LightSource() array will be used during the rendering of your scene, due to the maximum limit of allowed light sources set by OpenGL.

R3Camera has three important properties, namely CameraRotation a quaternion, DollyRotation another quaternion and DollyPosition a vector. DollyPosition is used to set the position of the camera in 3D space. DollyRotation defines the rotation of the dolly and 3D space, and CameraRotation defines the rotation of the camera mounted on the dolly. The camera and dolly can be rotated independently from each other, making it possible to implement any imaginable camera action.

If you study the Window1.KeyDown event, you will notice how a camera object can be used to delegate camera actions. On line 21 to 23 in the Window1.Open event we instantiate a new camera object for our scene. On line 25 we set the new camera object as the active camera for our scene. You can easily add multiple cameras to your scene, and switch between then by simply changing the index stored in the Scene.ActiveCamera property.

Run the tutorial project and experiment with the different camera movement actions. The better you understand the different action types, the easier it will be to develop advanced camera movement routines for your games, engineering simulations or any other 3D applications.

Project Downloads

<< Previous Tutorial     Next Tutorial >>

All the content on Real 3D Tutorials, with the exception of the SyntaxHighlighter which is licensed under the MIT License, is provided to the public domain and everyone is free to use, modify, republish, sell or give away this work without prior consent from anybody. Content is provided without warranty of any kind. Under no circumstances shall the author(s) or contributor(s) be liable for damages resulting directly or indirectly from the use or non-use of the content.
Should you find the content useful and would like to make a contribution, you can show your support by making a donation.