Non-square Viewports
You've just learned that WebGL renders only the unit cube to the viewport. What happens to that cube, then, if the viewport isn't square? Distortion. The cube will be stretched to fit the oblong viewport. The way to avoid distortion is to ensure that the viewing volume and viewport have the same width-to-height ratio or aspect ratio.
The viewport's width and height is often determined by the browser window, and you as a developer do not usually decide the window size. However, you do get to choose the six viewing volume parameters. To make the viewing volume's aspect ratio match the viewport's, you want to make this statement true:
In the renderers we have written so far, the likely place to compute the viewport's aspect ratio is in resizeCanvas
. We compute the aspect ratio at the end of that method with the following statement:
const aspectRatio = canvas.width / canvas.height;
const aspectRatio = canvas.width / canvas.height;
Many renderers will center the viewing volume around the eye. In such cases, the viewing volume has the following symmetry:
This symmetry allows us to simplify how we compute the aspect ratio of the viewing volume:
This then is the statement that we need to make true:
The browser decides \(\mathrm{viewport\ width}\) and \(\mathrm{viewport\ height}\). You as a developer decide the value of either \(\mathrm{right}\) or \(\mathrm{top}\). You must solve for the remaining term. If you fix \(\mathrm{right}\), say at 8, then you calculate \(\mathrm{top}\) as follows:
const right = 8;
const top = right / aspectRatio;
const right = 8; const top = right / aspectRatio;
If you fix \(\mathrm{top}\), say at 8, then you calculate \(\mathrm{right}\) as follows:
const top = 8;
const right = top * aspectRatio;
const top = 8; const right = top * aspectRatio;
Once you have both variables assigned, you use them to generate a projection matrix whose aspect ratio matches the viewport:
const clipFromEye = Matrix4.ortho(-right, right, -top, top, near, far);
const clipFromEye = Matrix4.ortho(-right, right, -top, top, near, far);
The renderer will no longer distort the unit cube.