使用OpenGL创造的物体,在最终被绘制出来之前,有一个流水线处理过程,该过程被称为graphics pipeline,或者rendering pipeline,期间大部分工作由GPU执行,跟GPU紧密相关。
随着GPU的发展,现在的GPU加入了可编程处理器,开发人员可直接控制GPU的行为。所谓Shader,就是控制GPU的一堆指令集,程序员写出shader,输入到GPU中,GPU执行。
早期的Shader是直接使用汇编。后来OpenGL ARB组织开发了一种新的编程语言,叫做GLslang或者GLSL, OpenGL shading language.该语言类似于C风格,在官方网站上有详细的语法解释,这样,程序员们就可以很方便的写出可直接控制GPU的代码了。
所谓控制GPU,就是控制GPU的处理器,现阶段,GPU有以下几个处理器:
1. Vertext processor
2. Tessellation Control processor
3. Tessellation Evaluation processor
4. Geometryprocessor
5. Fragmentprocessor
于是,shader就分为:
1. Vertext shader
2. Tessellation Controlshader
3. Tessellation Evaluationshader
4. Geometryshader
5. Fragmentshader
Shader可以说是现代OpenGL的灵魂。
这牵涉到一个历史遗留问题:GL 1.x中只有固定管线,渲染效果是固定的,而在GL 2.0中增加了可编程管线,想要什么渲染效果都可以自己往加。GL 3.0+就废弃了固定管线,也就是说不写Shader是不推荐的。不写Shader的固定管线时代早就在十多年前过去了。
渲染管线
--------------
什么是管线?什么又是固定管线和可编程管线?管线(pipeline)也称渲染管线,因为 OpenGL ES在渲染处理过程中会顺序执行一系列操作,这一系列相关的处理阶段就被称为OpenGL ES 渲染管线。pipeline 来源于福特汽车生产车间的流水线作业,在OpenGL ES 渲染过程中也是一样,一个操作接着一个操作进行,就如流水线作业一样,这样的实现极大地提供了渲染的效率。整个渲染管线如下图所示:
这张图就是 OpenGL ES 的“架构图”, 图中阴影部分的 Vertex Shader 和 Fragment Shader 是可编程管线。
Vertex Array/Buffer objects:
顶点数据来源,这时渲染管线的顶点输入,通常使用 Buffer objects效率更好。
Vertex Shader:
顶点着色器通过可编程的方式实现对顶点的操作,如进行坐标空间转换,
计算 per-vertex color以及纹理坐标;
Primitive Assembly:
图元装配,经过着色器处理之后的顶点在图片装配阶段被装配为基本图元。
OpenGL ES 支持三种基本图元:点,线和三角形,它们是可被 OpenGL ES 渲染的。
接着对装配好的图元进行裁剪(clip):保留完全在视锥体中的图元,
丢弃完全不在视锥体中的图元,对一半在一半不在的图元进行裁剪;
接着再对在视锥体中的图元进行剔除处理(cull):
这个过程可编码来决定是剔除正面,背面还是全部剔除。
Rasterization:
光栅化。在光栅化阶段,基本图元被转换为二维的片元(fragment),
fragment 表示可以被渲染到屏幕上的像素,它包含位置,颜色,纹理坐标等信息,
这些值是由图元的顶点信息进行插值计算得到的。
这些片元接着被送到片元着色器中处理。
这是从顶点数据到可渲染在显示设备上的像素的质变过程。
Fragment Shader:
片元着色器通过可编程的方式实现对片元的操作。在这一阶段它接受光栅化处理之后的
fragment,color,深度值,模版值作为输入。
Per-Fragment Operation:
对片元着色器输出的每一个片元进行一系列测试与处理,从而决定最终用于渲染的像素。
顶点着色器
-----------------
Attributes:由 vertext array 提供的顶点数据,如空间位置,法向量,纹理坐标以及顶点颜色,它是针对每一个顶点的数据。属性只在顶点着色器中才有,片元着色器中没有属性。属性可以理解为针对每一个顶点的输入数据。
Uniforms:uniforms保存由应用程序传递给着色器的只读常量数据。在顶点着色器中,这些数据通常是变换矩阵,光照参数,颜色等。由 uniform 修饰符修饰的变量属于全局变量,该全局性对顶点着色器与片元着色器均可见,也就是说,这两个着色器如果被连接到同一个应用程序中,它们共享同一份 uniform 全局变量集。因此如果在这两个着色器中都声明了同名的 uniform 变量,要保证这对同名变量完全相同:同名+同类型,因为它们实际是同一个变量。此外,uniform 变量存储在常量存储区。
Shader program:由 main 申明的一段程序源码,描述在顶点上执行的操作:如坐标变换,计算光照公式来产生 per-vertex 颜色或计算纹理坐标。
Varying:varying 变量用于存储顶点着色器的输出数据,当然也存储片元着色器的输入数据,varying 变量最终会在光栅化处理阶段被线性插值。顶点着色器如果声明了 varying 变量,它必须被传递到片元着色器中才能进一步传递到下一阶段,因此顶点着色器中声明的 varying 变量都应在片元着色器中重新声明同名同类型的 varying 变量。
在顶点着色器阶段至少应输出位置信息-即内建变量:gl_Position,其它两个可选的变量为:gl_FrontFacing 和 gl_PointSize。
三,片元着色器
----------------------
顶点着色器阶段输出的 varying 变量在光栅化阶段被线性插值计算之后输出到片元着色器中作为它的输入,即上图中的 gl_FragCoord,gl_FrontFacing 和 gl_PointCoord。
Uniforms:前面也已经讲过,这里是用于片元着色器的常量,如雾化参数,纹理参数等;
Samples:一种特殊的 uniform,用于呈现纹理。
Shader program:由 main 申明的一段程序源码,描述在片元上执行的操作。
在顶点着色器阶段只有唯一的 varying 输出变量-即内建变量:gl_FragColor。
shader数据类型
----------------------
在GL3.x中,废弃了attribute关键字以及varying关键字,属性变量统一用in/out作为前置关键字。
对每一个Shader stage来说,in表示该属性是作为输入的属性,out表示该属性是用于输出的属性。
uniform
随不同图元变化的全局变量,也即不能对每个顶点设置该变量。
注:其值不能在glBegin/glEnd中设置。一致变量适合描述在一个图元中、一帧中甚至一个场景中都不变的值。一致变量在顶点shader和片断shader中都是只读的。
------------------------------- opengl的一些函数 -------------------------------
void glGenBuffers(GLsizei n, GLuint * buffers);
n : Specifies the number of buffer object names to be generated.
buffers: Specifies an array in which the generated buffer object names are stored.
glGenBuffers returns n buffer object names in buffers.
There is no guarantee that the names form a contiguous set of integers;
however, it is guaranteed that none of the returned names was in use
immediately before the call to glGenBuffers.
Buffer object names returned by a call to glGenBuffers are not returned by
subsequent calls, unless they are first deleted with glDeleteBuffers.
No buffer objects are associated with the returned buffer object names
until they are first bound by calling glBindBuffer.
-------------------------------------------------------------------------------------
glShaderSource — Replaces the source code in a shader object
void glShaderSource( GLuint shader, GLsizei count, const GLchar **string, const GLint *length);
shader: Specifies the handle of the shader object whose source code is to be replaced.
count : Specifies the number of elements in the string and length arrays.
string : Specifies an array of pointers to strings containing the source code to be loaded into the
shader.
length : Specifies an array of string lengths.
glShaderSource sets the source code in shader to the source code in the array of strings specified by string. Any source code previously stored in the shader object is completely replaced. The number of strings in the array is specified by count. If length is NULL, each string is assumed to be null terminated. If length is a value other than NULL, it points to an array containing a string length for each of the corresponding elements of string. Each element in the length array may contain the length of the corresponding string (the null character is not counted as part of the string length) or a value less than 0 to indicate that the string is null terminated. The source code strings are not scanned or parsed at this time; they are simply copied into the specified shader object.
OpenGL copies the shader source code strings when glShaderSource is called, so an application may free its copy of the source code strings immediately after the function returns.
Errors
GL_INVALID_VALUE is generated if shader is not a value generated by OpenGL.
GL_INVALID_OPERATION is generated if shader is not a shader object.
GL_INVALID_VALUE is generated if count is less than 0.
---------------------------------------------------------------------------------------------------------------
glBindAttribLocation — Associates a generic vertex attribute index with a named attribute variable
void glBindAttribLocation( GLuint program,
GLuint index,
const GLchar *name );
program Specifies the handle of the program object in which the association is to be made.
index Specifies the index of the generic vertex attribute to be bound.
name Specifies a null terminated string containing the name of the vertex shader attribute
variable to which index is to be bound.
Description
glBindAttribLocation is used to associate a user-defined attribute variable in the program object specified by program with a generic vertex attribute index. The name of the user-defined attribute variable is passed as a null terminated string in name. The generic vertex attribute index to be bound to this variable is specified by index. When program is made part of current state, values provided via the generic vertex attribute index will modify the value of the user-defined attribute variable specified by name.
If name refers to a matrix attribute variable, index refers to the first column of the matrix.
Other matrix columns are then automatically bound to locations index+1 for a matrix of type mat2; index+1 and index+2 for a matrix of type mat3; and index+1, index+2, and index+3 for a matrix of type mat4.
This command makes it possible for vertex shaders to use descriptive names for attribute variables rather than generic variables that are numbered from zero to the value of GL_MAX_VERTEX_ATTRIBS minus one. The values sent to each generic attribute index are part of current state. If a different program object is made current by calling glUseProgram, the generic vertex attributes are tracked in such a way that the same values will be observed by attributes in the new program object that are also bound to index.
Attribute variable name-to-generic attribute index bindings for a program object can be explicitly assigned at any time by calling glBindAttribLocation. Attribute bindings do not go into effect until glLinkProgram is called. After a program object has been linked successfully, the index values for generic attributes remain fixed (and their values can be queried) until the next link command occurs.
Any attribute binding that occurs after the program object has been linked will not take effect until the next time the program object is linked.
首先检查属性变量是否被通过glBindAttribLocation绑定了属性索引,如果是,则使用此绑定的属性索引;否则,为之分配一个属性索引。
在应用程序中,一般使用函数glBindAttribLocation来绑定每个attribute变量的位置,然后用函数glVertexAttribPointer为每个attribute变量赋值。
-------------------------------------------------------------