基础内容学习小结
ES2.0绘图管线示意图:
VertexArray : 绘图场景中所有的物体空间位置由点坐标数组构成。
VertexShader: 对每个点的位置进行变换,计算光照方程式生成每点的颜色,生成或者变换纹理坐标。基本结构示意图:
Attributes ---- 采用点向量数组形式传入的每个点的数据。
Uniforms ---- vertex shader 使用常量数量。
Sampler --- 表示纹理的特殊常量。可选。
Varying Variable -- Vertex Shader的输出变量,作为Fragment Shader的输入。必须与Fragment Shader中的输入Varying一一对应。
gl_Position 是每个点固有的Varying .表示点的空间位置。
Primitive Assembly : 管线中这个流程是对所有的点数据进行点线面等基础图元的组装。这个过程会对所有的图元进行剪切和筛选。对于不在视区空间中的部分进行剪切,对于不可见的面进行筛选。
Rasterization : 光栅化的过程就是对所有的经过Primitive Assembly图元转换成屏幕上可以显示的二维Fragment。
Fragment Shader:通过shader程序对Fragment进行处理。基本结构如下图:
Per-Fragment Operations :每个Fragment的操作。每个Fragment在屏幕上都有一个显示坐标(wx,wy)。基本流程:
这些流程基本是一些在frame buffer 中的2D像素操作。
2.0和1.1 不兼容。
1.1 几乎可看作是OPENGL的子集。采用固定管线编程。
2.0 则全部采用Shader语言来操作。
3 EGL
ES2.0绘图需要一个上下文context 和 绘图surface . Context用来存储ES2.0的管线状态机,surface则表示绘图的缓冲及其属性。EGL是一个介于OPENGL ES 绘图语言和本地视窗系统之间的中间层。因此EGL使得OPENG ES 的平台无关性。
基本流程:
1) Query the displays that are available on the device and initialize them.
2) Create a rendering surface.
3) Create a rendering context. Attach context before start doing graphic .
Eg:
eglDisplay = eglGetDisplay((EGLNativeDisplayType)0); //获取默认显示设备
eglInitialize(eglDisplay, &iMajorVersion, &iMinorVersion); //初始化,返回版本号
eglChooseConfig(eglDisplay, pi32ConfigAttribs, &eglConfig, 1, &iConfigs); //选择一个配置。eglConfig是返回的配置,pi32ConfigAttribs是输入的配置属性,是一个int数组,以key-value的顺序存放属性和值。
eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig, (EGLNativeWindowType) NULL, NULL);//根据egl配置创建显示Surface。
eglContext = eglCreateContext(eglDisplay, eglConfig, NULL, pi32ContextAttribs); //根据egl配置和上下文配置创建上下文。pi32ContextAttribs也是一个int数组,以key-value的顺序存放属性和值。
eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext); //绑定设置当前的上下文和surface.
Ok,下面可以开始使用gl开关的函数绘图了。
编写vertex Shader和fragment shader源码。
创建两个shader 实例:GLuint glCreateShader(GLenum type);
给Shader实例指定源码。 glShaderSource
在线编译shaer源码 void glCompileShader(GLuint shader)
创建program GLuint glCreateProgram(void)
绑定shader到program 。 void glAttachShader(GLuint program, GLuint shader)。每个program必须绑定一个vertex shader 和一个fragment shader。
链接program 。 void glLinkProgram(GLuint program)
使用porgram 。 void glUseProgram(GLuint program)
对于使用独立shader编译器编译的二进制shader代码,可使用glShaderBinary来加载到一个shader实例中。
1) Uniforms and Attributes
Uniforms 是一个program 中统一分配的,vertext 和fragment中同名的Uniform必须同类型。对应于不经常变化的变量。
Attributes 变化率高的变量。主要用来定义输入的每次点属性。
Uniforms and Attributes 在shader中通过location 和 name 来对应的。
通过GLint glGetUniformLocation(GLuint program,const char* name).根据一个Uniform的名称获取其location.
通过 glUniform***系列函数可以给一个location 设置一个Uniform的值。
2) 数据类型
三类基本类型:float , int , boolean
复合类型:
浮点、整型、布尔向量 vec2 , vec3,vec4
矩阵 mat2, mat3,mat4
结构体 用基本类型和复合类型构建结构体。
变量初始化。可以由简单类型初始化复杂类型。
可以通过常量下标访问矩阵,变量数组,向量中的分量。
操作与C语言类似。
函数。传参指定in out 或者inout。
If else 流控制。
For循环。只支持常数循环次数。
无论下标,还是循环变量,都只能使用编译时可确定的常数。
Uniform 前辍修饰的变量初始值由外部程序赋值。在program中具有统一访问空间。存储空间有限
Attribute 前辍修饰的变量定义的是每个vertex的属性变量,包括位置,颜色,法线和纹理坐标
Uniform 和 Attribute 类型的变量在shader中是只读的,只能由外部主机程序传入值。
1)Vertex Attributes 是每点的属性数据。与一个index序号绑定。
外部程序可通过 glBindAttribLocation将一个attribute 名与一个index绑定起来。
当然,OPENGL ES 内部会自动绑定所有attributes.外部程序只需要通过 glGetAttribLocation获取指定attribute名的index.
2)给Attribute传值有两种方式:
可以通过 glVertexAttribPointer会话vertex Array数组。
可以通过 glVertexAttrib** 给指定location(index)的attribute赋值。
1)Primitive : 三角形 ,线 , 点
三角形绘制时可使用:GL_TRIANGLES ,GL_TRIANGLE_STRIP ,GL_TRIANGLE_FAN三种模式。
绘线可用:GL_LINES GL_LINE_STRIP GL_LINE_LOOP三种模式
线宽可用:void glLineWidth(GLfloat width)进行设置。
绘点可用: GL_POINTS. 绘点vertex Shader中内置gl_PointSize输出变量。定义点的半径
2)Drawing Primitives
绘制primitves时可用的两个函数:
void glDrawArrays(GLenum mode, GLint first, GLsizei count)
void glDrawElements(GLenum mode, GLsizei count,GLenum type, const GLvoid *indices)
这两个函数调用前都需要绑定点属性数组,主要是坐标数组。后都给定下标数组来绘制primitive,绘制大量的mesh时,有利于提高性能。
3) Primitive Assembly
坐标体系:
Primitive Assembly基本流程:
Clipping :
视区空间,六个面组成。对于每个primitive,凡在空间外的都clip掉。
Perspective Division
标准化坐标,即齐次坐标(x,y,z,w)转化为(x/w,y/w,z/w,1) 其中x,y,z绝对值均小于w
Viewport Transformation
将标准化后的空间坐标转换到平面可视窗口范围内的坐标上。窗口范围定义void glViewport(GLint x, GLint y, GLsizei w, GLsizei h) 。
其中Xw,Yw,Zw是窗口坐标,Z是深度坐标。
Rasterization :为每个primitive生成一个fragment。一个fragment由屏幕像素坐标(Xw,Yw)和其他的fragment数据组成,这些数据将在fragment shader中被使用。
Culling : 对triangle进行Rasterization之前必须确定它是正面还是反面朝向观察者,Culling操作将会忽略背向观察者的面。首要的问题是如果区分三角形的正面和反面,这跟绘制三角形时三个点的顺序有关。如下图:
通过 void glFrontFace(GLenum dir) 来设定三角形的正面。Dir可为GL_CW or GL_CCW(默认). 意思就是如果三角形三个点的绘制顺序为v0,v1,v2,站在观察者的位置,如果v0,v1,v2路径与 glFrontFace设定的时针方向相同,那么面向观察者的这一面就是正面,否则就是反面。
Culling其他相关接口:
void glCullFace(GLenum mode) 选择要Cull的面,参数可为 GL_FRONT, GL_BACK, and GL_FRONT_AND_BACK。默认是GL_BACK。
void glEnable(GLenum cap)
void glDisable(GLenum cap)
其中 cap参数为 GL_CULL_FACE 。 使能、禁止GL_CULL_FACE功能。
点Shader能做的事:
基于点操作的矩阵乘法位置变换.
根据光照公式计算每点的color值。
生成或者转换纹理坐标。
Vertex Shader OVERVIEW:
1)Built-In Special Variables 输出给管线的后端。
gl_Position : 点坐标。
gl_PointSize : point sprite的半径大小。绘制单点时用。
gl_FrontFacing: bool值。自动生成。
2)Built-In Uniform State
uniform gl_DepthRangeParameters gl_DepthRange; 窗口坐标深度远近值。
用gl_DepthRange可设置
3)Precision Qualifiers 精度限定
对于基于int float的类型变量可以在定义是指定精度,三种:highp,mediump lowp 。 如 highp vec4 position;
默认精度设定,如precision highp float; 对所有未加精度限定的float,使用默认设定highp。
4)ES 2.0 Vertex Shader Limitations
Length of Vertex Shader
Temporary Variables
Flow Control :
For循环。
Conditional Statements
If(bool){} 或者if(bool) {}else{}
Array Indexing:
只能使用常量。
Counting Number of Uniforms Used in a Vertex Shader:
OpenGL ES 2.0 实现标准是 128 vec4 entries的uniform常量,被用来存储这几种类型的数值:
Variables declared with the uniform qualifier。如uniform vec4 v;
Const variables. 如: const int i=1;
Literal values。 如 vec(0.0,0.0,0.0,0.0),对于这种情况,应该尽量使用const变量来定义重复的文字常量。如const float z=0.0; 然后使用vec(z,z,z,z)来表示这个0向量。Uniform 存储空间占用会由4个0.0缩小到一个z.
Implementation-specific constants.
1) 纹理坐标
2) Texture Objects and Loading Textures
Texture Object采用int句柄来指向。
void glGenTextures(GLsizei n, GLuint *textures) 创建指定数目的Texture对象。返回句柄到textures
void glDeleteTextures(GLsizei n, GLuint *textures) 删除对象
绑定纹理void glBindTexture(GLenum target, GLuint texture),对于2D纹理target使用GL_TEXTURE_2D
加载纹理: void glTexImage2D(....)
3) Texture Coordinate Wrapping
纹理坐标超出[0,1]范围时映射纹理使用的回绕方式:
Texture Wrap Modes : GL_REPEAT,GL_CLAMP_TO_EDGE, GL_MIRRORED_REPEAT
4) Using Textures in the Fragment Shader
在fragment shader 中定义uniform sampler2D s_texture;常量。
获取s_texture的location。 samplerLoc = glGetUniformLocation(
userData->programObject,
"s_texture");
使用void glActiveTexture(GLenum texture) 将GL_TEXTURE0 ..GL_TEXTURE31指定为当前active texture。
使用glBindTexture 绑定一个texture句柄到GL_TEXTURE*
glUniform1i(userData->samplerLoc, GL_TEXTURE* ); 当前激活的GL_TEXTURE*传给s_texture
在shader中使用 texture2D内建函数取纹理坐标对应的color值。如:gl_FragColor = texture2D(s_texture, v_texCoord);
5) Texture Subimage Specification
对纹理的子块进行更新。
void glTexSubImage2D(GLenum target, GLint level,
GLint xoffset, GLint yoffset,
GLsizei width, GLsizei height,
GLenum format, GLenum type,
const void* pixels)
6) Blending
生成的fragment是具有(x,y,z)坐标的,其中x,y是在窗口中显示的位置。Z是深度坐标。Blending是指当Fragment要显示在窗口中时,如果使能了blend,那么当前fragment的颜色要经过指定的blend方法去与屏幕中已经存在于(x,y)坐标上的颜色进行混合。
基本的混合模式是Cfinal = (fsource *Csource )op (fdestingation*Cdestination)
Csource 和Cdestination是源和目的颜色,fsource和fdestination是源和目的的系数。也就是最终的颜色将是源和目的的颜色乘以各自的系数然后OP操作进行混合。
void glBlendFunc(GLenum sfactor, GLenum dfactor);指定对于源和目的都采用什么系数模式。
void glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB,
GLenum srcAlpha, GLenum dstAlpha);
对于源和目的采用分开的系数模式。即alpha部分与RGB部分独立指定。
void glBlendEquation(GLenum mode); 指定OP操作。
void glBlendEquationSeparate(GLenum modeRGB,
GLenum modeAlpha);对于RGB部分和Alpha部分分开指定OP操作。
7) Reading and Writing Pixels to the Framebuffer
从color buffer中读取图像像素
void glReadPixels(GLint x, GLint y, GLsizei width,
GLsizei height, GLenum format,
GLenum type, void *pixels);
其余内容如光照,fog,mipmap,framebuffer object 等内容由于与目前项目无关,无暇顾及。
2010-7-29