Canvas 3d JS Library

WebGL made easy!
  • rss
  • What is C3DL?
  • Download
  • Tutorials
    • Tutorial #1: WebGL Browsers
    • Tutorial #2: A simple scene
    • Tutorial #3: Callback
    • Tutorial #4: Models
    • Tutorial #5: Light effects
    • Tutorial #6: Picking
    • Tutorial #7: Materials
    • Tutorial #8: Particle Systems
    • Tutorial #9: Camera Basics
    • Tutorial #10: Advanced FreeCamera
    • Tutorial #11: OrbitCamera
    • Tutorial #12: Advanced Camera Functions
  • Development News
  • Documentation
  • Community
  • Resources
  • Contact
  • About

Tutorial #10: Advanced FreeCamera

In this tutorial we’ll take a look at more advanced uses of a FreeCamera. We’ve already seen how to add a camera to a scene, how to move it (to a specific place), how to rotate it and how to switch to another camera. Now we’ll be expanding on by taking rotations into account so we can move based on where the camera is pointing, not just the global axes.

First we’ll need another html page, very similar to all the others:

The HTML document

Inside the mydemo folder, start by creating a simple html page.

<html>
    <head>
        <title>Canvas3D tutorial #10: Advanced FreeCamera</title>
        <script type="application/javascript" src="../canvas3dapi/c3dapi.js" ></script>
        <script type="application/javascript" src="tutorial10.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

The first thing we’re going to do is move the camera according to it’s own axes, not those of the scene. This change is surprisingly simple. When calling cam.setPosition, instead of manipulating the coordinates directly like we did in tutorial #9, we’ll take a unit vector (a vector with a length of one) that represents one of the camera’s axes (left, up or forward) and use c3dl.multiplyVector to multiply that vector by the amount we want to move, giving us a vector representing movement in the desired direction by the amount we want. If we want to move in one of the other directions (i.e. down instead of up). just pass a negative value as the second argument to multiplyVector. The result of that multiplication is a vector representing movement along the axis you chose, translated into global coordinates. Once you have that you can just add it to the current position of the camera (very similar to what we did in tutorial #9).

// Tutorial 10

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 released
            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);//yaw 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);//yaw 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();
        var mov = [0,0,0];
        switch(event.keyCode) {//determine the key released
            case 65://a key
            case 37://left arrow
                mov = c3dl.multiplyVector(cam.getLeft(),10,mov);//move the camera left
            break;
            case 68://d key
            case 39://right arrow
                mov = c3dl.multiplyVector(cam.getLeft(),-10,mov);//move the camera right
            break;
            case 83://s key
                mov = c3dl.multiplyVector(cam.getUp(),-10,mov);//move the camera down
            break;
            case 40://down arrow
                mov = c3dl.multiplyVector(cam.getDir(),-10,mov); //move the camera 'back' (towards the user)
            break;
            case 87://w key
                mov = c3dl.multiplyVector(cam.getUp(),10,mov); //move the camera up
            break;
            case 38://up arrow
                mov = c3dl.multiplyVector(cam.getDir(),10,mov);//move the camera 'forward' (into the scene)
            break;
        }
        cam.setPosition([pos[0]+mov[0],pos[1]+mov[1],pos[2]+mov[2]]);
    }
}

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();
 }
}

Now you have a camera that the user can move about the scene, provided they are willing to repeatedly press a key for a tiny increment of movement. An alternative to this is to use setLinearVel and setAngularVel so that the camera is automatically moved or rotated by a small amount each time the scene is updated, allowing the user to hold the key(s) for as long as they want that movement (or rotation) to continue. For this example we’ll make use of keyboard callbacks for when the key is pressed down and when it is released. Movement (or rotation) will start when the user presses a key and will stop when that key is released. Place the following code in tutorial10b.js and update the script tag in tutorial10.html accordingly:

// Tutorial 10b

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 stop rotating in that direction,
// if shift is not being held, the camera will stop moving.
function up(event){//a key is released
    var cam = scn.getCamera();
    var vel;
    if(event.shiftKey) {
        switch(event.keyCode) {//determine the key released, if it is any of the angular velocity keys, set angular velocity to 0
            case 65://a key
            case 68://d key
            case 37://left arrow
            case 39://right arrow
            case 83://s key
            case 40://down arrow
            case 87://w key
            case 38://up arrow
                cam.setAngularVel([0,0,0]);//stop rolling
            break;
        }
    }
    else {
        var pos = cam.getPosition();
        switch(event.keyCode) {//determine the key released, if it is one of the linear velocity keys, set linear velocity to 0
            case 65://a key
            case 37://left arrow
            case 68://d key
            case 39://right arrow
            case 83://s key
            case 40://down arrow
            case 87://w key
            case 38://up arrow
                cam.setLinearVel([0,0,0]);
            break;
            case 16://shift key
                cam.setAngularVel([0,0,0]);
            break;
        }
    }
}

//This function is going to be called when the user presses a key.
// If shift is currently pressed, the camera will start rotating in the chosen direction,
// if shift is not being held, the camera will move.
function down(event){//a key is released
    var cam = scn.getCamera();
    if(event.shiftKey) {
        switch(event.keyCode) {//determine the key pressed
            case 65://a key
                cam.setAngularVel([0,0,-0.001]);//roll the camera left
                break;
            case 37://left arrow
                cam.setAngularVel([0,0.001,0]);//yaw left
                break;
            case 68://d key
                cam.setAngularVel([0,0,0.001]);//roll the camera right
                break;
            case 39://right arrow
                cam.setAngularVel([0,-0.001,0]);//yaw right
                break;
            case 83://s key
            case 40://down arrow
                cam.setAngularVel([0.001,0,0]);//pitch down
            break;
            case 87://w key
            case 38://up arrow
                cam.setAngularVel([-0.001,0,0]);//pitch up
            break;
        }
    }
    else {
        var mov = [0,0,0];
        switch(event.keyCode) {//deterime the key pressed
            case 65://a key
            case 37://left arrow
                mov = c3dl.multiplyVector(cam.getLeft(),0.1,mov);
            break;
            case 68://d key
            case 39://right arrow
                mov = c3dl.multiplyVector(cam.getLeft(),-0.1,mov);
            break;
            case 83://s key
                mov = c3dl.multiplyVector(cam.getUp(),-0.1,mov);//move the camera down
            break;
            case 40://down arrow
                mov = c3dl.multiplyVector(cam.getDir(),-0.1,mov); //move the camera 'back' (towards the user)
            break;
            case 87://w key
                mov = c3dl.multiplyVector(cam.getUp(),0.1,mov); //move the camera up
            break;
            case 38://up arrow
                mov = c3dl.multiplyVector(cam.getDir(),0.1,mov);//move the camera 'forward' (into the scene)
            break;
            case 16://shift key, stop linear movement
                cam.setLinearVel([0,0,0]);
            break;
        }
        cam.setLinearVel(mov);
    }
}

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,down);

  scn.startScene();
 }
}

Now you have a camera that the user can use to navigate the scene. You’ll notice that the values used in setting the linear and angular velocities are quite small. They will vary depending on the scale of your objects/scene and how fast/fine you want movement to be. There are some weaknesses to this code, notably that when you press a new button before releasing the old one it forgets the old movement and only uses the new linear/angular velocity. This could be overcome by using getLinearVel and getAngularVel to find out what the camera is currently doing, and adding the new movement to that.

Videos

Demos

  • Asteroids-3D
  • RTS Prototype
  • Particle Systems Demo
  • Cross-Browser Orbiter
  • Mocap Demo With Spheres
  • Google Maps-3D

C3DL Development News

A spec change that keeps coming back to haunt me

At some point, the way firefox handles keyboard events changed. I’m not sure exactly when it happened, all I know is that it broke how I was dealing with keyboard interaction on almost every demo I’ve written (for example,the mocap demo and MotionView). When I wrote the demos, the keydown event would be fired once, [...]

Release 2.2

The 2.2 Release of the Canvas 3D Library includes a number of new features, updates to old features and fixes for several bugs along with the requisite changes to meet the evolving WebGL spec. Some of the things included (in no particular order) are: Better picking code. The ability to swap textures as a scene [...]

Tutorials

  • Tutorial #1: WebGL Browsers
  • Tutorial #2: A simple scene
  • Tutorial #3: Callback
  • Tutorial #4: Models
  • Tutorial #5: Light effects
  • Tutorial #6: Picking
  • Tutorial #7: Materials
  • Tutorial #8: Particle Systems
  • Tutorial #9: Camera Basics
    • Tutorial9-YawPitchRoll
  • Tutorial #10: Advanced FreeCamera
  • Tutorial #11: OrbitCamera
  • Tutorial #12: Advanced Camera Functions

Documentation

Archives

Archives

C3DL Development News

Recent Comments

  • June 2011
  • March 2011
  • October 2010
  • July 2010
  • April 2010
  • March 2010
  • February 2010
  • January 2010
  • December 2009
  • November 2009
  • October 2009
  • September 2009
  • July 2009
  • June 2009
  • May 2009
  • April 2009
  • March 2009
  • February 2009
  • January 2009
  • December 2008
  • November 2008
  • October 2008
  • September 2008
  • August 2008
  • July 2008
  • June 2008
  • May 2008
  • April 2008
  • March 2008
  • February 2008
  • January 2008
  • December 2007
  • A spec change that keeps coming back to haunt me
  • Release 2.2
  • 2.1 Release and things to come
  • Level Up! An Open Web Game Jam
  • Site moved!
  • SceneCreator0.3
  • WWW2010 in Raleigh
  • Motionview
  • On the train to Mountainview
  • C3DL 2.0-WebGL and beyond
  • That depends on what... - peter
  • This application is ... - Haisens
  • I think that example... - peter
  • The above links are ... - Atash
  • Hi there, just wante... - Patrick H. Lauke
  • Firefox 4 was releas... - Cathy Leung
  • In order to access l... - peter
  • I am not able to dis... - preksha
  • "JavaScript can’t di... - Joe Hocking
  • I should point out t... - peter



Canvas 3d JS Library

©2007- 2010 Canvas 3d JS Library

Disclaimer: This website is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 2.5 Canada License.
The Canvas 3d JS Library and Demos found on this website are licenced under the MIT License

Creative Commons License