In the last tutorial, I promised to show to use heightmaps. While playing around with that, I realised that the camera set up to now is inadequate to navigate through the scene. This is not quite a trivial operation, so have decided to insert a tutorial on setting up the camera here.

The new controls for the camera, will rotate the world view as you move around the screen, much like a first person shooter. Using the WASD keys, you can go forwards and back, and left and right. this allows us to simulate “flying” around our scene.

First off we have added quite a bit of global variables

var g_lastMouseX = 0;
var g_lastMouseY = 0;
var g_mouseXDelta = 0;
var g_mouseYDelta = 0;
var g_rotationDelta = 0.002;
var g_translationDelta = 0.2;
var g_mouseLocked = false;
var g_lookingDir = [0, 0, 0];

First, on mouse click, we set a flag saying that we are moving our view. This is because we don’t want the screen looking in any direction unless we want it to. So to start moving the view, you just need to click once. So in the **mousedown** function we add.

g_mouseLocked = !g_mouseLocked

Most of the action happens in the **mouseMove** function. We get the mouse coordinates, and then if the screen is locked into drag mode, we apply the transformation to move the screen. How this is done, is we need to work out our view direction, which is the location of the target minus the location of the eye. We then apply the formula to rotate the vector an angle specified by **g_rotationDelta** multiplied by the distance moved since the last update. We then add back the location of the eye so that we can set the new target, and finally update the view with the new target location.

function mouseMove(e) {
g_lastMouseX = g_mouseX;
g_lastMouseY = g_mouseY;
g_mouseX = e.x;
g_mouseY = e.y;
g_mouseXDelta = g_mouseX - g_lastMouseX;
g_mouseYDelta = g_mouseY - g_lastMouseY;
if (g_mouseLocked) {
var viewDir = g_math.subVector(g_camera.target, g_camera.eye);
var rotatedViewDir = [];
rotatedViewDir[0] = (Math.cos(g_mouseXDelta * g_rotationDelta) * viewDir[0]) - (Math.sin(g_mouseXDelta * g_rotationDelta) * viewDir[2]);
rotatedViewDir[1] = viewDir[1];
rotatedViewDir[2] = (Math.cos(g_mouseXDelta * g_rotationDelta) * viewDir[2]) + (Math.sin(g_mouseXDelta * g_rotationDelta) * viewDir[0]);
viewDir = rotatedViewDir;
rotatedViewDir[0] = viewDir[0];
rotatedViewDir[1] = (Math.cos(g_mouseYDelta * g_rotationDelta * -1) * viewDir[1]) - (Math.sin(g_mouseYDelta * g_rotationDelta * -1) * viewDir[2]);
rotatedViewDir[2] = (Math.cos(g_mouseYDelta * g_rotationDelta * -1) * viewDir[2]) + (Math.sin(g_mouseYDelta * g_rotationDelta * -1) * viewDir[1]);
g_lookingDir = rotatedViewDir;
g_camera.target = g_math.addVector(rotatedViewDir, g_camera.eye);
g_viewInfo.drawContext.view = g_math.matrix4.lookAt(g_camera.eye,
g_camera.target,
[0, 1, 0]);
}
}

Next, the **keyPressedAction **function has been modified. Pressing ‘a’ or ‘d’ moves the camera left or right, and ‘w’ or ‘s’ moves the camera forwards and backwards. This takes into account the view direction, as we need to move in the correct manner, so we work out which way we are looking, apply the translation, and then add back the target, and finally setting the view. For the sideways translation, we need to update both the eye and target locations or else our view direction will drift.

function keyPressedAction(keyPressed, delta) {
var actionTaken = false;
switch(keyPressed) {
case 'a':
var eyeOriginal = g_camera.eye;
var targetOriginal = g_camera.target;
var viewEye = g_math.subVector(g_camera.eye, g_camera.target);
var viewTarget = g_math.subVector(g_camera.target, g_camera.eye);
viewEye = g_math.addVector([g_translationDelta * -1, 0, 0], viewEye);
viewTarget = g_math.addVector([g_translationDelta * -1, 0, 0], viewTarget);
g_camera.eye = g_math.addVector(viewEye, targetOriginal);
g_camera.target = g_math.addVector(viewTarget, eyeOriginal);
g_viewInfo.drawContext.view = g_math.matrix4.lookAt(g_camera.eye,
g_camera.target,
[0, 1, 0]);
actionTaken = true;
break;
case 'd':
var eyeOriginal = g_camera.eye;
var targetOriginal = g_camera.target;
var viewEye = g_math.subVector(g_camera.eye, g_camera.target);
var viewTarget = g_math.subVector(g_camera.target, g_camera.eye);
viewEye = g_math.addVector([g_translationDelta, 0, 0], viewEye);
viewTarget = g_math.addVector([g_translationDelta, 0, 0], viewTarget);
g_camera.eye = g_math.addVector(viewEye, targetOriginal);
g_camera.target = g_math.addVector(viewTarget, eyeOriginal);
g_viewInfo.drawContext.view = g_math.matrix4.lookAt(g_camera.eye,
g_camera.target,
[0, 1, 0]);
actionTaken = true;
break;
case 'w':
var view = g_math.subVector(g_camera.eye, g_camera.target);
view = g_math.mulScalarVector( 11 / 12, view);
g_camera.eye = g_math.addVector(view, g_camera.target);
g_viewInfo.drawContext.view = g_math.matrix4.lookAt(g_camera.eye,
g_camera.target,
[0, 1, 0]);
actionTaken = true;
break;
case 's':
var view = g_math.subVector(g_camera.eye, g_camera.target);
view = g_math.mulScalarVector( 13 / 12, view);
g_camera.eye = g_math.addVector(view, g_camera.target);
g_viewInfo.drawContext.view = g_math.matrix4.lookAt(g_camera.eye,
g_camera.target,
[0, 1, 0]);
actionTaken = true;
break;
}
return actionTaken;
}

I have also modified the output panel to display the location of the eye, and the target, so we can see what is happening behind the scenes.

continue reading…