上一节中,我们遗留了一个Android适配的问题。 这个问题表现为我们创建的物体长宽比例如果与屏幕宽高比不一致的画,会被屏幕拉伸。
为什么会拉伸?
首先我们来认识齐次坐标
, 这个就是一个齐次坐标, 其中x, y, z 分别表示世界坐标系中x, y, z轴的坐标。 关于空间中一点的坐标,你可以想象下有一个原点,基于这个原点建立一个坐标系,而物体相对于该原点的位置就是这个坐标系下的坐标。
而w 简单来说,可以理解为一个尺度空间。 即如果w = 1时, 这个空间是与这个坐标系等同的空间;如果w = 2,即这个空间就会缩小一半。w越大,其空间其实越小, w越小,其空间为越大。 如果w为0 时, 那么x, y,z 全部趋于无穷, 即它们在无穷远, 再也回不来了。
关于齐次坐标,它其实可以用空间中的一条直线来表示即
即满足上式的一点 (x, y, z, 1)必在该直线上,如果等式两边同时乘以w 则,所表示的点(wx, wy, wz, w)也在该直线上,且为同一个点。
其次,了解下OpenGL管线流程中的坐标变换
一次是 clip变换,即通过 w 齐次坐标,将坐标缩放在尺度为1的空间里
一次为三维变换,即将clip后的坐标,映射为摄像机屏幕上的二维坐标。
一次为glViewport变换,即将二维坐标乘以屏幕的宽和高 变为屏幕上的图像。
对于clip变换,我们已经大体了解了,就是缩放。
而对于三维变换,又可分为两种: 透视变换 和 正交变换
关于这两种变换,可以形象的用一下两幅图来表示:
这两个图都是我们看到的三维世界, 但左图具有很强的透视效果,总体表现为近大远小的感觉。 空间中的点与摄像机光心连线与摄像机屏幕所交点即为屏幕的成像点(小孔成像原理), 因此,较近的物体总能形成较大像。
而右图由于离铁路较近,俯视正对,基本可近似为一个正交变换。 即所有的空间的点都是平行映射到屏幕上的, 这使得空间中点的Z轴失去作用。 所以,正交变换更适合二维图像。
分析我们之前的屏幕拉伸原因:
opengl中, clip变换后的点都在[-1. 1]之间, 因此,边界为-1或 1。只考虑宽和高的话, 则为一个 2x2的正方形。
也就是,物体所在空间的高比为1:1, 假如,我们的屏幕是2:1的, 则最后经过glViewport变换后,宽就被拉伸了2倍。
下文,我们称clip变换的空间为clip空间。
最后,来看下,正交变换矩阵:
其中, right, left, top, bottom, far, near 为 clip空间的边界。
我们假定空间中的一点为:
,(这里不考虑z轴坐标) 正交变换矩阵对该点作用(变换)后 ,新的坐标点为:
上式表示,变换后的x轴坐标, 不管x坐标为何,其变换后的点总会落在(left, right)之间。 opengl中,left为-1, right 为1。
同理有
轴坐标。
那么,进而可得出,如果屏幕的宽高比为aspect:1,则,应该让clip空间的bottom 为-aspect, top 为aspect。 反之,如果为1:aspect, 则应该让left 为-aspect, right为-aspect。
这样,经过正交变换后,映射到屏幕中的坐标经过glViewport 变换,就与屏幕的宽高比就为1:1,就不会出现拉伸的现象了。
————————————————————————————————————————————
知道了,上述原理后,我们来修改代码:
首先,在shader中添加 正交变换。
复制代码
为什么会拉伸?
首先我们来认识齐次坐标
![点击查看原图](http://www.arvrschool.com/attachment/1507/thread/66_18_4358127202fc7b0.png)
而w 简单来说,可以理解为一个尺度空间。 即如果w = 1时, 这个空间是与这个坐标系等同的空间;如果w = 2,即这个空间就会缩小一半。w越大,其空间其实越小, w越小,其空间为越大。 如果w为0 时, 那么x, y,z 全部趋于无穷, 即它们在无穷远, 再也回不来了。
关于齐次坐标,它其实可以用空间中的一条直线来表示即
![点击查看原图](http://www.arvrschool.com/attachment/1507/thread/66_18_6feea2f22a17217.png)
即满足上式的一点 (x, y, z, 1)必在该直线上,如果等式两边同时乘以w 则,所表示的点(wx, wy, wz, w)也在该直线上,且为同一个点。
其次,了解下OpenGL管线流程中的坐标变换
一次是 clip变换,即通过 w 齐次坐标,将坐标缩放在尺度为1的空间里
一次为三维变换,即将clip后的坐标,映射为摄像机屏幕上的二维坐标。
一次为glViewport变换,即将二维坐标乘以屏幕的宽和高 变为屏幕上的图像。
对于clip变换,我们已经大体了解了,就是缩放。
而对于三维变换,又可分为两种: 透视变换 和 正交变换
关于这两种变换,可以形象的用一下两幅图来表示:
![点击查看原图](http://www.arvrschool.com/attachment/1507/thread/66_18_e7aef788493b585.jpg)
这两个图都是我们看到的三维世界, 但左图具有很强的透视效果,总体表现为近大远小的感觉。 空间中的点与摄像机光心连线与摄像机屏幕所交点即为屏幕的成像点(小孔成像原理), 因此,较近的物体总能形成较大像。
而右图由于离铁路较近,俯视正对,基本可近似为一个正交变换。 即所有的空间的点都是平行映射到屏幕上的, 这使得空间中点的Z轴失去作用。 所以,正交变换更适合二维图像。
分析我们之前的屏幕拉伸原因:
opengl中, clip变换后的点都在[-1. 1]之间, 因此,边界为-1或 1。只考虑宽和高的话, 则为一个 2x2的正方形。
也就是,物体所在空间的高比为1:1, 假如,我们的屏幕是2:1的, 则最后经过glViewport变换后,宽就被拉伸了2倍。
下文,我们称clip变换的空间为clip空间。
最后,来看下,正交变换矩阵:
![点击查看原图](http://www.arvrschool.com/attachment/1507/thread/66_18_7e155ec60ab38b9.png)
其中, right, left, top, bottom, far, near 为 clip空间的边界。
我们假定空间中的一点为:
![点击查看原图](http://www.arvrschool.com/attachment/1507/thread/66_18_2e1bf730a363122.png)
![点击查看原图](http://www.arvrschool.com/attachment/1507/thread/66_18_19f2de3185718e2.png)
上式表示,变换后的x轴坐标, 不管x坐标为何,其变换后的点总会落在(left, right)之间。 opengl中,left为-1, right 为1。
同理有
![点击查看原图](http://www.arvrschool.com/attachment/1507/thread/66_18_e59c2866a36d419.png)
那么,进而可得出,如果屏幕的宽高比为aspect:1,则,应该让clip空间的bottom 为-aspect, top 为aspect。 反之,如果为1:aspect, 则应该让left 为-aspect, right为-aspect。
这样,经过正交变换后,映射到屏幕中的坐标经过glViewport 变换,就与屏幕的宽高比就为1:1,就不会出现拉伸的现象了。
————————————————————————————————————————————
知道了,上述原理后,我们来修改代码:
首先,在shader中添加 正交变换。
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
|
attribute vec4 a_Position;
attribute vec4 a_Color;
|