上一篇介绍了变换矩阵,本篇将介绍两个重要的变换矩阵,透视投影矩阵和正交投影矩阵,可以前往我的博客查看代码演示。
基本概念
透视投影矩阵
主要作用是模仿人眼观察3D世界的规律,让物体近大远小,所以被称为透视。
正交投影矩阵
主要作用是将坐标系映射到其他大小,主要用于2D UI绘制。
接下来我们就结合代码和效果深入了解这两个矩阵。我沿用了上一篇的代码,在渲染代码出根据当前选择的投影矩阵currentProjectionMatrix
使用透视或者正交投影,并配合一些平移,旋转实现本例的效果。triangleBuffer
中修改了顶点数据,将绘制的三角形改成了矩形,方便观察效果。同时记的把绘制的代码顶点数改成6,gl.drawArrays(gl.TRIANGLES, 0, 6);
。
window.onWebGLRender = function render(deltaTime, elapesdTime) {
gl.viewport(0, 0, canvas.width, canvas.height);
gl.clearColor(1.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
...
var rotateMatrix = mat4.create();
mat4.rotate(rotateMatrix, rotateMatrix, elapesdTime / 1000.0, vec3.fromValues(0, 1, 0));
var translateMatrix = mat4.create();
mat4.translate(translateMatrix, translateMatrix, vec3.fromValues(0, 0, -1));
var transform = mat4.create();
mat4.multiply(transform, translateMatrix, rotateMatrix);
mat4.multiply(transform, currentProjectionMatrix, transform);
transformUniformLoc = gl.getUniformLocation(program, 'transform');
gl.uniformMatrix4fv(transformUniformLoc, false, transform);
gl.drawArrays(gl.TRIANGLES, 0, 6);
}
function makeBuffer() {
var triangle = [
-0.5, 0.5, 0.0,
-0.5, -0.5, 0.0,
0.5, -0.5, 0.0,
-0.5, 0.5, 0.0,
0.5, -0.5, 0.0,
0.5, 0.5, 0.0,
];
buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(triangle), gl.STATIC_DRAW);
return buffer;
}
透视投影
这是构建透视投影矩阵的代码。
perspectiveProjectionMatrix = mat4.create();
mat4.perspective(perspectiveProjectionMatrix, 80 / 180.0 * Math.PI, canvas.width / canvas.height, 0.1, 1000);
perspective
方法有4个参数float fovyRadians, float aspect, float nearZ, float farZ
。fovyRadians
表示视角。aspect
表示屏幕宽高比,为了将所有轴的单位长度统一,所以需要知道屏幕宽高比多少。nearZ
表示可视范围在Z轴的起点到原点(0,0,0)的距离,farZ
表示可视范围在Z轴的终点到原点(0,0,0)的距离,nearZ
和farZ
始终为正。下面是透视投影的剖面示意图。
透视投影矩阵默认的可视方向是向Z轴的反方向生长的。视角(fovyRadians)越大,看到的东西就越多。只有在nearZ和farZ两个平面范围内的点才会被投影到屏幕上,当然这些点也必须在视角的范围内。根据上面的条件,一个位于z=0上的点是不能被投影到屏幕的,所以我在渲染时增加了一个平移矩阵mat4.translate(translateMatrix, translateMatrix, vec3.fromValues(0, 0, -1));
,为了演示近大远小的视觉效果,我又增加了旋转矩阵mat4.rotate(rotateMatrix, rotateMatrix, elapesdTime / 1000.0, vec3.fromValues(0, 1, 0));
。最后将 perspectiveMatrix * translateMatrix * rotateMatrix
的结果赋值给Vertex Shader中的transform。
如果读者还记得上一篇提到的矩阵运算的话,就应该知道perspectiveMatrix * translateMatrix * rotateMatrix
代表着先旋转再平移最后执行透视投影。这是以后所有3D变换操作的基本顺序,投影必须放在最后。透视投影的效果如下。
正交投影
构建矩阵的代码如下
orthoProjectionMatrix = mat4.create();
mat4.ortho(orthoProjectionMatrix, -0.8, 0.8, -0.8, 0.8, -100, 100);
正交投影其实比较好理解,原先屏幕的X轴从左到右是-1到1,Y轴从上到下是1到-1,经过mat4.ortho(orthoProjectionMatrix, -0.8, 0.8, -0.8, 0.8, -100, 100);
正交矩阵的变换,就会变成X轴从左到右是-0.8到0.8,Y轴从上到下是0.8到-0.8。正交投影里的nearZ和farZ代表可视的Z轴范围,超出的点就不可见了。代码效果如下。
矩阵切换
例子通过select元素切换投影效果。根据不同的选择,currentProjectionMatrix
会赋予不同的投影矩阵值,然后在渲染代码中直接使用。
function setupProjectionMatrixSelect() {
currentProjectionMatrix = perspectiveProjectionMatrix;
currentBuffer = triangleBuffer;
var selectNode = document.getElementById("projectionModeSelect");
selectNode.onchange = function (evt) {
switch (evt.target.value) {
case 'perspective':
currentProjectionMatrix = perspectiveProjectionMatrix;
break;
case 'ortho':
currentProjectionMatrix = orthoProjectionMatrix;
break;
}
}
}
本篇主要介绍了WebGL中的两个重要投影矩阵,掌握好它们对于后面更深入的学习3D和2D渲染有着非常重要的作用。
下一篇会讲解摄像机,作为3D渲染中最基本的三大矩阵MVP之一,学习完之后就可以正式踏入3D渲染的世界了。
网友评论