OpenGL ES 2.0 入门(持续更新)

版权声明:本文为“剑西”原创文章,转载需注明出处! https://blog.csdn.net/mabeijianxi/article/details/79186086
请尊重原创,转载请注明出处:http://blog.csdn.net/mabeijianxi/article/details/79186086

发现公司不管是游戏业务还是视频业务无不与 Open GL 息息相关,于是每周抽了点时间操练下,万一哪天被点将点中了也是不虚的,下面是笔者的一些学习笔记。

一、Open GL 2.0 的渲染管道

Created with Raphaël 2.1.2 基本处理 顶点着色器 图元装配 光栅化 片原着色器 剪裁测试 深度测试、模板测试 颜色混合 抖动 帧缓冲

1、基本处理

基本处理主要对顶点坐标、顶点颜色、顶点纹理坐标等属性赋值,并制定绘制方式,如三角形、线段、点等。

2、顶点着色器

2.0的顶点着色器整合了 1.0 中的顶点变换、光照计算,变成了可编程的形式了,主要是进行变换、光照计算、材质的应用与计算等顶点相关的操作,并将处理后的信息传递给图元装配。

3、图元装配

图元装配主要有两个任务,一个是图元组装,一个是图元处理。图元组装是根据绘制方式把顶点数据组装成完整的图元,比如三角形,需要三个顶点组成一个图元。图元处理主要是对图元进行剪裁,因为根据观察位置和角度的不同,看到的物体形状也不同,一个三角形可能会被剪裁成4边形,这时候就成了四个顶点了。

4、光栅化

屏幕是2D的,在光栅化之前会把3D的物体投影到2平面上,然后后理是把连续的数学量转换为离散的数学量,因为电子屏幕的像素点是一个一个的,这些离散的量就叫片原,其实就是候选像素。因为可能有很多的图元,同一位置也可能有很多的片原,但是只会有一个片原成为最后的像素,所以才叫候选像素,具体的还需要进行计算对比。

5、片原着色器

片原着色器主要是执行纹理的采样、颜色的汇总、计算雾颜色等操作,每个片原执行一次。

6、剪裁测试

如果程序设定了剪裁测试,并当前片原在帧缓存中对应的位置在剪裁窗口中就进入下一阶段、否则丢弃。

7、深度测试、模板测试

如果帧缓存中同一位置有n个图元那么深度值小的将会被送入下一阶段,反之丢弃,深度就是离摄像机的距离,想象一下,距离近的肯定是挡住了距离远的,距离远的肯定就没必要存在了。模板测试主要功能为将绘制区域限定在一定范围内,一般用在湖面倒影、镜像等场合。

8、颜色缓冲混合

若程序开启了Alpha 混合,则根据混合因子将上一阶段送来的片原与帧缓冲中对应位置的片原进行Alpha混合;否则后来的覆盖帧缓存中当前的。

9、抖动

暂时略

10、帧缓冲

Open GL ES 中的物体并不是直接绘制在屏幕上的,而是预先在帧缓冲区进行绘制,没绘制完一帧再把结果交换到屏幕上。帧缓冲主要包括:颜色缓冲、深度缓冲、模板缓冲。


——2018.02.03更

二、着色语言(Shading Language):

与传统通用编程语言有很大不同的是,其提供了更加丰富的原生类型,如向量、矩阵等。这些新特性的加入使得 OpenGL ES 着色语言在处理3D图形方面更加高效、易用。简单俩说,OpenGL ES 着色语言包括以下特性。

  • OpenGL ES 着色语言是一种高级的过程语言。
  • 对顶点着色器、片元着色器使用的是同样的语言,不做区分。
  • 基于 C/C++的语言及流程控制。
  • 完美支持向量与矩阵的各种操作。
  • 通过类型限定符来管理输入输出(attribute、uniform、varying)
  • 拥有大量的内置函数来提供丰富的功能(有些是基于硬件的,速度非常快)。

着色语言基础

数据类型概述:

OpenGL ES 着色语言虽然是基于C/C++ 语言的语言,但是其与C/C++ 相比还是有很大不同的,该语言不支持 double、byte、short、long并取消了 union、enum、unsigned、以及位运算。其支持的类型主要分为:标量、向量、矩阵、采样器、结构体、数组。

1、标量

也叫无向量,只有大小没有方向。有 bool、int、float.

2、向量

向量可以看成是同样类型的标量组成的,其基本类型也分为 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 的向量

向量可以很方便的存储颜色、位置、纹理坐标等,访问其某个分量的语法为 <向量明>.<分量名>,根据目的不同主要分为以下几种:

  • 你要是把这个向量当成颜色来看的话,他们的分量名字就是 r、g、b、a或者r、g、b或者、r、g,其取决于定义的维度。
vec4 aColor;
aColor.r=0.1;
aColor.b=0.5;
  • 要是当成位置看的话,用 x、y、z、w 四个分量明,w表示向量的模,和上面一样维度也决定了其分量个数。
vec4 aPosion;
aPosion.x=88.88;
aPosion.y=11.11;
  • 若将一个向量看作纹理坐标,可以使用s、t、p、q等四个分量来表示,维度决定其分量个数。
vec4 aPosion;
aPosion.s=0.22;
aPosion.t=0.11;
3、矩阵

很多动画和矩阵都有着关系,向位移、旋转、缩放等变换都是由矩阵运算来实现的,矩阵变换其实就是物体在规定的空间按照一定的规则(规则也就是一个或者多个矩阵)就行移动或者说叫跳跃,其实移动、跳跃都不是很准确,就是一个位置跑到另外一个位置的过程。其表示方法如下:

矩阵类型 说明
mat2 2 x 2 的浮点数矩阵
mat3 3 x 3 的浮点数矩阵
mat4 4 x 4 的浮点数矩阵

着色语言中,矩阵是按列顺序组织的,也就是一个矩阵可以看成是几个列向量组成的。例如,mat3 就可以看作由 3个vec3组成的。
对于矩阵的访问,可以将矩阵作为列向量的数组来访问。如 matrix 为一个 mat4,可以使用 matrix[2]取到该矩阵的第三列,其为一个 vec4。也可以使用 matrix[0][1]取得1列的第二个分量。

4、采样器

其专门用来进行纹理采样的相关操作。一般情况下,一个采样器代表一副或者一套纹理贴图,如下:

采样器类型 说明 采样器类型 说明
sampler2D 用于访问二维纹理 samplerCube 包含四个 int 的向量
sampler3D 用于访问三维纹理

采样器不能在着色器中初始化,一般采样器都是 uniform 限定符来修饰,从宿主语言接受传递进着色器的值。

5、结构体

着色语言的结构体和c中是差不多的。

struct info{
vec3 color;
vec3 position;
vec2 textureCoor;
}
6、数组

其使用和声明和其他语言差不多。下面说下一些特殊的地方。

  • 使用的时候可以定义一个大小不一定的数组,但在使用的时候需要为其设定大小:
vec3 position[];
vec3 postion[2]; //再次声明,并且指定大小
  • 代码中访问素组的下标都是编译时常量,这时编译器会自动创建适当大小的数组,使得数组尺寸足够储存看到的最大索引值对应的元素,这种系统量体裁衣、自动分配的方法若恰当采用可以提高硬件的使用效率,降低对硬件资源的消耗:
vec3 position[];
vec3 postion[2] = vec3(3.0); // 容器大小为3了
vec3 postion[20] = vec3(1.0);//容器大小为21了
7、空类型

void

数据类型的基本使用

  • 系统中很多变量的命名都是以“gl_”作为开头的,因此用户自定义的变量不允许使用“gl_”作为开头。
  • 一些初始化技巧:
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)
  • const 限定符修饰的变量必须在声明的时候进行初始化。
  • 属性变量、一致变量、易变变量在声明的时候一定不能进行初始化。(attribute、uniform、varying)
  • 混合选择,如下示例:
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)

限定符:

  • attribute 用于描述顶点的信息,如位置、颜色、法向量等,只能用于顶点着色器中,不能在片元着色器中使用,且 attribute 限定符只能用来修饰浮点数标量、浮点数向量以及矩阵变量。2.0中规定了所有实现应该支持的属性个数不能少于8个。
  • uniform 用于指定同一组顶点的单个3D物体中中所有顶点都相同的量,一般为光源位置、当前摄像机位置、投影矩阵等。2.0中也规定了所有实现应该支持的顶点着色器中uniform不能少于128个,片元(todo…)
  • varying 变量用于从顶点着色器把数据把数据出入片原着色器,如片原的颜色、法向量、纹理坐标等任意值
  • const 用于声明常量

片元着色器中浮点变量精度的指定

片元着色器中使用浮点相关类型的变量时与顶点着色器中有所不同,在顶点着色器中直接声明使用即可,而在片元着色器中必须指定精度,若不指定精度可能会引起编译错误。指定方式如下:

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_Position 顶点着色器中经过变换后得到的新的顶点位置。类型为 vec4
  • gl_PointSize 顶点着色器中可以计算一个点的大小,单位为像素,并将其赋值给 gl_PointSize,如果没赋值默认是1,一般采用点绘制的时候才有意义。

片元着色器中的内建变量

片元着色器有输入和输出两种内建变量。

1、内建输入变量

片元着色器中的内建变量主要有gl_FragCoord 以及 gl_FrontFacing。这两个内建变量都是只读的。

  • gl_FragCoord(vec4类型)中含有当前片元相对于窗口位置的坐标信息 x、y、z、1/w。其中z代表深度,也就是距离摄像机的距离。
  • gl_FrontFacing 是一个布尔型的内建变量,通过读取该内建变量的值可以判断正在处理的片元是否在光栅化阶段生成此片元的对应图元的证明。如果输入证明值就是 true.
2、内建输出变量

片元着色器中的内建输出变量主要有 gl_FragColor 与 gl_FragData,在片元着色器中根据情况需要给它赋值。

  • gl_FragColor是 vec4类型,其是由片元着色器写入计算完成的片元颜色值,此颜色值将送入渲染管线的后续阶段进行处理。
  • gl_FragData 内建变量是一个 vec4 类型数组,写入时要给出下标。
    实际开发中只需要为两个中的一个赋值即可。

着色语言的内置函数

其内置的函数通常都是以最优方式实现的,有部分函数有硬件直接支持,效率贼高。内置函数按照设计目的可以分为以下3个类别。

猜你喜欢

转载自blog.csdn.net/mabeijianxi/article/details/79186086
今日推荐