Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WebGL: canvas coordinates to 3d coords

Tags:

html

webgl

I am trying to find the "left" border of my WebGL view port because I would like to draw a number of debug information there. (an axis mini map like most modeling programs have) I certainly can get the width and height of the canvas containing the WebGL viewport.

I would really like to know how I would go about calculating 2d canvas coordinates to 3d coordinates? What would be the best approach to find the left border in the 3d viewport?


Anyone looking into this should read http://webglfactory.blogspot.com/2011/05/how-to-convert-world-to-screen.html or take a look at GluProject() and GluUnproject()

like image 484
Tom Avatar asked Jan 17 '23 16:01

Tom


2 Answers

To clarify datenwolf's answer, the coordinate mapping between your 3D space and 2D canvas is exactly what you want it to be. You control it with gl.viewport and the matrices that you pass to your shader.

gl.viewport simply blocks out a rectangle of pixels on your canvas that you are drawing to. Most of the time this matches the dimensions of your canvas exactly, but there are some scenarios where you only want to draw to part of it. (Split-screen gaming, for example.) The area of your canvas that you're drawing to will be referred to as the viewport from here on out. You can assume it means the same thing as "canvas" if you'd like.

At it's simplest, the viewport always has an implicit coordinate system from -1 to 1 on both the X and Y axis. This is the space that the gl_Position output by your vertex shader operates in. If you output a vertex at (-1, -1) it will be in the bottom left corner of your viewport. a vertex at (1, 1) will be in the top right. (Yes, I'm ignoring depth for now) Using this, you could construct geometry designed to map to that space and draw it without any matrix transforms at all, but that can be a bit awkward.

To make life easier, we use projection matrices. A projection matrix is simply one that transforms your geometry from some arbitrary 3D space into that -1 to 1 space required by the viewport. The most common one is a perspective matrix. How you create it will look a bit different depending on the library you use, but typically it's something like this:

var fov = 45;
var aspectRatio = canvas.width/canvas.height;
var near = 1.0;
var far = 1024.0;
var projectionMat = mat4.perspective(fov, aspect, near, far);

I'm not going to get into what all those values mean, but you can clearly see that we're using the canvas width and height to help set up this projection. That allows it to not look stretched or squashed depending on the canvas size. What it all boils down to, however, is that taking any 3D point in space and multiplying it by this matrix will produce a point that maps to that -1 to 1 space, taking into account distance from the 'camera' and everything else. (It may actually fall outside of that bounds, but that simply means it's off camera.) It's what makes our 3D scenes look 3D.

It's also possible to create an projection matrix specifically for drawing 2D geometry, though. This is called an orthographic matrix, and the setup typically looks something like this:

var left = 0;
var top = 0;
var right = canvas.width;
var bottom = canvas.height;
var near = 1.0;
var far = 1024.0;
var projectionMat = mat4.ortho(left, right, bottom, top, near, far);

This matrix is different than the perspective matrix in that it ignores the z component of your position entirely. Instead, this matrix transforms flat coordinates, like pixels, into the -1 to 1 range. As such, your scenes don't look 3D but it's easier to control exacty where things appear on screen. So, using the matrix above, if we give it a vertex at (16, 16, 0) it will appear at (16, 16) on our canvas (assuming the viewport is the same dimensions as the canvas). As such, when you want to draw things like flat UI elements this is the type of matrix you want!

The nice part is that because these are just values that you pass to a shader you can use completely different matrices from one draw call to the next. Typically you'll draw all of your 3D geometry with a perspective matrix, then all of your UI with a orthographic matrix.

Apologies if that was a bit rambling. I've never been terribly good at explaining all that math-y stuff.

like image 53
Toji Avatar answered Jan 28 '23 23:01

Toji


I am trying to find the "left" border of my WebGL view port because I would like to draw a number of debug information there. (an axis mini map like most modeling programs have) I certainly can get the width and height of the canvas containing the WebGL viewport.

Just switch the viewport and projection for those parts. You can change them anytime.

like image 29
datenwolf Avatar answered Jan 28 '23 23:01

datenwolf