admin 管理员组

文章数量: 1087678

WebGL实践篇(七)三维相机及视图矩阵

一般来说,物体的位置是固定不动的,而我们的日常做法是将移动相机到合适的位置去拍摄这个物体(总不能把风景吸星大法过来,对它说自己过来站好拍照)。但是,在咱们这个三维空间里是有视锥体的范围,你随便移动相机那就可能要重新调节视锥体的参数,这样反而会更麻烦。因此一般来说在三维空间当中,相机应该是相对不变的。根据相机的位置再去对物体做一系列的变换。

1.相机矩阵:

      var radius = 200;var cameraMatrix = m4.yRotation(cameraAngleRadians);cameraMatrix = m4.translate(cameraMatrix, 0, 0, radius * 1.5);

这个矩阵计算出来的相机的位置是图中这样的,相机看向原点,在半径为radius * 1.5的圆上移动

2.视图矩阵

通过视图矩阵,我们可以移动视角观察到每一个“F”,那么如何计算视图矩阵呢?它是利用相机矩阵的逆变换来进行计算的。这个计算就是相当于吸星大法,让物体移动到相机面前(保持相机的不变性)。

在利用相机矩阵计算完视图矩阵之后,再与投影矩阵相结合:

      //计算视图矩阵var viewMatrix = m4.inverse(cameraMatrix);//计算视图投影矩阵var viewProjectionMatrix = m4.multiply(projectionMatrix, viewMatrix);

我们要绘制五个围成一圈丢手绢的“F",需要将每个F乘以视图矩阵之后再做旋转跟平移,做旋转跟平移主要是为了让它们能围城小圈圈。视图矩阵将控制物体的移动距离(即距相机的远近)

      for (var i = 0; i < numFs; i++) {var angle = i * Math.PI * 2 / numFs;var x = Math.cos(angle) * radius;var y = Math.sin(angle) * radius;var matrix = m4.translate(viewProjectionMatrix, x, 0, y);webgl.uniformMatrix4fv(matrixUniformLocation, false, matrix);webgl.drawArrays(webgl.TRIANGLES, 0, 16 * 6);}

OK,让我们看看结果吧。

 为啥子我的F倒了!这不是我想要的结果!让我们来继续修正修正(具体为什么还是得去扒扒原理哈,大概就是三维的Y的正方向向上,之前的二维Y的正方向是向下的)我们要对F做个以X为旋转轴的旋转操作,把它们正过来。

接下来的操作需要在setGeometry()这个函数里面进行操作:

      var matrix = m4.xRotation(Math.PI);matrix = m4.translate(matrix, -50, -75, -115);for (var i = 0; i < positions.length; i += 3) {var vector = m4.vectorMultiply([positions[i + 0], positions[i + 1], positions[i + 2], 1], matrix);positions[i + 0] = vector[0];positions[i + 1] = vector[1];positions[i + 2] = vector[2];}gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW)

结果如下:

 3.相机矩阵的优化

这个优化相当于实在做一个视线跟随吧(锁定目标)。

(1)定义相机的位置和朝向

假设相机的位置为cameraPosition,物体的位置(即目标位置)为target,相机的朝向zAxis就是cameraPosition - target(注意相机注视的是Z的负方向),然后进行单位化。

(2)确定物体的姿态

我们知道正上方的单位矢量是(0,1,0),其与zAxis的叉乘则能得到xAxis,再根据zAxis与xAxis的叉乘我们则能得到yAxis

(3)得到最终的矩阵(xAxis,yAxis,zAxis,cameraPosition)

(4)lookAt的视图矩阵

      lookAt: function (cameraPosition, target, up) {var zAxis = normalize(subtractVectors(cameraPosition, target));var xAxis = normalize(cross(up, zAxis));var yAxis = normalize(cross(zAxis, xAxis));return [xAxis[0], xAxis[1], xAxis[2], 0,yAxis[0], yAxis[1], yAxis[2], 0,zAxis[0], zAxis[1], zAxis[2], 0,cameraPosition[0], cameraPosition[1], cameraPosition[2], 1]},

(5)优化之后的矩阵参数设置

        //计算第一个f的位置var fPosition = [radius, 0, 0];var cameraMatrix = m4.yRotation(cameraAngleRadians);cameraMatrix = m4.translate(cameraMatrix, 0, 0, radius * 1.5);var cameraPosition = [cameraMatrix[12], cameraMatrix[13], cameraMatrix[14]];var up = [0, 1, 0];var cameraMatrixLook = m4.lookAt(cameraPosition, fPosition, up);var viewMatrix = m4.inverse(cameraMatrixLook);var viewProjectionMatrix = m4.multiply(projectionMatrix, viewMatrix);

(6)优化后的结果与上边的那个有点不同,这个移动滑块之后就有那种追踪单个“F”的效果了。

4.lookAt的用处

比如小时候玩的那种坦克游戏,坦克上面的那个瞄准的就可以用lookAt来做,你会发现通过上下左右的方向键能改变它的朝向从而瞄准你的目标。

然后lookAt也有一些外部库封装函数,可以根据参数直接调用使用,以及一些矩阵可能看起来长得有些不一样,但其实内部原理是一样的,具体可以看看这两篇博文(也是我现找的hhh),选择自己能理解的方式去理解就好啦。

(26条消息) WebGL之旅(九)视图矩阵_丿寒风的博客-CSDN博客(里面包括了模型矩阵、投影矩阵以及视图矩阵):

webgl笔记-1.模型视图矩阵和投影矩阵 - 一叶斋主人 - 博客园 (cnblogs).html

本文标签: WebGL实践篇(七)三维相机及视图矩阵