How to use Matrix4.setLookAt to move the camera around the scene

Trying to make a first person camera controller in webGL. I'm trying to do this using the Matrix4.setLookAt () function, but I'm not sure how to calculate (and frankly, a bit vague about which parameters I need to change and when) how to navigate. As I currently implement for looking left and right, it seems to work fine at first, but as soon as the value approaches 1.0 or -1.0 for g_eyeX values, it starts to move the camera (in the negative x direction towards) from the cube to the scene. can't find much documentation on how to use this function to move the "camera" around a scene as most of it links to three.js (which I'm trying to find out how it works and doesn't want to use the library for it).Can anyone help or point me in the right direction? It would be very helpful

My code is below and this is what the setLookAt function does as an argument to Matrix4.setLookAt (eyeX, eyeY, eyeZ, atX, atY, atZ, upX, upY, upZ)

'eyeX, Y, Z' - Specify the position of the eye point 'atX, atY, atZ' - Specify the position of the eye point 'upX, upY, upZ' - Specify the upward direction in the scene

JS:

 // sceneWalker.js
    // modified from RotatingTriangle.js (c) 2012 matsuda
    // uses a non-indexed cube - 2 triangles per side - 36 vertices
    // Vertex shader program
    var VSHADER_SOURCE =
      'attribute vec4 a_Position;\n' +
      'uniform mat4 u_ViewMatrix;\n' +
      'uniform mat4 u_ModelMatrix;\n' +
      'uniform mat4 u_ProjMatrix;\n' +
      'void main() {\n' +
      '  gl_Position = u_ProjMatrix * u_ViewMatrix * u_ModelMatrix * a_Position;\n' +
      '}\n';

    // Fragment shader program
    var FSHADER_SOURCE =
      'void main() {\n' +
      '  gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' +
      '}\n';

    // Rotation angle (degrees/second)
    var ANGLE_STEP = 0.0;
    var MOVE_AMOUNT = 0.0;
    var g_eyeX = 0.0, g_eyeY = 0.0, g_eyeZ = 0.25; // Eye position
    var g_curX = 0.0, g_curZ = -3.0;

    function main() {
      // Retrieve <canvas> element
      var canvas = document.getElementById('webgl');

      // Get the rendering context for WebGL
      var gl = getWebGLContext(canvas);
      if (!gl) {
        console.log('Failed to get the rendering context for WebGL');
        return;
      }

      // Initialize shaders
      if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
        console.log('Failed to intialize shaders.');
        return;
      }

      // Write the positions of vertices to a vertex shader
      var n = initVertexBuffers(gl);
      if (n < 0) {
        console.log('Failed to set the positions of the vertices');
        return;
      }

      // Specify the color for clearing <canvas>
      gl.clearColor(0.0, 0.0, 0.0, 1.0);

      // Get storage location of u_ViewMatrix
      var u_ViewMatrix = gl.getUniformLocation(gl.program, 'u_ViewMatrix');
      if (!u_ViewMatrix) { 
        console.log('Failed to get the storage location of u_ViewMatrix');
        return;
      }

      var u_ModelMatrix = gl.getUniformLocation(gl.program, 'u_ModelMatrix');
      if (!u_ModelMatrix) { 
        console.log('Failed to get the storage location of u_ModelMatrix');
        return;
      }

      var u_ProjMatrix = gl.getUniformLocation(gl.program, 'u_ProjMatrix');
        if (!u_ModelMatrix) { 
            console.log('Failed to get the storage location of u_ProjMatrix');
            return;
        }   
      // Current rotation angle
      var currentAngle = 0.0;
      // Model matrix
      var modelMatrix = new Matrix4();
      var viewMatrix = new Matrix4();
      var projMatrix = new Matrix4();
      modelMatrix.setTranslate(0, 0, 100);
      viewMatrix.setLookAt(g_eyeX, g_eyeY, g_eyeZ, 0, 0, 0, 0, 1, 0);
      projMatrix.setPerspective(45, (canvas.width)/(canvas.height), 0.1, 10000000);
      gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements);
      gl.uniformMatrix4fv(u_ViewMatrix, false, viewMatrix.elements);
      gl.uniformMatrix4fv(u_ProjMatrix, false, projMatrix.elements);

      document.onkeydown = function(ev){ keydown(ev, gl, n, u_ViewMatrix, viewMatrix); };
      // Start drawing
      var tick = function() {
        //currentAngle = animate(currentAngle);  // Update the rotation angle
        draw(gl, n, currentAngle, modelMatrix, viewMatrix, u_ModelMatrix, u_ViewMatrix);   // Draw the triangle
        requestAnimationFrame(tick, canvas); // Request that the browser calls tick
      };
      tick();
    }

    function keydown(ev, gl, n, u_ViewMatrix, viewMatrix) {
    console.log(ev.keyCode);
        if(ev.keyCode == 39) { // The right arrow key was pressed
          g_eyeX -= 0.01;
          console.log(g_eyeX);
        } else 
        if (ev.keyCode == 37) { // The left arrow key was pressed
          g_eyeX += 0.01;
          console.log(g_eyeX);
        }
        if(ev.keyCode == 38){
            g_eyeY += 0.01;
        }
        if(ev.keyCode == 40){
            g_eyeY -= 0.01;
        }
        if(ev.keyCode == 68){
            g_curX -= 0.01;
        }
        if(ev.keyCode == 65){
            g_curX += 0.01;
        }
        if(ev.keyCode == 87){
            g_curZ += 0.01;
        }
        if(ev.keyCode == 83){
            g_curZ -= 0.01;
        }
        else { return; }   
    }


    function initVertexBuffers(gl) {
      var vertices = new Float32Array ([
        -0.5, 0.5, 0.5,
        -0.5, -0.5, 0.5,
        0.5, -0.5, 0.5,
        -0.5, 0.5, 0.5,
        0.5, -0.5, 0.5,
        0.5, 0.5, 0.5,
        0.5, 0.5, 0.5,
        0.5, -0.5, 0.5,
        0.5, -0.5, -0.5,
        0.5, 0.5, 0.5,
        0.5, -0.5, -0.5,
        0.5, 0.5, -0.5,
        0.5, -0.5, 0.5,
        -0.5, -0.5, 0.5,
        -0.5, -0.5, -0.5,
        0.5, -0.5, 0.5,
        -0.5, -0.5, -0.5,
        0.5, -0.5, -0.5,
        0.5, 0.5, -0.5,
        -0.5, 0.5, -0.5,
        -0.5, 0.5, 0.5,
        0.5, 0.5, -0.5,
        -0.5, 0.5, 0.5,
        0.5, 0.5, 0.5,
        -0.5, -0.5, -0.5,
        -0.5, 0.5, -0.5,
        0.5, 0.5, -0.5,
        -0.5, -0.5, -0.5,
        0.5, 0.5, -0.5,
        0.5, -0.5, -0.5,
        -0.5, 0.5, -0.5,
        -0.5, -0.5, -0.5,
        -0.5, -0.5, 0.5,
        -0.5, 0.5, -0.5,
        -0.5, -0.5, 0.5,
        -0.5, 0.5, 0.5
      ]);
      var n = 36;   // The number of vertices

      // Create a buffer object
      var vertexBuffer = gl.createBuffer();
      if (!vertexBuffer) {
        console.log('Failed to create the buffer object');
        return -1;
      }

      // Bind the buffer object to target
      gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
      // Write date into the buffer object
      gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

      // Assign the buffer object to a_Position variable
      var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
      if(a_Position < 0) {
        console.log('Failed to get the storage location of a_Position');
        return -1;
      }
      gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, 0, 0);

      // Enable the assignment to a_Position variable
      gl.enableVertexAttribArray(a_Position);

      return n;
    }

    function draw(gl, n, currentAngle, modelMatrix, viewMatrix, u_ModelMatrix, u_ViewMatrix) {
      // Set the rotation matrix
      modelMatrix.setRotate(currentAngle, 1, 1, 1); 
      modelMatrix.setTranslate(g_curX, 0, g_curZ);

      viewMatrix.setLookAt(g_eyeX, g_eyeY, g_eyeZ, 0, 0, 0, 0, 1, 0);
      // Pass the rotation matrix to the vertex shader
      gl.uniformMatrix4fv(u_ViewMatrix, false, viewMatrix.elements);
      gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements);

      // Clear <canvas>
      gl.clear(gl.COLOR_BUFFER_BIT);

      // Draw the rectangle
      gl.drawArrays(gl.TRIANGLES, 0, n);
    }

    // Last time that this function was called
    var g_last = Date.now();
    function animate(angle) {
      // Calculate the elapsed time
      var now = Date.now();
      var elapsed = now - g_last;
      g_last = now;
      // Update the current rotation angle (adjusted by the elapsed time)
      var newAngle = angle + (ANGLE_STEP * elapsed) / 1000.0;
      return newAngle %= 360;
    }

      

HMTL:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>Cube</title>
  </head>

  <body onload="main()">
    <canvas id="webgl" width="400" height="400">
    Please use a browser that supports "canvas"
    </canvas>

    <script src="../lib/webgl-utils.js"></script>
    <script src="../lib/webgl-debug.js"></script>
    <script src="../lib/cuon-utils.js"></script>
    <script src="../lib/cuon-matrix.js"></script>
    <script src="sceneWalker.js"></script>
  </body>
</html>

      

+3
javascript webgl


source to share


1 answer


setLookAt is typically implemented to take 3 vectors (or 9 distinct values) as arguments. The first argument is the position of the eye / camera / you. The second argument is the position in the direction you want to look. The third argument is up the axis. This is used to set the orientation of the camera. This is necessary because there are infinitely many landmarks that point in the same direction. Think of a plane, the direction of the plane tells you how it moves, but the orientation of the plane indicates whether it flies normally or is upside down.

SetLookAt usually returns a matrix of the view (or its inverse), which you then pass to the GPU.

So instead of the three 0's that you have as the gaze position, you probably want to use your model's position instead? Also, note that your implementation of motion is currently moving you in absolute coordinates, not based on the current orientation of the camera. +/- 1.0 to eye_x cannot make you move left in camera space.



Here's a simple pseudo FPSCamera implementation for reference that should get you started. The main thing to note is that the camera should track its orientation through the front, front and side vectors. They are in world coordinates and are normalized to unit length.

/** @constructor */
function FPSCamera(){
    this.pos = [0.0, 0.0, 0.0];

    this.dir = [0.0, 0.0, -1.0]; // or forward
    this.up = [0.0, 1.0, 0.0];
    this.side = [1.0, 0.0, 0.0]; // or right
}

FPSCamera.prototype.forward = function(dist){
    this.pos[0] += this.dir[0] * dist;
    this.pos[1] += this.dir[1] * dist;
    this.pos[2] += this.dir[2] * dist;
};
// do the same for other 2 directions, strife and fly

// looks to left/right
FPSCamera.prototype.yaw = function(radians){
    var orientationChange = ORIENTATION.fromAxisAngle(this.up, radians);
    this.dir = VEC3.rotatedByOrientation(this.dir, orientationChange);
    this.side = VEC3.cross(this.dir, this.up);
    this.side = VEC3.normalize(this.side);
};

// same for pitch... except the rotation axis is this.side and you need to ensure the pitch is within +/- 90 degrees

FPSCamera.prototype.getViewMatrix = function(){
    // matrix can be extracted from the 3 direction vectors, but lets use lookAt here;
    return MAT4.lookAt(this.pos, VEC3.plus(this.pos, this.dir), this.up);
};

      

+1


source to share







All Articles