Learn OpenGLES: 正交变换
来源:互联网 发布:ubuntu官方下载地址 编辑:程序博客网 时间:2024/05/16 15:38
上一节中,我们遗留了一个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中添加 正交变换。
复制代码有线性代数的基本知识,知道 一个4x4的矩阵,乘以一个4x1的坐标为一个4x1的坐标, 这中间其实完成了一个变换,就像上面我们讲的原理一样。
接着,定义变量:
复制代码这里定义变换矩阵为一个大小为16的数组,表示4x4的矩阵, 其中前四个元素表示矩阵的第一列,以此类推。
然后, 在onSurfaceCreated里, 找到shader里投影矩阵的位置,
复制代码
在onSurfaceChanged,根据屏幕的宽高比定义 正交变换矩阵:
复制代码
orthoM 是我们静态库, android.opengl.Matrix里的函数,它的源代码基本就是上述的公式。它的参数,第一个,是我们传递的数组, 第二个是数组的起始位置,后面依此为clip空间的 left, right, bottom, top , near, far。
最后,在onDrawFrame里添加:
复制代码
看一下效果:
比起上一帖的竖屏是不是好多了。
为什么会拉伸?
首先我们来认识齐次坐标
, 这个就是一个齐次坐标, 其中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中添加 正交变换。
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
attribute vec4 a_Position;
attribute vec4 a_Color;
uniform mat4 u_Projection;
varying vec4 v_Color;
void
main()
{
v_Color = a_Color;
gl_Position = u_Projection*a_Position;
}
接着,定义变量:
复制代码
1
2
3
private
static
final
String U_PROJECTION =
"u_Projection"
;
private
int
uProjectionLocation;
private
final
float
[] projectionMatrix =
new
float
[
16
];
然后, 在onSurfaceCreated里, 找到shader里投影矩阵的位置,
复制代码
1
uProjectionLocation = glGetUniformLocation(program, U_PROJECTION);
在onSurfaceChanged,根据屏幕的宽高比定义 正交变换矩阵:
复制代码
1
2
3
4
5
6
7
8
9
10
final
float
aspectRatio = width>height ?
(
float
) width / (
float
) height:
(
float
) height/(
float
) width;
if
(width > height)
{
orthoM(projectionMatrix,
0
, -aspectRatio, aspectRatio, -1f, 1f, -1f, 1f );
}
else
{
orthoM(projectionMatrix,
0
, -1f, 1f, -aspectRatio, aspectRatio, -1f, 1f);
}
orthoM 是我们静态库, android.opengl.Matrix里的函数,它的源代码基本就是上述的公式。它的参数,第一个,是我们传递的数组, 第二个是数组的起始位置,后面依此为clip空间的 left, right, bottom, top , near, far。
最后,在onDrawFrame里添加:
复制代码
1
glUniformMatrix4fv(uProjectionLocation,
1
,
false
, projectionMatrix,
0
);
// 将矩阵传递给shader
看一下效果:
比起上一帖的竖屏是不是好多了。
0 0
- Learn OpenGLES: 正交变换
- 正交变换
- Learn OpenGLES: HelloWorld
- Learn OpenGLES:画三角形
- Learn OpenGLES:颜色渐变
- 图像正交变换
- 正交投影与变换
- 关于正交变换和正交矩阵
- OpenGLES demo - 9. 矩阵变换
- opengles基本变换的实质
- 正交变换——来龙去脉
- 图像的正交变换----傅立叶变换
- 图像的正交变换---离散余弦变换
- 对OpenGLES中的空间变换的理解
- 傅立叶变换的实质-正交之美
- 傅立叶变换的实质-正交之美
- 傅立叶变换的实质-正交之美
- 矩阵论基础知识2(正交、 Givens 变换、Householder变换)
- C/C++中extern关键字详解
- 谈谈虚幻引擎4的Global Illumination
- thinkphp下网站建设笔记
- openstack git
- 《MFC游戏开发》笔记五 定时器和简单动画
- Learn OpenGLES: 正交变换
- UnrealEngine3-渲染构架
- innobackupex备份恢复详解
- 8月能否成为翻身月
- HDU1083 Courses 二分匹配
- Python学习之生成器
- 移植u-boot-2015.07-rc3之增加smdk2440开发板框架支持(一)
- Python IDE:PyCharm中的那些实用功能
- Java的8中封装类(未完待续)