发现公司不管是游戏业务还是视频业务无不与 Open GL 息息相关,于是每周抽了点时间操练下,万一哪天被点将点中了也是不虚的,下面是笔者的一些学习笔记。
基本处理主要对顶点坐标、顶点颜色、顶点纹理坐标等属性赋值,并制定绘制方式,如三角形、线段、点等。
2.0的顶点着色器整合了 1.0 中的顶点变换、光照计算,变成了可编程的形式了,主要是进行变换、光照计算、材质的应用与计算等顶点相关的操作,并将处理后的信息传递给图元装配。
图元装配主要有两个任务,一个是图元组装,一个是图元处理。图元组装是根据绘制方式把顶点数据组装成完整的图元,比如三角形,需要三个顶点组成一个图元。图元处理主要是对图元进行剪裁,因为根据观察位置和角度的不同,看到的物体形状也不同,一个三角形可能会被剪裁成4边形,这时候就成了四个顶点了。
屏幕是2D的,在光栅化之前会把3D的物体投影到2平面上,然后后理是把连续的数学量转换为离散的数学量,因为电子屏幕的像素点是一个一个的,这些离散的量就叫片原,其实就是候选像素。因为可能有很多的图元,同一位置也可能有很多的片原,但是只会有一个片原成为最后的像素,所以才叫候选像素,具体的还需要进行计算对比。
片原着色器主要是执行纹理的采样、颜色的汇总、计算雾颜色等操作,每个片原执行一次。
如果程序设定了剪裁测试,并当前片原在帧缓存中对应的位置在剪裁窗口中就进入下一阶段、否则丢弃。
如果帧缓存中同一位置有n个图元那么深度值小的将会被送入下一阶段,反之丢弃,深度就是离摄像机的距离,想象一下,距离近的肯定是挡住了距离远的,距离远的肯定就没必要存在了。模板测试主要功能为将绘制区域限定在一定范围内,一般用在湖面倒影、镜像等场合。
若程序开启了Alpha 混合,则根据混合因子将上一阶段送来的片原与帧缓冲中对应位置的片原进行Alpha混合;否则后来的覆盖帧缓存中当前的。
暂时略
Open GL ES 中的物体并不是直接绘制在屏幕上的,而是预先在帧缓冲区进行绘制,没绘制完一帧再把结果交换到屏幕上。帧缓冲主要包括:颜色缓冲、深度缓冲、模板缓冲。
——2018.02.03更
与传统通用编程语言有很大不同的是,其提供了更加丰富的原生类型,如向量、矩阵等。这些新特性的加入使得 OpenGL ES 着色语言在处理3D图形方面更加高效、易用。简单俩说,OpenGL ES 着色语言包括以下特性。
OpenGL ES 着色语言虽然是基于C/C++ 语言的语言,但是其与C/C++ 相比还是有很大不同的,该语言不支持 double、byte、short、long并取消了 union、enum、unsigned、以及位运算。其支持的类型主要分为:标量、向量、矩阵、采样器、结构体、数组。
也叫无向量,只有大小没有方向。有 bool、int、float.
向量可以看成是同样类型的标量组成的,其基本类型也分为 bool、int、float 3种,在c语言或者其他语言中都可以构建相应的数据结构在实现向量,但是着色器中的向量不同,其由硬件原生支持,进行向量运算时效率提高很多。每个向量可以由2个、3个或者4个相同的标量组成,如表:
向量类型 | 说明 | 向量类型 | 说明 |
---|---|---|---|
vec2 | 包含了两个 float 的向量 | ivec4 | 包含四个 int 的向量 |
vec3 | 包含了3个 float 的向量 | bvec2 | 包含两个 bool 的向量 |
vec4 | 包含了4个 float 的向量 | bvec3 | 包含三个 bool 的向量 |
ivec2 | 包含了两个 int 的向量 | bvec4 | 包含四个 bool 的向量 |
ivec3 | 包含三个 int 的向量 |
向量可以很方便的存储颜色、位置、纹理坐标等,访问其某个分量的语法为 <向量明>.<分量名>,根据目的不同主要分为以下几种:
vec4 aColor;
aColor.r=0.1;
aColor.b=0.5;
vec4 aPosion;
aPosion.x=88.88;
aPosion.y=11.11;
vec4 aPosion;
aPosion.s=0.22;
aPosion.t=0.11;
很多动画和矩阵都有着关系,向位移、旋转、缩放等变换都是由矩阵运算来实现的,矩阵变换其实就是物体在规定的空间按照一定的规则(规则也就是一个或者多个矩阵)就行移动或者说叫跳跃,其实移动、跳跃都不是很准确,就是一个位置跑到另外一个位置的过程。其表示方法如下:
矩阵类型 | 说明 |
---|---|
mat2 | 2 x 2 的浮点数矩阵 |
mat3 | 3 x 3 的浮点数矩阵 |
mat4 | 4 x 4 的浮点数矩阵 |
着色语言中,矩阵是按列顺序组织的,也就是一个矩阵可以看成是几个列向量组成的。例如,mat3 就可以看作由 3个vec3组成的。
对于矩阵的访问,可以将矩阵作为列向量的数组来访问。如 matrix 为一个 mat4,可以使用 matrix[2]取到该矩阵的第三列,其为一个 vec4。也可以使用 matrix[0][1]取得1列的第二个分量。
其专门用来进行纹理采样的相关操作。一般情况下,一个采样器代表一副或者一套纹理贴图,如下:
采样器类型 | 说明 | 采样器类型 | 说明 |
---|---|---|---|
sampler2D | 用于访问二维纹理 | samplerCube | 包含四个 int 的向量 |
sampler3D | 用于访问三维纹理 |
采样器不能在着色器中初始化,一般采样器都是 uniform 限定符来修饰,从宿主语言接受传递进着色器的值。
着色语言的结构体和c中是差不多的。
struct info{
vec3 color;
vec3 position;
vec2 textureCoor;
}
其使用和声明和其他语言差不多。下面说下一些特殊的地方。
vec3 position[];
vec3 postion[2]; //再次声明,并且指定大小
vec3 position[];
vec3 postion[2] = vec3(3.0); // 容器大小为3了
vec3 postion[20] = vec3(1.0);//容器大小为21了
void
float a=11.1;
vec2 va=vec2(2.3,2.2);
vec3 vc=vec3(2.5,va);
vec4 ve=vec4(0.5); //相当于 vec4(0.5,0.5,0.5,0.5);
mat2 ma=mat2(1.0,2.0,5.0,9.0);
mat2 mb=mat2(vec2,vec2);
mat2 mc=mat2(0.1);//相当于 mat2(0.1,0,0,0.1)
vec4 color= vec4(0.2,0.3,0.7,1.0)
vec3 temp=color.agb //temp 现在等于(1.0,0.3,0.7)
vec4 tempL=color.aabb //tempL 现在等于(1.0,1.0,0.7,0.7)
vec3 tempLL;
tempLL.grb=color.aba //tempLL 现在等于(0.7,1.0,1.0)
float f0=1
这就会产生错误,可以 float f0=float(1)
片元着色器中使用浮点相关类型的变量时与顶点着色器中有所不同,在顶点着色器中直接声明使用即可,而在片元着色器中必须指定精度,若不指定精度可能会引起编译错误。指定方式如下:
lowp float color; //指定名称为color的float型变量为lowp
varying mediump vec2 coord; // 指定名称为 coord 的 vec2型变量精度为 mediump
highp mat4 m; // 指定名称为m的mat4型变量精度为 highp
如果在开发中同一个片元着色器中浮点相关类型的变量都选用同意精度,则可以指定整个着色器中浮点相关类型的默认精度,语法如下:
precision <精度><类型>
着色器提供了一些用来满足特定需求的内建变量。这些内建变量不需要声明即可使用,一般用来实现渲染管线固定功能部分与自定义顶点或片元着色器之间的信息交互。
内建变量根据信息传递的方向可以分为两类,输入与输出变量。输入变量负责将渲染管线中固定功能部分产生的信心传递进着色器,输出变量负责将着色器产生的信息传递给渲染管线中固定功能部分。
顶点着色器中主要是输出变量,包含gl_Position、gl_PointSize 等。在顶点着色器中应该根据需要给这些内建变量赋值,以便由渲染管线中的图元装配与光栅化等后续固定功能阶段进行进一步的处理。
片元着色器有输入和输出两种内建变量。
片元着色器中的内建变量主要有gl_FragCoord 以及 gl_FrontFacing。这两个内建变量都是只读的。
片元着色器中的内建输出变量主要有 gl_FragColor 与 gl_FragData,在片元着色器中根据情况需要给它赋值。
其内置的函数通常都是以最优方式实现的,有部分函数有硬件直接支持,效率贼高。内置函数按照设计目的可以分为以下3个类别。