前言
Android 系统中,不管任何一种View,其测量、滑动、绘制、布局都是按照父View左上角原点进行的,这种就是Android 默认的2D坐标体系,除此之外,Android还支持基于open gl es的3D坐标体系以及Camera 3D坐标体系。
关于坐标
实际上,Android系统中,如果设计Camera和open gl,我们可能会遇到总共4种坐标系统,因此,使用的时候需要提前了解。
2.1 Canvas 2D坐标系
正常情况下,Canvas 2D坐标系就是一张普通的画板,当然,其本身和软件绘制与硬件绘制也有关系,软件绘制时,Canvas的大小可能会大于View本身,因为Canvas时共享的,而硬件绘制是每个View拥有单独的RenderNode,从而避免了硬件绘制性能问题,以及Canvas 过大的问题。
- 左上角为(0,0)点
- 三角函数计算时顺时旋转
- y轴向下为正,x向左为正
- 向量表示(x,y)
- 坐标轴取值范围任意
2.2 Shader 坐标
Shader 坐标是最容被遗忘的,因为其本身作为画笔的一部份,不属于Canvas 直接调用,但其实Shader也是有坐标和范围大小,而且还能通过Canvas Matrix后者setLocalMatrix进行变幻。
Shader可以理解为印染工具,不会因为图形的绘制位置的偏移而偏移(排除Canvas 矩阵变换)。
2.3 Camera 3D坐标系
- 左上角为(0,0)点
- 属于3D坐标系统,但z轴向屏幕内方向
- 三角函数计算时逆时针旋转
- y轴向上为正,x向左为正,z轴向内为正
- 向量表示(x,y,z)
- 坐标轴取值范围任意
2.4 open gl 顶点坐标系(世界坐标系)
- View中心点为原点
- 属于3D坐标系,但存在两种坐标系统,左手坐标系和右手坐标系,左手坐标系看似和Camera坐标系
- 三角函数计算按逆时针旋转
- y轴向上为正,x向左为正,z轴取决于使用哪种坐标系统,一般的都是使用右手坐标系统。
- 默认正对(0,0,0,1)点,其中第四个分量为w,此分量表示顶点到Camera的缩放比例,注意不表示Camera的位置
- 向量表示(x,y,z,w),其中w分量会用来做点的缩放, (x/w,y/w,z/w),从而实现距离的调整
- 坐标轴取值范围-1.0到1.0
2.5 open gl 纹理坐标系
纹理本身就是材质的一部份,所谓纹理可以理解为对材质的坐标表示形式,通俗一点的讲,这种坐标系每张图片自身坐标系。
- 左下角为(0,0)点
- 三角函数计算时逆时旋转
- y轴向上为正,x向右为正
- 向量表示(x,y) 或(S,T)
- 坐标轴取值范围-1.0到1.0
关于矩阵
在Android系统中,矩阵实际上也分为2种android.graphics.Matrix 和android.opengl.Matrix ,前者为2D坐标系和Camera 3D坐标系所使用,当然有些图片处理也使用前者。
android.graphics.Matrix 和android.opengl.Matrix 相比,主要有以下特点:
3.1 graphics专门用来处理Android自身的坐标转换,当然,在开发过程中,通常调用matrix#preTranslate来对齐Camera和View的旋转点,而后者需要利用Matrix#multipleMM 修改投影矩阵,最终在Shader中修改位置向量。
3.2 graphics默认是三阶矩阵,向量为(x,y,z),而open gl是4阶矩阵,向量为(x,y,z,w)
3.3 矩阵表示形式存在差异,graphic控制点相对固定,而open gl 复杂一些。
3.4 数组表示差异 graphic的数组表示形式以行为准,open gl 以列为准,
数组
| 1 | 2 | 3 |
| 4 | 5 | 6 |
| 7 | 8 | 9 |
转为运算矩阵如下:
| 1 | 2 | 3 |
| 4 | 5 | 6 |
| 7 | 8 | 9 |
基本上顺序和数组一致
open gl的是是取转置矩阵,当然运算的时候不影响 数组
| 1 | 2 | 3 | 4 |
| 5 | 6 | 7 | 8 |
| 9 | 10 | 11 | 12 |
| 13 | 14 | 15 | 16 |
转为运算矩阵
| 1 | 5 | 9 | 13 |
| 2 | 6 | 10 | 14 |
| 3 | 7 | 11 | 15 |
| 4 | 8 | 12 | 16 |
因此,构建不同模式的矩阵时,要注意构建矩阵时的顺序问题。
Graphic 矩阵变化
Graphic矩阵一般在使用Canvas时才会使用,可以通过translate、rotate等方法进行坐标转换,但是这里要注意的是,一个错误的理解是“坐标系转换”,实际上是坐标的Matrix投影的转换。
Matrix有很多方法,基本都是矩阵运算,但仍然存在几个方法 Matrix#setPolyToPoly、Matrix#invert、Matrix#mapXXX、Matrix#setValues
- Matrix#setPolyToPoly 可以利用结果坐标和原始坐之间对应关系,生成结果投影矩阵
- Matrix#invert 计算逆矩阵,输出逆矩阵
- Matrix#mapXXX 通过现有矩阵计算出结果坐标,显然这类方法方便我们开发时观测数据变化
- Matrix#setValues 主要用于手动生成矩阵,注意,这里必须是3x3的矩阵
open gl 矩阵变化
open gl使用的4x4的矩阵,相对来说易用性和理解上比较差一些,但好处是在Android中该Matrix类矩阵都是java实现的,反而更容易观察运算过程。当然其中也有一些比较重要的矩阵。
- Matrix#setXXXM 在open gl矩阵类中,一般setXXXM的不是去修改矩阵,而是定义矩阵。例如setIdentityM定义单位矩阵,setLookAtM定义摄像机(眼睛)位置的矩阵,setRotateEulerM 定义初始旋转矩阵。
- 在open gl中,矩阵初始转换都是代码完成,最后在顶点着色器中右乘4维向量,这样做有很多原因,比如gpu运算快。
- open gl直线问题,我们知道open gl只能画(点、线、三角),但是“线”比较特殊,缺少一些中间过程(这里所谓的中间过程是 起点->终点 绘制时,点合三角会存在众多中间位置,gl_Position.x 也是动态变化的),但是线是不一样的,缺少这个过程,导致无法像点、圆、三角形那样实现过渡效果。
precision mediump float;
uniform vec4 u_Color;
varying float x;
void main()
{
if(x > 0.25){
gl_FragColor = u_Color;
}else if(x >= 0.0){
gl_FragColor = vec4(0.0,1.0,0.0,1.0);
} else if(x > -0.25){
gl_FragColor = u_Color;
}else if(x >= -0.6){
gl_FragColor = vec4(0.5,0.5,0.0,0.5);
}else {
gl_FragColor = u_Color;
}
}
从图上我们看到,除了正方形和点,线一直是红色,因此线条绘制相对特殊。
open gl es 归一化
open gl es 和 canvas 等坐标体系、矩阵体系是不同的,特别是open gl的顶点坐标范围(-1,1),因此open gl的绘制往往需要归一化处理,就是最大范围不超过1,最小不能超过-1,准确的表示是-1到1之间,这也是使用open gl时必须要注意的。
那么如何归一化呢,其实很简单
总结
以上就是完整的Android 系统坐标体系介绍,在我们实现特殊效果,免不了使用这些坐标系以及矩阵,因此,本篇对于学习自定义View,是一篇入门文章,但是也是必须了解的Android 绘制规则。
另外,上一篇文章我们了解了《 Egl Context 与 open gl 纹理关系》,也是一篇非常重要的基础内容,很多学习open gl 图像处理的同学,经常会很疑惑纹理为什么没有关联Egl Context,却能实现离屏渲染,原因就是通过线程进行了映射,底层将两者进行了关联。
本篇就到这里
附录
Android--利用camera打造3D效果
open gl 坐标系统
android matrix 最全方法详解与进阶