Webgl 3rd person camera

I am playing around in webgl and have build a simple gltf loader, that allows to move the main object around. It also allows to rotate the camera (orbit) the main object, but only on yaw. I can orbit the object, but it only allows to view the front side. Now I did fix that using rotation and multiplication, but I want to use the lookAt function, to make it more simple, and also to have pitch orbit (up-down). My camera class has the transform matrix and the projection matrix. I then make a view matrix and multiply it with the projection matrix, then save it in the transform matrix. But this only allows for yaw rotation. If I add pitch, then the camera does move up and down, but it doesn’t rotate to keep the object in center. I am thinking this could be done with the lookAt function, but how would I get the camera origin position, since it requires a vector, but I only have the main transform matrix. I do have transformation, rotation and scale vectors, but since I am multiplying matrixes, the remain 0.

Here is my code:

const c = this;

        
let camX = Math.sin(c.yaw) * c.distance;
//let camY = Math.cos(c.pitch) * c.distance;
let camZ = Math.cos(c.yaw) * c.distance;


var viewMatrix = mat4.create();
mat4.invert(viewMatrix, c.matrix);
mat4.multiply(c.matrix, c.projection, viewMatrix);
mat4.fromTranslation(c.matrix, vec3.fromValues(camX, 0, camZ));
     
const vec = vec3.create();
vec3.add(vec, vec3.clone(plane.translation), vec3.fromValues(camX, 0, camZ));
var moveMatrix = mat4.create();
mat4.fromTranslation(moveMatrix,  vec);
mat4.multiply(c.matrix, c.matrix, moveMatrix);

var rotMatrix = mat4.create();
mat4.fromYRotation(rotMatrix, c.yaw);
mat4.multiply(c.matrix, c.matrix, rotMatrix);

Matrix is the transform matrix.

For a better structure in the future I would suggest keeping more information for each object/reference you have, rather than sticking to the matrix itself. That should only be a result of all the operations you perform in order to send it to the GPU/Shader/Stack.

With this in mind, a good example is to keep reference of:

  • Position vector
  • Direction or forward vector
  • Up vector
  • Right or left (depending or your referential) vector
    and those last 3 vectors will store the scaling of the object itself.

using those, its way easier to make adjustements and transformatinos to your object and to prepare a matrix for rendering.

Now, to look at something (or point to/align with) you need to have at least 2 vectors (the 3rd one can be obtained by the cross product of the former 2).

Assuming you want to keep having an up vector aligned with the Y vector(the vertical one), you now need to create a vector from the center of your camera to the point you wish to point to, and then invert it.

Continuing, we have the vector direction, and an up vector which is unit vector Y, but this in not ready to be sent to the matrix because those 2 are not perpendicular, otherwise we would have distortion on the camera.

but, we can get a point from the up vector (which is [0,1,0]) cross it with ouer forward vector to get a perpendicular and the cross it again, which gives us the following:

UPv = DIRv.cross(0,1,0).cross(DIRv);

leaving us with the new vector we need, and now we just need to acquire the right vector just by crossing those 2, as following:

RIGHTv = UPv.cross(DIRv).normalize();

the full data:

DIRv = target.sub(camera.position).normalize().invert();
UPv = DIRv.cross(0,1,0).cross(DIRv).normalize();
RIGHTv = UPv.cross(DIRv).normalize();

now you can build your new matrix in order to point to it.

My first and third person movement demo in JS, WebGL 1.0 and OimoPhysics physics engine based on a 3D apartment plan created in Blender from a 2D drawing found on the Internet

image