参考:Learn OpenGL
简介OpenGL ES是一套图形硬件的软件接口,它直接跟GPU交互。
它是OpenGL图形库的一个子集,通常应用与嵌入式和手持设备,比如手机,平板电脑等。
它的主要作用是将3D场景绘制到2D屏幕中,版本主要有两种:
1.x的版本主要是固定渲染管线, 它是不支持人们对渲染流程进行干预的。
2.0以上的版本是可编程渲染管线, 通过修改顶点着色器和片段着色器制作更加炫酷的效果。
可编程渲染管线主要通过Shader来实现,它是一种类C语言。在OpenGL中主要通过GLSL语言编写。
渲染管线主要将3D转换为2D渲染到屏幕上,大致阶段:
每个阶段均已上个阶段的数据进行计算。简要的说明下:
顶点数据:
包含顶点坐标、颜色、法线向量及纹理坐标等,是渲染管线数据的主要来源
顶点着色器:
-
执行坐标转换,将本地坐标根据模型视图变换矩阵转换为裁剪坐标系,其数据会被保存在GLSL的内置变量gl_Position中
-
将可变变量(varying)数据经过插值计算后传递给片段着色器, 在使用中一定要保证顶点和片段着色器变量类型的统一性
图元组装:
将顶点数据根据图元类型,组装为指定类型的图元。 常见的图元类型有:
- POINTS: 点
- LINES: 未连接的线段
- LINE_LOOP: 闭合且连接的选段
- LINE_STRIP: 未连接的线段
- TRIANGLE_STRIP: 链接的三角形
- TRIANGLE_FAN: 扇形三角形
- TRIANGES: 未连接的三角形
在转换图元的过程中,丢弃在裁剪坐标系以外的;与裁剪坐标系相交的,会对图元执行裁剪,生成新的图元。
在该阶段以后,所有的3D图元会被转换为2D图元。
光删化:
将图元转换为一系列的片段, 并计算出每个片段的坐标位置,以决定片段是否位于图元之内。
在计算的过程中,片段的坐标位置因为精度丢失的问题,可能会导致图元边缘出现锯齿。
可通过多重采样来解决该问题, 与单重采样相比,它会基于附近多个位置的采样进行计算。
Cocos2d-x 默认是不开启的, 开启的参数是: multiSampling.
注意: 此处的每个片段可以理解为每个像素点
片段着色器:
为图元内的每个片段(像素)进行着色, 其颜色数据会被写入gl_FragColor中
它是实现高级特效(如,纹理贴图, 光照, 阴影等功能)的地方。
测试与混合:
会经过多个阶段的测试 *** 作,这些 *** 作会丢失片段或者修改片段的颜色值。主要有:
- 裁剪测试:检测片段是否在设定的裁剪窗口内, 如果没有则丢失
- 透明度测试:检测片段的透明度是否符合条件
- 深度测试:检测片段的前后遮挡关系, 比如前后窗口遮挡, 如果被遮挡则不会显示
- 模版测试: 检测当前片段的模版值是否与模版缓冲区的模版值相对应
它是一种类C的程序语言, 由于实时绘制程序对性能极度敏感, 因为该语言相较于C语言有着诸多的限制:
- 不支持精度更高的double
- 不支持引用,指针,比如&、*、->
- 不支持字符串 *** 作
- 不支持隐式转换
- 有限数组的使用
它是一种强类型语言, 因此变量和方法在使用之前必须定义它,且每个变量必须有特定的类型。
数据类型:
示例:
//------------------------- 标量 ------------------------- int c = 10; float d = 1.0; // 注意float跟int, 浮点型一定要加上小数点 bool isExist = bool(d); // 使用()将float转换为bool类型 // ------------------------- 向量 ------------------------- // 主要用于颜色、法线、位置、纹理坐标等,类型可为float, int, bool等,支持2~4个数据。 // 初始化向量可以使用: () ivec3 a = vec3(1); // a = {1, 1, 1} vec3 b = vec3(1.5, 2.4, 4.0); // b = {1.5, 2.4, 4.0} vec3 c = vec3(b); // c = {1.5, 2.4, 4.0} vec3 d = b.xyz; // d = {1.5, 2.4, 4.0} vec3 e = b.xyx; // e = {1.4, 2.4, 1.4} vec4 f = vec4(c, 5.0); // 用vec3的变量和float变量初始化vec4 // 标量可以和向量交互使用 float f; vec2 v,u; u = v * f; // 等价于: u.x = v.x * f; u.y = v.y * f; // ------------------------- 矩阵 ------------------------- // 成员只能为浮点型数据 mat3 data1 = mat3( 1.0, 0.0, 1.0, 2.0, 0.0, 2.0, 3.0, 0.0, 3.0, ); // data1 = {1.0, 0.0, 1.0, 2.0, 0.0, 2.0,3.0, 0.0, 3.0,} mat2 data2 = mat2(1.0); // data2 = {1.0, 1.0, 1.0, 1.0} // 向量可以和矩阵交互使用 vec3 v, u; mat3 m; u = v * m; // 等价于 u.x = m[0].x * v.x + m[1].x * v.y + m[2].x * v.z; // u.y = m[0].y * v.x + m[1].y * v.y + m[2].y * v.z; // u.z = m[0].z * v.x + m[1].z * v.y + m[2].z * v.z; // ------------------------- 结构体 ------------------------- struct myst { float num; vec3 color; }; myst st; myst st1 = myst(float(1.0), vec3(1.0, 1.0, 1.0)); // ------------------------- 数组 ------------------------- // 不能在声明时,直接初始化数组 int a[3]; a[0] = 1;
*** 作符:
限定符:
共有三种:in, out, inout, 分别表示输入, 输出, 输入输出。
在没有指定修饰符的情况下,默认为in
void func(float num) // 等价于 in float num { // }
精度限定符:
使用的时候, 要预先进行声明
#ifdef GL_ES precision lowp float; // 表示使用低精度, 精度越高, 图像越清晰但是相应的计算量也越大 #endif
修饰符:
可放在变量类型的前面, 主要有如下几种:
- const: 仅能用于本地变量和函数参数中, 结构体成员和函数返回值不能使用。它必须在定义时被初始化, 使用const有助于外部程序为其赋值导致不必要的错误。
const vec3 data = vec3(1.0);
-
attribute: 仅能由应用程序传递给顶点着色器,且不能在其他任何类型的着色器程序中使用。
在顶点着色器中为只读状态, 不可修饰数组和结构体类型, 应用程序主要传递颜色, 位置, 法线等数据
attribute vec4 a_position; attribute vec4 a_color;
-
uniform: 由应用程序在运行前传递数据, 一般为光照参数, 颜色值等,属于只读的全局变量。
它可以修饰任何基础数据类型
uniform vec4 lightPosition;
-
varying: 在顶点着色器中定义并赋值, 在片段着色器中可读取其值,但不能进行赋值。
它是可变的, 该变量会在每个顶点设置一个值, 然后在一个图元范围内被线性插值, 如果采用单一采样, 其值表示对应片段中心的值。
它的使用一定要确保顶点着色器和片段着色器必须使用相同的类型和名称,否则会导致链接错误。
// 顶点着色器 varying vec4 v_fragmentColor; // 片段着色器 varying vec4 v_fragmentColor;其他
- 支持关键字if-else, for, while, break, continue等, 另外片段着色器中支持discard来丢弃当前片段
- 顶点和片段的着色器都需要有一个main() 表示着色器程序的入口
- 函数允许重载,即函数名相同,但参数个数不同的函数
简单的示例:
attribute vec4 vVertex; attribute vec4 vColor; varying vec4 v_fragmentColor; void main() { gl_Position = vVertex; v_fragmentColor = vColor; } varying vec4 v_fragmentColor; void main() { gl_FragColor = v_fragmentColor; }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)