OpenGL ES 数学知识点

发表于2016-05-21
评论1 2.4k浏览

    OpenGL 使用列主序矩阵,即列矩阵,因此我们总是倒过来算的(左乘矩阵,变换效果是按从右向左的顺序进行): 投影矩阵 × 视图矩阵 × 模型矩阵 × 3D位置。并且是以列序为存储的,也就是说第一张图的存到数组里是
{1,0,0,0,
0,1,0,0,
0,0,1,0,
x,y,z,1}。
平移矩阵可表示为:


201212041757359838

    平移矩阵 × 列矩阵(a, b, c, 1) = 列矩阵(a + x, b + y, c + z, 1)。

    缩放矩阵可表示为:


201212041757359282

    缩放矩阵 × 列矩阵(a, b, c, 1) = 列矩阵(a × sx, b × sy, c × sz, 1)。

    绕 X 轴旋转的旋转矩阵可表示为:


201212041757351757

    绕 X 轴旋转的旋转矩阵 × 列矩阵(a, b, c, 1) = 列矩阵(a, b × cos(θ) – c × sin(θ), b × -sin(θ) + c × cos(θ), 1)。

    绕 Y 轴旋转的旋转矩阵可表示为:


201212041757366741

    绕 Y 轴旋转的旋转矩阵 × 列矩阵(a, b, c, 1) = 列矩阵(a × cos(θ) – c × sin(θ), b , a × -sin(θ) + c × cos(θ), 1)。

    绕 Z 轴旋转的旋转矩阵可表示为:


201212041757363120

    绕 Z 轴旋转的旋转矩阵 × 列矩阵(a, b, c, 1) = 列矩阵(a × cos(θ) – b × sin(θ), a × -sin(θ) + b × cos(θ), c, 1)。

   OpenGL 使用右手规则进行旋转,因此逆时针方向的选择是正角度的


201212041757366675

    OpenGL 中物体最初是在本地坐标空间中,然后转换到世界坐标空间,再到 camera 视图空间,再到投影空间,这一系列转换都是靠 matrix 计算来实现。

opengl中的矩阵变换
a、viewport(视口)变换
    viewport 变换发生在投影到2D 投影平面之后,该变换是将投影之后归一化的点映射到屏幕上一块区域内的坐标。视口变换的目的是指定投影之后图像在屏幕上显示的区域。如下示意图所示:


2012120519052224

    视口变换 glViewport(x, y, width, height); x,y 是投影平面描绘在屏幕或窗口上的起始位置(注意屏幕坐标以左上方为原点),width和height是以像素为单位,指投影平面在屏幕上描绘的区域大小。如果投影平面的宽高比,与width/height比不相同(如上面的右图),那么描绘的场景就会扭曲。

    从裁剪到屏幕的整个过程如下图所示,w 就是前面提到的齐次坐标那一维,从 Clip Space 到 Normalized Device Space 就是投影规范化的过程,从 Normalized Device Space 到 Window Space 就是 viewport 变换过程。


2012120421555619

    该转换内部计算公式为:
2012120421212773
    (Xw, Yw)是屏幕坐标,(x, y, width, height)是传入的参数,(Xnd, Ynd)是投影之后经归一化之后的点(上图中 Normalized Device Space 空间的点)。因此 viewport 变换就是将投影之后归一化的点转换为真正可用于在屏幕上进行渲染的屏幕坐标;


b、模型视图变换
    OpenGL 和 OpenGL ES 都将模型变换与视图变换结合在一起,而不是分开为两个,这是因为模型变换等价于视图变换的逆变换。视图变换是将物体转换到观察者(一般称之为 camera)的视线空间中。你可以想象一下,照相时,你可以:A)照相机不懂,旋转自己的头找个侧面像,也可以B)自己不动,照相机旋转一定的角度来达到同样的效果。下面的两幅图分别描述了情形A)和情形B):

情形A):旋转物体,相机不动


2012120422025433

情形B):旋转相机,物体不动


2012120422032245

    在 OpenGL 中,我们在设置场景(scene)的时候通常是采取情形B)的做法


c、投影变换
    正交投影和透视投影。透视投影用的比较广泛,它与真实世界更相近:近处的物体看起来要比远处的物体大;而正交投影没有这个效果,正交投影通常用于CAD或建筑设计。下面是正交投影与透视投影效果示意图:

视锥体/视景体:


2012120422542148


    glFrustum(left, right, bottom, top, zNear, zFar);

    left,right, bootom,top 定义了 near 裁剪面大小,而 zNear 和 zFar 定义了从 Camera/Viewer 到远近两个裁剪面的距离(注意这两个距离都是正值)。由这六个参数可以定义出六个裁剪面构成的锥体,这个锥体通常被称之为视锥体或视景体。只有在这个锥体内的物体才是可以见的,不在这个锥体内的物体就相当于不再视线范围内,因而会被裁减掉,OpenGL 不会这些物体进行渲染。

    由于 OpenGL ES 2.0 不提供此函数,因此我们需要自己实现该函数。其计算公式如下:

    假设:l = left, r = right, b = bottom, t = top, n = zNear, f = zFar,有
2012120518243618

    在 OpenGL 中,我们可以通过工具库提供的 gluLookAt 该函数的原型为:

    gluLookAt(eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz);

    eye 表示 camera/viewer 的位置, center 表示相机或眼睛的焦点(它与 eye 共同来决定 eye 的朝向),而 up 表示 eye 的正上方向,注意 up 只表示方向,与大小无关。通过调用此函数,就能够设定观察的场景,在这个场景中的物体就会被 OpenGL 处理。在 OpenGL 中,eye 的默认位置是在原点,指向 Z 轴的负方向(屏幕往里),up 方向为 Y 轴的正方向。在接下来的教程 04 中,使用的就是这个默认设置。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引