专栏名称: dearmiku
iOS开发攻城狮
目录
相关文章推荐
51好读  ›  专栏  ›  dearmiku

OpenGL ES on iOS --- 坐标系统与矩阵转换

dearmiku  · 掘金  ·  · 2017-12-14 10:58

正文

简述

本文记录我记录我学习 坐标体系和矩阵转换的过程,加深学习便于后续查询,可能有些描述不够准确,或者内容不够充实,还请多多指正,共同学习

矩阵变换

我们将物体坐标进行一系列变换,达到自己期望的位置,需要使用到矩阵.先说一下矩阵的公式.这里我是本着了解的心态去学习的,因为已经有趁手的数学工具了,把重要的学完~ 我会再来研究这里的.

矩阵相乘

这是一个简单的矩阵相乘例子,

例子

这是矩阵乘法过程~

矩阵乘法过程

注意:

1, 矩阵相乘不遵守交换律 即 A * B ≠ B * A 2, 只有当左侧矩阵列数 等于 右侧矩阵行数 两矩阵才能相乘.

在我们对坐标进行缩放,位移,旋转 等变换时,我们多用4x4矩阵来进行~

缩放

我们把缩放变量表示为(S1,S2,S3)我们可以为任意向量(x,y,z)定义一个缩放矩阵:

缩放矩阵

位移

如果我们把位移向量表示为(Tx,Ty,Tz),我们就能把位移矩阵定义为:

位移矩阵

旋转

绕X轴旋转

x轴旋转

绕y轴旋转

y轴旋转

绕z轴旋转

z轴旋转

将旋转分为绕3个轴进行旋转,以达到自己希望的位置,见下面这个公式,(Rx,Ry,Rz)代表任意旋转轴:

任意旋转

这种处理方式,简单容易理解,但是 会出现一个问题 万向节死锁 .

举个栗子~ 加入在三维空间中有一个平行于X中的向量,然后将它绕Y轴旋转至它平行于Z轴,这时绕z轴的任何旋转都不会改变 向量的方向了. 在正常情况下,关于3个轴的旋转过程应该是可以任意组合的,最终旋转结果都是一致的,但是当出现了万向节死锁后, 就会导致各个轴旋转顺序 组合不同,而最终旋转结果不同~ 大家可以找根笔试一试~也可以看看这里: 欧拉角与万向节死锁(图文版

那么如何解决呢~ 使用四元数 旋转矩阵与四元数 因为复变函数早已还给老师~ 后续再研究补充~~

齐次坐标

在上面关于描述3D坐标的向量 是四维向量,多出一个分量w,w分量的用处是来创造3D视觉效果的,根据w分量的大小对物体进行拉伸,最后将w=1的截面进行展示,从而产生物体远近效果. 这篇文章我觉得介绍的比较详细 写给大家看的“透视除法” —— 齐次坐标和投影

组合

我将不同变换的矩阵组合起来~ 将一个放大2倍的矩阵 和位移(1,2,3)的矩阵组合起来~,得到新的变换矩阵

矩阵组合

将得到的变换矩阵 进行验证

矩阵验证

因为矩阵相乘是不遵守 交换律 的,所以在矩阵组合时,顺序就十分重要, 建议 先缩放 --> 再旋转 --> 再位移. 并且矩阵的顺序是从右到左的 所以应该是 位移矩阵 * 旋转矩阵 * 缩放矩阵 = 所需矩阵

补充

为什么我们要用矩阵来进行着一系列的变换呢? 据我了解 是因为这样做,将 旋转,位移,缩放加以统一.简化计算流程,提高计算机的计算效率.

最后总结:像这样利用矩阵进行位移,缩放,旋转 这一系列的变换叫做: 仿射变换

坐标体系

OpenGL 顶点着色器 希望接受的的顶点 都是 标准化设备坐标 (Normalized Device Coordinate, NDC)的坐标,也就是(x,y,z)都是在 -1~1之间变换.在此之外的顶点丢弃,并且按照传入的顶点进行绘制.

将3D的物体坐标转换到理想的绘制效果需要进行一些列的转换过程. 局部空间(Local Space)/物体空间(Object Space) ---> 世界空间(World Space) ---> 观察空间(View Space)/视觉空间(Eye Space) --->裁剪空间(Clip Space) ---> 屏幕空间(Screen Space)

OpenGL是不提供数学工具的~ 我们可以使用 GLM(OpenGL Mathematics) GLM官网 我用的是0.9.9版本~

示意图:

坐标空间变换

局部空间

局部空间: 就表示物体在自己本身坐标系里的坐标,比较像view的bounds属性.可以理解为建模时模型的坐标.

世界空间

世界空间: 表示物体需要展示世界里的坐标,比较像view的frame属性,好比我们的模型是个房子,将它放到小镇(世界)中, 这时它的坐标就是在世界空间的坐标.

将局部空间坐标转换为世界空间坐标需要进行一系列转换,就像在象棋棋盘上放棋子,我们需要将棋子旋转,位移...操作才能将棋子放到正确的位置上.

观察空间

在最终展示时,我们展示的是用户观察的界面, 我们需要将世界空间的坐标 转换为 以用户坐标观察视野产生的结果.

裁剪空间

在OpenGL 中所期望的坐标是 标准化设备坐标, 所以我们 需要将自己的坐标集进行转换,将需要显示的坐标 落在 -1.0~1.0之间.

如果只是图元(Primitive),例如三角形,的一部分超出了裁剪体积(Clipping Volume),则OpenGL会重新构建这个三角形为一个或多个三角形让其能够适合这个裁剪范围,就像三角形的角被切了一刀变成四边形那样~

投影

在裁剪时,我们是将3D空间的物体 转换为 2D空间的平面图像, 这样的过程叫做投影, 像投影截取的显示的3D空间 平截头体 ,它就像一个容器,在这里面的所有坐标都不会被裁剪掉~







请到「今天看啥」查看全文