关于“绕坐标轴的旋转”和“鼠标控制物体的旋转”(二)

来源:互联网 发布:疯狗雾化器做丝数据 编辑:程序博客网 时间:2024/05/01 23:11


CSDN这个文章非类真的很蛋疼啊!!!以下是我转载的一篇,感觉解释的很清楚,前面的矩阵大家就都不用看了,后面我感觉对我挺重要的。

转自:星光
作者:ming1016@gmail.com
原文:http://www.starming.com/index.php?action=plugin&v=wave&tpl=union&ac=viewgrouppost&gid=34493&tid=9690


常见变换

 

除了glTranslatef()和 glRotatef()外,还有 glScalef(),它使绘制物体的尺寸增大或减小。在OpenGL ES中还有其他一些变换功能,但这三个(与glLoadIdentity()一起使用)是最常见的。其他功能主要用于将三维虚拟世界转换为二维表示的过 程,这个过程称为透视 。我们稍后涉及一下透视,但大部分情况下,除了设置视口外我们不需要直接与透视打交道。

 

这些常用的变换非常实用。你可以仅使用这四个调用就完成整个游戏。但是有时你可能需要自己控制转换。你想要自己控制转换的一个原因是这些常用变换必须按顺序分别调用,每次调用都是一次具有一定开销的矩阵乘法(稍后讨论)。如果你自己进行转换,你可以将多个转换组合成一个矩阵,从而减少每帧都要进行的矩阵乘法操作。

 

由于你可以向量化你的矩阵乘法调用,所以你可以通过定义自己的矩阵来获取最大性能。据我所知,关于此点iPhone 并无文档记录,但作为基本规则OpenGL ES将对向量间或顶点和矩阵间的乘法进行硬件加速,但两个转换矩阵间的乘法并无加速。通过矩阵乘法向量化,你可以获得比让OpenGL进行矩阵乘法更好的 性能。由于通常矩阵与矩阵的乘法调用的数量远小于向量/顶点间的矩阵乘法调用的数量,所以这并不会带来巨大的性能提升,但在一个复杂的3D程序中,每个方 面小的额外性能提升都很有好处。

矩阵

 

这里我明显不是指电影“黑客帝国”(”The Matrix”),我们将要在随后的篇幅中介绍矩阵。

 

不幸的是没人可以告诉我矩阵是什么。

 

实际上,矩阵不过是一个二维数组。就这么简单。没什么神秘的。下面是一个矩阵示例:

 

simplematrix

 

这是一个 3×3 矩阵,它有三行和三列。顶点和向量实际由一个1×3的矩阵表示:

 

vertexmatrix

 

一个顶点还可以由一个 3×1 数组而不是一个 1×3 数组表示,但是我们这里使用1×3 格式(后面解释原因)。甚至一个数据元素技术上也可以用一个 1×1 矩阵表示,尽管这并不是一个十分有用的矩阵。

还有什么可以用数组来表示?坐标系统。还记得向量?向量是想象的从原点指向空间一点的直线。现在,记住笛卡尔坐标系统具有三个轴:

 

cartesian

 

那么,指向X轴反向的归一向量是什么样的?记住:归一向量是长度为一的向量,所以一个沿X轴正向的归一向量是这样的:

 

xaxisvector

 

注意我们是使用3×1 矩阵而不是像处理顶点一样使用1×3矩阵来表示向量。实际上这并不重要,只要按处理顶点相反的方式处理向量就行。向量中的三个数值适用于同一个坐标轴。我知道,这可能还不太好理解,但我很快就会解释到。Y轴向上的向量看上去像这样:

 

yaxisvector

 

Z轴上的向量像这样:

 

zaxisvector

 

现在我们将这三个向量矩阵按照它们在顶点(x然后是y再后是z)中的顺序放入矩阵中,像这样:

 

3x3identity

 

有一个特殊矩阵称为单元矩阵。听起来很熟悉?当你调用glLoadIdentity()时, 你就加载了一个单元矩阵1。 这里我解释一下为什么它是一个特殊矩阵。矩阵可以通过相乘而组合在一起。如果你将矩阵乘以一个单元矩阵,其结果就是原始矩阵,就像数字乘以一。你可以通过将所有除行号和列号相等的元素外的值设置为0来设定一个任意尺寸的单元矩阵,行号和列号相等处的值为1.0.

 

矩阵相乘

 

矩阵相乘是矩阵组合的关键。如果你有一个定义了转移到矩阵和一个定义了旋转的矩阵,如果将它们相乘,你将得到一个既定义了旋转又定义了转移的矩阵。让我们看看一个简单的矩阵相乘的简单例子。看看下面两个矩阵的图像:

 

simplemultiply

 

 

矩阵相乘的结果是另一个与等式左边矩阵一样尺寸的矩阵。矩阵乘法是不可置换的。顺序是很重要的。将矩阵a乘以矩阵b的结果不一定与矩阵b乘以矩阵a的结果相同(尽管在某些情况下有可能相同)。

 

有关矩阵相乘还有一件事需要注意:并不是所有的矩阵都可以相乘的。它们并不需要具有同样的尺寸,但等式中右边的矩阵的行数必须与等式中左边矩阵的列 数相同。所以,你可以将一个3×3的矩阵与另一个3×3的矩阵相乘,或者你可以将一个1×3的矩阵与一个3×6的矩阵相乘,但你不能将一个2×4的矩阵与 另一个2×4的矩阵相乘,因为2×4矩阵的列数与另一个2×4矩阵的行数并不相同。

 

要得出矩阵相乘的结果,我们首先建立一个与等式中左边矩阵同样尺寸的空矩阵:

 

empty3x3matrix

 

对矩阵中的各点,我们从左边矩阵中取出相应行,再从右边矩阵中取出相应列。所以,对于结果矩阵中的左上方的点,我们取出等式中左边矩阵的第一行以及等式中右边矩阵的第一列,像这样:

 

multbreakdown

 

然后,将左边矩阵行中第一个值乘以右边矩阵列的第一个值,左边矩阵行第二个值乘以右边矩阵列的第二个值,左边矩阵行第三个值乘以右边矩阵列的第三个值,然后再将它们相加。像这样:

 

firstspotcalc

 

对结果矩阵中的各点重复以上步骤,得到以下结果:

 

simplematrixfinal

 

将矩阵(蓝色)乘以单元矩阵(红色),其结果就是原始矩阵。由于单元矩阵代表没有经过任何变换的坐标系统,所以结果完全合理。这也同样适用于顶点。我们将一个顶点乘以一个矩阵:

vertexmult

 

现在,我们假定我们希望旋转一个物体。我们要做的就是定义一个描述了被旋转的坐标系统的矩阵。在场景中,我们实际上是旋转了世界坐标,然后将物体绘 制其上。如果说我们希望绕Z轴旋转一个物体,那么Z轴将保持不变,而X和Y轴将变化。尽管有些不那么直观,要定义一个绕z轴旋转的坐标系统,我们需要调整 3×3矩阵中的x和y向量,换句话说,我们必须修改第一和第二列。

 

vectoraxes


所以需要调整通过修改X轴向量的X值和Y向量的Y值为旋转角度的余弦值。余弦是三角形角度对应的相邻两边之比。我们还需要修改X轴向量的Y值为相同角度的正弦值的负值,以及Y轴向量的X值为相同角度的正弦值。用矩阵来表示可能更容易理解:

 

zrotation

 

现在如果将世界坐标中所有物体的各顶点都乘以这个矩阵,那么物体将被旋转。一旦对物体的所有顶点都进行此操作,那么该物体将沿Z轴旋转n度。

 

如果你还不太理解也不要紧。其实你并不需要真正理解使用矩阵的数学原理。它们都是已经解决了的难题,你可以通过Google找到任何变换所需的矩 阵。实际上,你可以在OpenGL的文档中找到大部分。所以如果你不能完全理解为什么这个矩阵导致绕Z轴的旋转,也完全不必气恼。

 

一个3×3的矩阵可以描述绕任意轴旋转任何角度的情况。然而,为表示可能遇到的任何变换,我们仍然需要第四行/列。第四列用来保存变换信息,第四行 用来表示透视变换。因为需要理解同原坐标以及透视空间,而这些对于成为一个出色的OpenGL程序员并不重要,所以我不打算在这里介绍透视变换的数学原理 了。要乘以一个4×4矩阵,我们需要填充一个附加值,通常我们称其为W。W应该为1。在进行乘法运算后,忽略W值。我不打算介绍向量的矩阵乘法,因为 OpenGL已经对此进行了硬件加速,所以通常不需要进行手工处理,但理解其基本步骤是很好的建议。

原创粉丝点击