When I use the identity view matrix, I can see my model, but when I use LookAt
, it is not visible. How can I see my model using LookAt
?
The LookAt
function takes three parameters:
eye
, which is where your camera is. in the identity matrix, your camera is at 0, 0, 0
target
, which is where your camera is pointed at. you can think of the camera's direction vector as target - eye
. In the identity matrix, the camera is facing in the direction of the negative Z axis.
up
, which is which way your camera is rotated. 0, 1, 0
is the default up
in the usual coordinate system.
In order to replicate your identity view matrix, just use mat4.lookat(.., [0, 0, 0], [0, 0, -1], [0, 1, 0])
.
If the above works, now you can experiment with changing the eye
parameter to move the camera around.
If I set up an ortho camera like this: mat4.ortho(output, 0, screenWidth, 0, screenHeight, 0, 1)
, things go wrong.
Those parameters dont' look right to me. it should be mat4.ortho(output, -scaleX, scaleX, -scaleY, scaleY, 0, farZ)
. Depending on your coordinates and aspect ratio, the values of scaleX
and scaleY
are roughly half the distance between your camera and target to get a similar scale of view to the perspective camera. If you have no ideal, start scaleX and scaleY off at 1. additionally, farZ = 1 is a very short range, you may want to raise it up much higher, especially if you're moving the camera around.
Playground
I've included a basic "rotating camera around a triangle" demo here, the left side is a perspective projection, the right side is an ortho projection. Feel free to play with the distance
variable and see how the scale for the ortho changes in proportion to the perspective shrinking as the camera is further away.
cv.width = window.innerWidth;
cv.height = window.innerHeight;
var gl = cv.getContext('webgl');
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.enable(gl.DEPTH_TEST);
function Mesh(arr) {
var buf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buf);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(arr), gl.STATIC_DRAW);
return buf;
}
var mesh = Mesh([0.0, 1.0, -0,-1.0, -1.0, -0,1.0, -1.0, -0 ])
function shader(type, src) {
var s = gl.createShader(type);
gl.shaderSource(s, src);
gl.compileShader(s);
return s
}
var program = gl.createProgram();
gl.attachShader(program, shader(gl.VERTEX_SHADER, `
attribute vec3 pos;
uniform mat4 view;
uniform mat4 projection;
void main() { gl_Position = projection * view * vec4(pos, 1); }
`));
gl.attachShader(program, shader(gl.FRAGMENT_SHADER, "void main() { gl_FragColor = vec4(1); }"));
gl.linkProgram(program);
gl.validateProgram(program);
gl.useProgram(program)
gl.bindBuffer(gl.ARRAY_BUFFER, mesh);
gl.enableVertexAttribArray(program, 0);
function render(viewport, proj_mat, view_mat) {
gl.viewport.apply(gl, viewport);
gl.uniformMatrix4fv(
gl.getUniformLocation(program, 'projection'), false, proj_mat)
gl.uniformMatrix4fv(gl.getUniformLocation(program, 'view'), false, view_mat)
gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
gl.drawArrays(gl.TRIANGLES, 0, 3);
}
var view = mat4.create();
var ortho_proj = mat4.create();
var perspective_proj = mat4.create();
var fov = 0.7, distance = 4;
var scale = Math.tan(fov / 2) * distance; // since ortho is distance invariant, scale by (distance from camera to some reference point)
function loop(t) {
t /= 1000;
mat4.perspective(perspective_proj, fov, 1, 0.1, 1000.0);
mat4.ortho(ortho_proj, -scale, scale, -scale, scale, 0.1, 100);
mat4.lookAt(view, [distance * Math.sin(t),0, distance * Math.cos(t)],[0,0,0],[0,1,0]);
render([0, 0, cv.width / 2, cv.height], perspective_proj, view);
render([cv.width / 2, 0, cv.width / 2, cv.height], ortho_proj, view);
requestAnimationFrame(loop);
}
loop();
body, html { margin:0px; padding:0px; }
canvas { background: #39e; position:absolute; top:0px; }
h2, h3 { position:absolute; top:0px; z-index: 20; }
.r { right:0px; }
<h2>Perspective</h2>
<h2 class=r>Ortho</h2>
<canvas id=cv> </canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.4.0/gl-matrix.js"></script>
Obsolete Answer
This first answer to a supposed question "what, in the general sense, is the relationship between an ortho and a lookAt matrix?".
There's 3 kinds of matrices that combine to form a full transformation:
the model matrix, which describes the transformation applied to the vertices of your model to get them into world-space,
the view matrix, which describes the transformation to get from your world-space into a camera-relative space (eye coordinates),
the perspective matrix to describe how to transform the camera-space positions into how it appears on your screen (clip-space / screen-space after the perspective correction).
In your case, ortho
and perspective
are ways to create the perspective matrix, and lookAt
creates a view matrix (you could also manually create a view matrix by combining a bunch of mat4.translate/rotate/scales to re-create the camera position).
Your final transform must multiply the perspective * view * model matrices.