huangwei.pro

本文中,我会将不会动的2D三角形替换为旋转的3D立方体。你会看到这样的效果:

现在我们终于能在屏幕上搞点有趣的东西了,我放了更多的动图在这里:

为了生成旋转立方体,我们需要学些关于矩阵的数学,,用于创建透视投影,旋转,平移和“相机”概念。我们还有必要学习些深度缓冲,和典型的随时间改变的3D应用,比如动画。

获取代码

所有例子代码的zip打包可以从这里获取:https://github.com/tomdalling/opengl-series/archive/master.zip。

这一系列文章中所使用的代码都存放在:https://github.com/tomdalling/opengl-series。你可以在页面中下载zip,加入你会git的话,也可以复制该仓库。

本文代码你可以在source/02_textures目录里找到。使用OS X系统的,可以打开根目录里的opengl-series.xcodeproj,选择本文工程。使用Windows系统的,可以在Visual Studio 2013里打开opengl-series.sln,选择相应工程。

工程里已包含所有依赖,所以你不需要再安装或者配置额外的东西。如果有任何编译或运行上的问题,请联系我。

矩阵原理

本文讲的最多的就是关于3D中的矩阵,所以让我们在写代码前先了解下矩阵原理。我不会过多关注数学,网上有很多好的这类资源。我们只需要使用GLM来实现相关运算。我会注重于那些应用在我们3D程序里的矩阵。

矩阵是用来进行3D变换。可能的变换包括(点击可以看动画):

一个矩阵是一个数字表格,像这样:

矩阵英文matrix的复数形式是matrices。

不同的数值的能产生不同类型的变换。上面的那个矩阵会绕着Z轴旋转90°。我们会使用GLM来创建矩阵,所以我们不用理解如何计算出这些数值。

矩阵可以有任意行和列,但3D变换使用4×4矩阵,就像上面看到的那样。无论我在那说到“矩阵”,指的就是4×4矩阵。

当用代码实现矩阵时,一般会用一个浮点数组来表示。我们使用glm::mat4类来表示4×4矩阵。

两个最重要的矩阵操作是:

matrix × matrix = combined matrixmatrix × coordinate = transformed coordinate 矩阵 × 矩阵

当你要对两个矩阵进行相乘时,它们的乘积是一个包含两者变换的新矩阵。

比如,你将一个旋转矩阵乘以一个平移矩阵,得到的结果就是“组合”矩阵,即先旋转然后平移。下面的例子展示这类矩阵相乘。

不像普通的乘法,矩阵乘法中顺序很重要。 比如,A和B是矩阵,A*B不一定等于B*A。下面我们会使用相同的矩阵,但改变下乘法顺序:

注意不同的顺序,结果也不同。下面动画说明顺序有多重要。相同的矩阵,不同的顺序。两个变换分别是沿Y轴上移,和旋转45°。

当你编码的时候,假如看到变换出错,请回头检查下你的矩阵运算是否是正确的顺序。

矩阵 × 坐标

当你用矩阵乘以一个坐标时,它们的乘积就是一个变换后的新坐标。

比如,你有上面提到的旋转矩阵,乘上坐标(1,1,0),它的结果就是(-1,1,0)。变换后的坐标就是原始坐标绕着Z周旋转90°。下面是该乘法的图例:

为何我们会使用4D坐标

你可能注意到了上面的坐标是4D的,而非3D。它的格式是这样的:

为何我们会使用4D坐标?因为我们需要用4×4的矩阵完成所有我们需要的3D变换。不管怎样,矩阵乘法需要左边的列数等于右边的行数。这就意味着4×4矩阵无法与3D坐标相乘,因为矩阵有4列,但坐标只有3行。我们需要使用4D坐标,因为4×4的矩阵需要用它们来完成矩阵运算。

一些变换,比如旋转,缩放,只需要3×3矩阵。对于这些变换,我们不需要4D坐标,因为3D坐标就能运算。但无论如何,变换需要至少是4×3的矩阵,而透视投影矩阵需要4×4矩阵,而我们两者都会用到,所以我们强制使用4D。

这些被称为齐次坐标。在后续的教程里,我们会讲到有向光照,那里我们会学到有关“W”维度的表示。在这里,我们只需要将3D转换为4D。3D转换为4D只要将第四维坐标“W”设为1即可。比如,坐标(22,33,44)转换为:

当需要将4D坐标变为3D时,假如“W”维度是1,你可以直接忽略它,使用X,Y,Z的值即可。如果你发现“W”的值不为1,好吧,你就需要做些额外处理,或者这里出了个bug。

构造一个立方体

代码上第一个变动就是用立方体替换之前的三角形。

我们用三角形来构造立方体,用两个三角形表示6个面的每个面。在旧版本的OpengGL中,我们可以使用1个正方形(GL_QUADS)来替代2个三角表示每个面,但GL_QUADS已经被现代版本的OpenGL给移除了。X,Y,Z坐标值域为-1到1,这意味着立方体是两个单位宽,立方体中心点在原点(原点坐标(0,0,0))。我们将使用256×256的贴图给立方体每个面贴上。后序文章中都会使用这个数据,我们不需要改变太多。这里有立方体数据:

GLfloat vertexData[] = {// XYZUV// bottom-1.0f,-1.0f,-1.0f, 0.0f, 0.0f,1.0f,-1.0f,-1.0f, 1.0f, 0.0f,-1.0f,-1.0f, 1.0f, 0.0f, 1.0f,1.0f,-1.0f,-1.0f, 1.0f, 0.0f,1.0f,-1.0f, 1.0f, 1.0f, 1.0f,-1.0f,-1.0f, 1.0f, 0.0f, 1.0f,// top-1.0f, 1.0f,-1.0f, 0.0f, 0.0f,-1.0f, 1.0f, 1.0f, 0.0f, 1.0f,1.0f, 1.0f,-1.0f, 1.0f, 0.0f,1.0f, 1.0f,-1.0f, 1.0f, 0.0f,-1.0f, 1.0f, 1.0f, 0.0f, 1.0f,1.0f, 1.0f, 1.0f, 1.0f, 1.0f,// front-1.0f,-1.0f, 1.0f, 1.0f, 0.0f,1.0f,-1.0f, 1.0f, 0.0f, 0.0f,-1.0f, 1.0f, 1.0f, 1.0f, 1.0f,1.0f,-1.0f, 1.0f, 0.0f, 0.0f,1.0f, 1.0f, 1.0f, 0.0f, 1.0f,-1.0f, 1.0f, 1.0f, 1.0f, 1.0f,// back-1.0f,-1.0f,-1.0f, 0.0f, 0.0f,-1.0f, 1.0f,-1.0f, 0.0f, 1.0f,1.0f,-1.0f,-1.0f, 1.0f, 0.0f,1.0f,-1.0f,-1.0f, 1.0f, 0.0f,-1.0f, 1.0f,-1.0f, 0.0f, 1.0f,1.0f, 1.0f,-1.0f, 1.0f, 1.0f,// left-1.0f,-1.0f, 1.0f, 0.0f, 1.0f,-1.0f, 1.0f,-1.0f, 1.0f, 0.0f,-1.0f,-1.0f,-1.0f, 0.0f, 0.0f,-1.0f,-1.0f, 1.0f, 0.0f, 1.0f,-1.0f, 1.0f, 1.0f, 1.0f, 1.0f,-1.0f, 1.0f,-1.0f, 1.0f, 0.0f,// right1.0f,-1.0f, 1.0f, 1.0f, 1.0f,1.0f,-1.0f,-1.0f, 1.0f, 0.0f,1.0f, 1.0f,-1.0f, 0.0f, 0.0f,1.0f,-1.0f, 1.0f, 1.0f, 1.0f,1.0f, 1.0f,-1.0f, 0.0f, 0.0f,1.0f, 1.0f, 1.0f, 0.0f, 1.0f};大理的洱海形如人耳,风平浪静时,

huangwei.pro

相关文章:

你感兴趣的文章:

标签云: