上一篇介绍了变换矩阵,本篇将介绍两个重要的变换矩阵,透视投影矩阵和正交投影矩阵,可以前往我的博客查看代码演示。
基本概念
透视投影矩阵
主要作用是模仿人眼观察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渲染的世界了。
链接:http://www.jianshu.com/p/5de75274278e
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。