Cameras

In this tutorial we will be expanding on the program in the Render loop tutorial to showcase the three types of cameras available in Irrlicht. The following topics are covered:

  1. Creating a project
  2. Camera scene node
  3. FPS camera and Maya camera
  4. FOV and View Frustum

The tutorial's code files and media files are installed along with Ginjo-Builder and can be accessed from the 'Project' window that is shown when the editor starts. This tutorial is called '04_Cameras' in the 'Tutorials' tab.

1. Creating a project

First we create a project and compiler options XML file. (See Render loop for a more detailed description of creating a project.)

  1. Create a new project through the Project menu.
  2. Right click on project's top level tree node named "New GBP(Unsaved)" and select Rename folder. Rename the folder to "Cameras".
  3. Save the project as "CamerasProject.gbp" from the Project menu.
  4. Add a new file to the project tree and save it as "tryCameras.gbc"
  5. Add a new file to the project tree and save it as "Cameras.xml". (The XML file must have the same name as the top level tree node.)

Open "Cameras.xml", and just like in Render loop add the <exe> and <startup> elements. We will also import the GB namespace so we don't have to type it out every time. (For the full list of XML tags see Compiler options.)

<?xml version="1.0" encoding="utf-8"?>
<root>
   <exe path=".\game.exe" />
   <startup name="tryCameras.main" />
   
   <ImportSymbols>
      <namespace name="GB"  />
   </ImportSymbols>
</root>

2. Camera scene node

Cameras are scene nodes and can be attached to any other scene node (just like models or lights). When a camera is attached to a parent scene node it will follow its parent's movement, rotation and so on. Cameras control what parts of the scene graph are rendered/seen by the user.

In our XML file we specified the startup function as "tryCameras.main". Double-click on "tryCameras.gbc" in the project tree to open it, and add the following function, called "main". (When you run your program this is the function where execution starts.) Initialize the Irrlicht 3D engine as in the Render loop tutorial. Add a camera scene node and set it's position in the scene and it's target property. The target is the point in the scene that the camera points towards.

function main(var:string cmdArgs[]) returns Int32
{
   var:gb.IrrlichtCreationParameters options=new gb.IrrlichtCreationParameters()
   //Without anti-aliasing our model edges would be jagged 
   options.AntiAliasing=255
   //Tell Irrlicht to use OpenGL for graphics
   options.DriverType=gb.video.DriverType.OpenGL
   //Turn off logging, we won't be using it for now
   options.LoggingLevel=gb.LogLevel.None
   
   var:gb.IrrlichtDevice engine = gb.IrrlichtDevice.CreateDevice(options)
   //Also set our window's title and make it resizeable
   engine.SetWindowCaption('Try the built in cameras')
   engine.SetWindowResizable(true)
   
   var:video.VideoDriver driver=engine.VideoDriver
   var:Scene.SceneManager smgr=engine.SceneManager

   //add camera 
   var:core.Vector3Df position=new gb.core.Vector3Df(0, 60, -180)
   var:core.Vector3Df lookat=new gb.core.Vector3Df(10, 10, 0)
   var:CameraSceneNode camera = smgr.AddCameraSceneNode()
   camera.Position=position
   camera.Target=lookat
}

Next we are going to add a non-animated model, set it's position, rotation and scale. In this tutorial we do not have any lights, thus the Lighting material flag of the model must be turned to false. (Otherwise the model will be completely black.) Add the following code to the main function after the camera's code:

//load model from relative path ..\media\GlobalHawk.obj 
var:scene.Mesh drone = smgr.GetMesh('..\media\GlobalHawk.obj')
//add model to scene 
var:Scene.MeshSceneNode droneNode = smgr.AddMeshSceneNode(drone)
if(!isNull(droneNode)){
    droneNode.Position=new gb.core.Vector3Df(0, 0, 0)
    droneNode.Rotation=new gb.core.Vector3Df(0, 180, 0)
    droneNode.Scale=new gb.core.Vector3Df(0.5, 0.5, 0.5)
    droneNode.SetMaterialFlag(gb.video.MaterialFlag.Lighting, false)
}

Finally, add a render loop exactly as in the first tutorial:

var:video.Color background=new video.Color(160, 160, 160)
while (engine.Run()){
   driver.BeginScene(video.ClearBufferFlag.All, background)
   smgr.DrawAll()
   driver.EndScene()
}

When you run the program you should see the drone model as below:

Note that you can use the IntelliDoc Symbol Info feature to look-up symbol types and definitions. The 'lightbulb' button on the toolbar looks-up the symbol type for the current cursor location and displays it in a tooltip. Pressing F1 also shows the tooltip.

3. FPS camera and Maya camera

A First Person Shooter (FPS) camera is controlled by the arrow keys on your keyboard and the movement of the mouse. (This camera will lock the mouse cursore in the center of the screen. You can quit the program by pressing ALT + F4) In your program replace smgr.AddCameraSceneNode() with smgr.AddCameraSceneNodeFPS(), and adjust the camera's field of view. The usual Field of View angle for FPS is 90 degrees. In the following code we will also hide the mouse cursor, as it is always at the center of the window when using an FPS camera. To quit the program press ALT+F4.

//var:CameraSceneNode camera = smgr.AddCameraSceneNode()
var:CameraSceneNode camera = smgr.AddCameraSceneNodeFPS(null, 100, 1)
camera.FOV=1.57079633     //FOV is in radians
device.CursorControl.Visible = false

A Maya camera behaves as the camera in the Maya graphics editor. It is controlled by holding down a mouse button while moving the mouse. Hold down the right mouse button to move sideways/up/down; hold down the left mouse button to rotate; hold down the center mouse button (or mouse wheel) and move your mouse to zoom in and out. In your program replace smgr.AddCameraSceneNode() with smgr.AddCameraSceneNodeMaya(), and also set the FOV based on the window height (see FOV in video games):

//var:CameraSceneNode camera = smgr.AddCameraSceneNode()
//var:CameraSceneNode camera = smgr.AddCameraSceneNodeFPS(null, 100, 1)
var:CameraSceneNode camera = smgr.AddCameraSceneNodeMaya()
camera.FOV=system.math.Atan((system.Convert.ToSingle(driver.ViewPort.Height)/2)/camera.NearValue)

4. FOV and View Frustum

Two important concepts when working with cameras are view frustum and field of view (FOV). The view frustum is used to control the volume of the 3d world that is rendered, a process called view frustum culling. The value of the near clipping plane of a camera can be set with its NearValue property, while the far clipping plane can be set with its FarValue property. (For an example of setting the far value see the Terrain tutorial.) Cameras in the real world have lens focal length values, measured in millimeters. The lens size determines the camera's focal point. The vertical Field of View of a camera can be set (in radians) using the FOV property of the camera.

Continuing with the Maya camera, resize the window horizontally. (The window was set as resizeable in section 2. using engine.SetWindowResizable(true)) As you can see the model stretches as the window is resized. Cameras do not automatically update their properties in response to window events. In fact, Irrlicht does not pass on Window events to your event handler. In the following code we modify the render loop from section 2. to check for change in the size of our window and adjust the camera's aspect ratio and FOV:

var:int32 prevWidth=driver.ViewPort.Width
var:int32 prevHeight=driver.ViewPort.Height
var:video.Color background=new video.Color(160, 160, 160)
while (engine.Run()){
   if(prevWidth!=driver.ViewPort.Width || prevHeight!=driver.ViewPort.Height){
      camera.AspectRatio= system.Convert.ToSingle(driver.ViewPort.Width)/ system.Convert.ToSingle(driver.ViewPort.Height)
      camera.FOV=system.math.Atan((system.Convert.ToSingle(driver.ViewPort.Height)/2)/camera.NearValue)

      prevWidth=driver.ViewPort.Width
      prevHeight=driver.ViewPort.Height
   }
   driver.BeginScene(video.ClearBufferFlag.All, background)
   smgr.DrawAll()
   driver.EndScene()
}