Tutorial #9: Camera Basics
This tutorial shows how to create and use cameras in our scenes along with basic camera movement. In previous tutorials we’ve looked at models in a scene and some things that we can do to make them rotate or look different, but how we see them hasn’t been an issue. We had code for the camera in place, but haven’t paid much attention to it. In the next few tutorials, we’ll take a look at how the cameras work, and what we can do with them.
Having a camera set in one specific place may be useful for some applications, but we’ll often want the ability to change cameras, or move a camera, or to change how a camera sees the scene (which we’ll deal with in another tutorial).
In past tutorials we included this code (or something like it)// Create a camera var cam = new c3dl.FreeCamera(); // Place the camera. // WebGL uses a right handed co-ordinate system. // move 200 to the right // move 300 up // move 500 units out cam.setPosition(new Array(200.0, 300.0, 500.0)); // Point the camera. // Here it is pointed at the same location as // the duck so the duck will appear centered. cam.setLookAtPoint(new Array(0.0, 0.0, 0.0)); // Add the camera to the scene scn.setCamera(cam);
This created a single ‘FreeCamera’ for us to use (there is another type of camera that you can use called an Orbitcamera, but we’ll see that in another tutorial). You’ll notice it has a position (set through the setPosition() function) that specifies where it is in the scene, just like any other object. It also has a direction in which it is pointing (allowing us to see a particular portion of the scene). While you do not set the direction directly, it is done indirectly by using setLookAtPoint. The setLookAtPoint function allows us to specify what point the camera should be looking directly at, without having to calculate the direction ourselves. In the snippet of code above, the camera is set to look at {0,0,0} where we’ve placed a duck model in the other tutorials, but this could just as easily be set to look at any other point. Finally, we added the camera to the scene using scn.setCamera(cam). This is the minimum code required to have a camera in our scene.
Of course we’ll want something to look at, so we’re going to start with a scene almost identical to tutorial #2, but we’re going to call it tutorial #9 (which means we’ll need a new html file and js file).
The HTML document
Inside the mydemo folder, start by creating a simple html page.<html>
<head>
<title>Canvas3D tutorial #9: Camera Basics</title>
<script type="application/javascript" src="../canvas3dapi/c3dapi.js" ></script>
<script type="application/javascript" src="tutorial9.js"></script>
</head>
<body>
<!-- Add a canvas element to the page. It is scripted by using its id -->
<canvas id="tutorial" style="border: 2px solid blue" width="500" height="500"></canvas>
</body>
</html>
The JavaScript Code
Place the following code in a file called tutorial9.js The only thing we’ve changed from tutorial 2 is to remove the line of code that caused the duck to spin (we’ll be moving the camera so we want a nice constant reference).// Tutorial 9: the javascript
c3dl.addMainCallBack(canvasMain, "tutorial");
c3dl.addModel("duck.dae");
var duck;
function canvasMain(canvasName){
scn = new c3dl.Scene();
scn.setCanvasTag(canvasName);
renderer = new c3dl.WebGL();
renderer.createRenderer(this);
scn.setRenderer(renderer);
scn.init(canvasName);
if(renderer.isReady() )
{
duck = new c3dl.Collada();
duck.init("duck.dae");
duck.setTexture("duck.png");
scn.addObjectToScene(duck);
var cam = new c3dl.FreeCamera();
cam.setPosition(new Array(200.0, 300.0, 500.0));
cam.setLookAtPoint(new Array(0.0, 0.0, 0.0));
scn.setCamera(cam);
scn.startScene();
}
}
The first thing we’re going to do is add a second camera so that we can view the scene from another angle. To do this we’ll need to:
- add a few lines of code to create another camera.
- create a function that will switch which camera is in use
- Add an event handler so that function gets called when the user presses a key (the space bar)
// Tutorial 9: the javascript
c3dl.addMainCallBack(canvasMain, "tutorial");
c3dl.addModel("duck.dae");
var cam; ///The cameras are going to be global so that we can access them from the event handler
var otherCam;
//This function is going to be called when the user releases a key.
// If the key they release is the space bar (keyCode 32), the camera currently
// in use by the scene will switch.
function up(event){
switch(event.keyCode) {//deterime the key
case 32://space bar
if(cam == scn.getCamera()) {
scn.setCamera(otherCam);
}
else {
scn.setCamera(cam);
}
break;
}
}
function canvasMain(canvasName){
scn = new c3dl.Scene();
scn.setCanvasTag(canvasName);
renderer = new c3dl.WebGL();
renderer.createRenderer(this);
scn.setRenderer(renderer);
scn.init(canvasName);
if(renderer.isReady() )
{
var duck = new c3dl.Collada();
duck.init("duck.dae");
duck.setTexture("duck.png");
scn.addObjectToScene(duck);
cam = new c3dl.FreeCamera();
cam.setPosition(new Array(200.0, 300.0, 500.0));
cam.setLookAtPoint(new Array(0.0, 0.0, 0.0));
scn.setCamera(cam);
//create a second camera, looking at the duck from a different direction.
otherCam = new c3dl.FreeCamera();
otherCam.setPosition(new Array(200.0, 0.0, 0.0));
otherCam.setLookAtPoint(new Array(0.0, 0.0, 0.0));
//let the scene know which function to call when a key is pressed (down)
//and released (up).
scn.setKeyboardCallback(up);
scn.startScene();
}
}
This same thing could easily have been accomplished by just moving the one camera using setPosition and setLookAtPoint, but I wanted to introduce the possibility of switching cameras, as we’re going to use that later to switch between different types of cameras.
There are several fairly simple things we can do with the camera to make it more interactive and useful, such as moving it around or rotating it on various axes. To do this we’ll create another js file called tutorial9b.js (which will require you to change the script tag in the html file to reflect this), then we’ll need to add some code to the up function to move or rotate the camera when specific keys are released.
// Tutorial 9b
c3dl.addMainCallBack(canvasMain, "tutorial");
c3dl.addModel("duck.dae");
//This function is going to be called when the user releases a key.
// If shift is currently pressed, the camera will rotate a bit in the chosen direction,
// if shift is not being held, the camera will move.
function up(event){//a key is released
var cam = scn.getCamera();
if(event.shiftKey) {
switch(event.keyCode) {//determine the key pressed
case 65://a key
cam.roll(-Math.PI * 0.025);//tilt to the left
break;
case 37://left arrow
cam.yaw(Math.PI * 0.025);//rotate to the left
break;
case 68://d key
cam.roll(Math.PI * 0.025);//tilt to the right
break;
case 39://right arrow
cam.yaw(-Math.PI * 0.025);//rotate to the right
break;
case 83://s key
case 40://down arrow
cam.pitch(Math.PI * 0.025);//look down
break;
case 87://w key
case 38://up arrow
cam.pitch(-Math.PI * 0.025);//look up
break;
}
}
else {
var pos = cam.getPosition();
switch(event.keyCode) {//deterime the key pressed
case 65://a key
case 37://left arrow
cam.setPosition([pos[0]-10,pos[1],pos[2]]);//move - along the X axis
break;
case 68://d key
case 39://right arrow
cam.setPosition([pos[0]+10,pos[1],pos[2]]);//more + along the X axis
break;
case 83://s key
cam.setPosition([pos[0],pos[1]-10,pos[2]]);//move - along the Y axis (down)
break;
case 40://down arrow
cam.setPosition([pos[0],pos[1],pos[2]+10]);//move + on the Z axis
break;
case 87://w key
cam.setPosition([pos[0],pos[1]+10,pos[2]]);//move + on the Y axis (up)
break;
case 38://up arrow
cam.setPosition([pos[0],pos[1],pos[2]-10]);//move - on the Z axis
break;
}
}
}
function canvasMain(canvasName){
scn = new c3dl.Scene();
scn.setCanvasTag(canvasName);
renderer = new c3dl.WebGL();
renderer.createRenderer(this);
scn.setRenderer(renderer);
scn.init(canvasName);
if(renderer.isReady() )
{
var duck = new c3dl.Collada();
duck.init("duck.dae");
duck.setTexture("duck.png");
duck.yaw(-Math.PI * 0.5); //rotate the duck to look up the Z axis
scn.addObjectToScene(duck);
var cam = new c3dl.FreeCamera();
cam.setPosition(new Array(0, 0, 600));
cam.setLookAtPoint(new Array(0.0, 0.0, 0.0));
scn.setCamera(cam);
//let the scene know which function to call when a key is pressed (down)
//and released (up).
scn.setKeyboardCallback(up);
scn.startScene();
}
}
For rotation we use three separate functions. Pitch, yaw and roll each rotate the camera around a different axis. If you are not sure which one is which, take a look at this page.
Note that these functions expect to receive values in radians (2 * PI radians is 360 degrees), but if you aren’t comfortable with converting between radians and degrees yourself, there are functions to take care of that for you (radiansToDegrees and degreesToRadians).
There are no similar functions for movement (nothing to specifically move you ‘left’), but using getPosition and setPosition will allow you to find out where the camera is, then move it to somewhere else.
This works, but if you play with the page a bit (See the comments in the code to determine which key does what) you’ll notice that the camera movement occurs along the scene’s axes, not the camera’s (that is, when you move the camera +5 on the x axis, it moves a specific direction in the scene, regardless of how the camera has been rotated). We can move based on how the camera has been rotated, but that’s a little more complicated. We can also rotate around an axis other than the pre-defined X, Y and Z. We’ll see both of these in the next tutorial.
