- 浏览: 1360282 次
-
文章分类
最新评论
-
极限_裁决:
第一题,a 没有定义全局变量不属于 window
第二题,由于 ...
你真懂JavaScript吗? -
netsupper:
1)a=1,答错了."a" in wind ...
你真懂JavaScript吗?
《OpenGLES 2.0 Programming Guide》学习笔记(持续更新)
《OpenGLES 2.0 Programming Guide》 学习笔记
1 介绍OpenGLES
gles由KhronosGroup创立,目前有3个版本1.0,1.1(统称1.x)和2.0。ES1.0,1.1由OpenGL1.3,1.5继承而来,ES2.0由OpenGL2.0继承而来。
OpenGLES 2.0的specifications有两份:theOpenGL ES 2.0 API specification和theOpenGL ES Shading Language Specification(OpenGL ES SL)。
下图是ES2.0的图形流水线,灰色的方框是可编程阶段。
VertexShader
vs实现了一种作用于顶点的通用可编程方法。Vs的输入由以下几种组成:
1)Attributes– 由顶点数组提供的Per-vertexdata。
2)Uniforms– vs使用的常量数据
3)Samplers– 一种特殊的uniform,用于表示vs使用的纹理。Samplers对于vs是可选的。
4)Shaderprogram – vs程序,源代码或者可执行的,描述了对于顶点进行的操作。
Vs的输出叫做varying变量。在primitiverasterization阶段,varying的值对于每个生成的fragment进行计算,并将结果作为输入传递给fragmentshader。从赋予图元每个顶点的varying值为每个fragment生成一个varying值的机制叫做插值(interpolation)。
下图是vs的输入输出图:
Vs可用来进行传统的基于顶点的操作,例如使用矩阵变换位置、进行光照计算产生一个per-vertex的颜色、生成或变换纹理坐标。然而,因为VS是一个程序,VS可以用来进行任意的自定义顶点变换。
一个简单的VS:
uniformmat4 u_mvpMatrix;
attributevec4 a_position;
attributevec4 a_color;
varyingvec4 v_color;
voidmain()
{
v_color= a_color;
gl_Position= u_mvpMatrix*a_position;
}
其中gl_Position是一个内置的varying,不用声明,vs必须向它写入。Main函数是shader唯一的入口点。
PrimitiveAssembly 图元装配阶段
vs之后的流水线阶段就是图元装配,所谓图元是指可以用OpenGLEs绘制命令绘制的基本几何体。图元由顶点组成,顶点有各种属性,如位置和颜色。vs使用这些属性进行计算。在图元集成阶段,经过shade的顶点被集成进一个个独立的几何图元中,例如三角形,线或点精灵。对于每个图元,必须对其进行viewfrustum裁剪。如果图元部分在viewfrustum中,会被clip,如果图元完全在viewfrustum外则被丢弃。clipping之后,顶点的位置被转换到屏幕坐标系。另外,背面剔除也会在这阶段进行。这之后,图元就准备被传送到下一个阶段-光栅化。
Rasterization光栅化阶段
光栅化将图元转化成二维片段(fragments)的集合,这些片段将被fragmentshader处理。Fragment表示了可以被绘制到屏幕上的像素。(注:图元的属性是之前VS输出的varying,在光栅化阶段,基于图元的varying值被插值计算为基于片段的varying值)
FragmentShader
Fs实现了一种作用于片段的通用可编程方法。FS对光栅化阶段产生的每个片段进行操作。
Fs的输入:
1)Varyingvariables :Vs输出的varying经过光栅化插值后对每个片段产生的值。
2)Uniforms:FS使用的常量数据
3)Samplers:一种特殊类型的uniform,表示FS使用的纹理
4)Shaderprogram:FS程序,代码或可执行的,描述了对于片段的操作。
Fs可以丢弃片段或者为片段生成一个颜色,输出保存到gl_FragColor中。
光栅化阶段生成的color,depth,stencil和窗口坐标(Xw,Yw)将会成为流水线per-fragment操作阶段的输入(FS之后的阶段)。
一个简单的FS程序:
precisionmediump float;
varyingvec4 v_color; // input vertex color from vertex shader,VS必须写这个v_color
voidmain(void)
{
gl_FragColor= v_color; //gl_FragColor是唯一的输出
}
Per-FragmentOperations阶段
Fs之后就是逐片段操作阶段。光栅化产生的一个片段,具有窗口坐标(Xw,Yw),只能修改framebuffer中位置在(Xw,Yw)的像素。
下图是Per-FragmentOperations阶段的操作过程:
其中PixelOwnershipTest是用来决定framebuffer中某个位置的像素是否属于OpenGLES的context,比如如果OpenGLES的显示窗口被其他窗口遮住了,则一些像素就通不过这个测试,也就不会被OpenGLES显示。(似乎程序不需要控制这个)
Scissortest:测试(Xw,Yw)的片段是否在scissor矩形内,如果不在,片段被丢弃。
Stenciland depth test:测试incomingfragment的stencil和depth值,决定片段是否被丢弃。
Blending:将新产生的片段的颜色和framebuffer中相应位置像素的颜色进行混合。
Dithering:抖动
在per-fragment阶段之后,(Xw,Yw)处的片段要么被拒绝要么会产生一个fragmentcolor,depth,stencil值写入到framebuffer的(Xw,Yw)位置。Fragmentcolor, depth, stencil值是否真的写入framebuffer还取决于相应的writemasks是否enable。
另外,OpenGLES2.0也提供了从framebuffer回读像素的接口,但只有colorbuffer可以回读,depth和stencil值是读不到的。
alphatest不再在pre-fragmentstage中支持,需要在fragmentshader中实现
logicOp被去掉了,因为很少使用。(alphatest和logicop在OpenGL2.0和OpenGLES1.x中是存在的)
ES2.0和ES1.1的兼容性
ES2.0不向后兼容ES1.1,2.0不支持1.1中的固定功能流水线。2.0用vertexshader代替了1.1中的固定功能顶点处理单元,即:顶点T&L,纹理坐标生成和变换,顶点颜色计算。fragmentshader代替了1.1的固定功能texturecombine单元,即为每个textureunit实现一个texturecombine stage。
(不同于OpenGL2.0,OpenGL2.0是完全向后兼容的,同时支持可编程流水线和固定流水线。)
EGL简介
OpenGLEs命令需要一个renderingcontext和一个drawingsurface。Renderingcontext存储OpenGLEs状态。Drawingsurface是图元绘制上去的surface,drawingsurface指定了渲染所需的buffer的类型,例如colorbuffer, depth buffer和stencilbuffer,以及每种buffer的位数。
OpenGLES API不提供如何创建renderingcontext并且attach到natviewindow system。EGL是一个在OpenGLEs和native windowsystem之间的接口。然而厂商在实现OpenGLEs时并不一定提供EGL,不同平台可能有各自的接口。
2 Shaders and Programs
-----------创建编译shader---------------------------
Gluintshader = glCreateShader(type);
glShaderSource(shader, 1,&shaderSrc, NULL);
glCompileShader(shader);
-----------program------------------------------------
创建:
Gluintprogram = glCreateProgram();
Attach:
glAttachShader(program,shader);
1)一个programobject必须且仅能attach一个vs和一个 fs
-
attach可以在任意时刻进行,哪怕shader没有compile,甚至没有source。
-
可用glDetachShader从program上移除shader。
-
如果一个shader已经被attach到一个programobject上,调用glDeleteShader不会立即删除这个shader,这个shader会被标记为待删除,一旦这个shader不再attach到任何programobject上,这个shader的内存将被释放。
Link:
当两个shader被attach到program上,并且shader已经成功compile,使用glLinkProgram连接program。
1)linker会检查,确保fs使用的所有varyingvariables会被vs写入,并且被声明成同样的类型
2)linker会检查,确保vs和fs中声明的uniforms具有匹配的类型
3)linker会确保最终的program适合实现的限制(即,attribute,uniform, varying的数量,使用的指令)
link阶段会产生最终的硬件指令(link是在GPU上进行的)
有些问题如纹理没有被绑定到samper,在Link时是不能查到的,可使用glValidateProgram(program);验证program是否可以在当前状态下执行。这个操作很慢,一般只在debug版本中使用。
使用:
glUseProgram(program);
-----------uniformsand attributes------------------------------------
uniform: 应用程序通过通过es2.0API传送给shader的只读变量;uniform在programobject中是共享的,即一个programobject只有一组uniforms。如果uniform同时在vs和fs中声明,必须具有相同的类型,并且在这两个shader中该uniform的值是一样的。在link时,linker会为program中的每个activeuniform分配一个uniformlocation。应用程序使用这个uniformlocation作为标识来载入uniform的值。(location需要手动查询得到)
所谓“active”的uniform是值在program中实际使用的uniform,如果仅仅是声明不算。
载入uniform值,首先使用
glGetActiveUniform(program,index, bufSize, &length, &size, &type, uniform_name);
获得uniform的名字,以及数据类型type,数组元素数size(如果不是数组size就是1)
然后使用
location= glGetUniformLocation(program, uniform_name);
获得uniform的location。这样就可以使用一系列的glUniform*函数载入uniform的值。
使用glUniform*的时候,不用programhandle作为参数,因为这是针对当前use的program的。但是一旦为一个program中的uniform设置了值后,这个值将会保存在这个program中。
Gettingand Setting Attributes:
@seeChapter6 “Vertex Attributes, Vertex Arrays and Buffer Objects”
3 OpenGL ES Shading language (GLESSL)
数据类型
float,int, bool
float,vec2, vec3, vec4
int,ivec2, ivec3, ivec4
bool,bvec2, bvec3, bvec4
mat2,mat3, mat4
变量声明
floatspecularAtten;
vec4vPosition;
mat4mViewProjection;
ivec2vOffset;
变量可以在声明时初始化也可以以后初始化。初始化通过使用构造器完成,构造器也被用作类型转换。
变量构造器
GLESSL的类型转换是很严格的,变量只能被赋值给相同类型的变量或者和相同类型的变量一起计算。为了进行类型转换,语言中有很多构造器。
FloatmyFloat = 1.0;
boolmyBool = true;
intmyInt = 0;
myFloat= float(myBool); //convert from bool-> float
myFloat= float(myInt);
myBool= bool(myInt);
向量的构造:
单标量参数-向量所有分量值设置为该标量
多标量或向量参数构造– 向量分量从左到右赋值,参数必须够用
vec4myVec4 = vec4(1.0); // myVec4={1.0,1.0,1.0,1.0}
vec3myVec3 = vec3(1.0, 0.0, 0.5);
vec3temp = vec3(myVec3);
vec2myVec2 = vec2(myVec3); //myVec2 = {myVec3.x, myVec3.y}
myVec4= vec4(myVec2, temp, 0.0); //myVec4={myVec2.x, myVec2.y, temp.x, 0.0}
矩阵的构造:
如果只提供一个标量参数,这个值被设置在矩阵对角线上,例如mat4(1.0)会构造一个4X4单位阵。
矩阵可用多个向量构造;可用多个标量构造;或者向量和标量混搭构造。
访问向量和矩阵的成员
向量可用点访问(”.”) 或数组下标访问。可以用{x,y,z,w},{r,g,b,a},{s,t,r,q}这几种分量名字,但不可混用。
向量可通过点访问重新排序,如:
vec3myVec3 = vec3(0.0, 1.0, 2.0);
vec3temp;
temp= myVec3.xyz; // temp = {0.0, 1.0, 2.0}
temp= myVec3.xxx; // temp = {0.0, 0.0, 0.0}
temp= myVec3.zyx; // temp = {2.0, 1.0, 0.0}
下标访问,从0开始,[0]=x,[1]=y,[2]=z;下标如果不是常量,gles2.0可能不支持。
矩阵被看出是由很多向量组成。例如mat3是由3个vec3组成。矩阵的列用数组下标选择。
然后每个列向量使用向量访问规则。例如:
mat4myMat4 = mat4(1.0); //单位阵
vec4col0 = myMat4[0];
floatm1_1 = myMat4[1][1];
floatm2_2 = myMat4[2].z;
常量
可定任意基本类型的常量。常量变量在shader中值不改变。常量必须在声明时初始化。
const float zero = 0.0;
constfloat pi = 3.14159;
constvec4 red = vec4(1.0, 0.0, 0.0, 1.0);
constmat4 identity = mat4(1.0);
结构体
structfogStruct
{
vec4color;
floatstart;
floatend;
}fogVar;
fogVar= fogStruct(vec4(0.0,1.0,0.0,0.0), 0.5, 2.0);
数组
floatfloatArrary[4];
vec4vecArray[2];
关于数组的重要事项:
1)很多OpenGLEs实现不允许使用无法在编译时确定值的变量去索引数组。
2)不能在创建时初始化数组-没有这样的语法。因此,数组不能是常量。数组元素需要逐个初始化。
操作符
操作必须使用于具有相同基本类型的变量之间
*, / , + , - (基本类型必须是float或者int,乘法可在floats,vectors,matrices之间组合)
++, --
=
+=,-=, *=, /=
==,!=, <, >, <=, >= (只能作用于标量,要比较向量使用内置函数)
&&
^^(逻辑异或)
||
函数
和c类似,最大的区别在于参数的传入方式。OpenGLES提供了特定的修饰符来定义参数是否可以被函数修改:
in (默认,如果不指定)passedby value,不会被函数修改
inout passed by reference, 如果被修改,函数返回后改变值。
out 变量的值不传入函数,函数返回时变量修改。
例子:
vec4myFunc(inout float myFloat, out vec4 myVec4, mat4 myMat4);
例子,计算diffuse光照的函数:
vec4diffuse(vec3 normal, vec3 light, vec4 baseColor)
{
returnbaseColor * dot(normal, light);
}
另外,函数不可以递归,因为一些实现会以inline的方式实现函数调用。
内置函数
使用例子,计算高光:
floatnDotL = dot(normal, light);
floatrDotV = dot(viewDir, (2.0*normal)*nDotL - light);
floatspecular = specularColor * pow(rDotV, specularPower);
控制流
和c类似,但有很多限制。
1)判断表达式必须是bool类型(bool变量或者比较表达式),因为glessl不支持隐式转换。
2)使用循环有各种限制,归结为:OpenGLES必须在编译时知道迭代数。
必须只有一个循环迭代变量,并且只能使用简单的表达式增加或减少(i++,i--,i+=constant,i-=constant);
循环的结束条件判断必须是循环索引和一个常量表达式之间的比较;
不能在循环中改变迭代变量的值;
基本上,gles2不需要实现真正支持loop,它这样限制loop是为了让编译器可以将loop展开。
Uniforms
uniform变量保存应用程序通过OpenGLES2.0API传给shader的只读值。uniform可以保存shader使用的各种数据,如变换矩阵,光的参数或者颜色。基本上,shader需要使用的任意参数如果对于所有的顶点和片段都是常量(但在编译时不知道)应该传入给uniform。
Uniform变量在全局范围内定义:
uniformmat4 viewProjMatrix;
uniformmat4 viewMatrix;
uniformvec3 lightPosition;
uniform存储于硬件上的“constantstore”, 可使用的数量有限制。OpenGLES2.0至少支持128个vertexuniform vectors和16个fragmentuniform vectors。
Attributes
只在vs中使用,用于指定per-vertex的输入。通常保存位置,法线,纹理坐标,颜色等数据。
attributevec4 a_position;
attributevec4 a_texCoord0;
attribute数量的限制:至少是8。
Varyings
vs的输出,fs的输入(在光栅化时进行了图元内线性插值)。在vs,fs中的声明必须一致。
varyingvec2 texCoord;
varyingvec4 color;
varying在硬件上就是interpolator(插值器),数量至少为8.
Preprocessorand Directives 预处理器和指令
宏定义和测试指令:
#define
#undef
#if
#ifdef
#ifndef
#else
#elif
#endif
宏不能用参数定义;#if,#else,#elif可以使用defined测试某个宏是否定义。
预定义的宏:
__LINE__
__FILE__ //ES2.0中总是0
__VERSION__//OpenGL ES Sl的版本(e.g,100)
GL_ES //1
#error指令会在编译shader时引发一个编译错误并将message写入infolog。
#pragma指定用于编译器实现相关的指令。
#version指令用于表示glesslshader语言的版本,必须写在最上面,目前版本是#version 100
#extension用于厂商对语言的扩展。
Uniformand Varying Packing
存储布局为4Xn网格,packing自动进行。
PrecisionQualifiers
用于指定任意基于float或者int类型的变量。
highpvec4 position;
varyinglowp vec4 color;
mediumpfloat specularExp;
如果变量没有指定精度,则使用默认精度。默认精度在shader代码头部指定:
precisionhighp float; //用于所有基于浮点数值的变量
precisionmediump int; //用于所有基于整型值的变量
在vertexshader中,如果没有指定默认精度,则int和float的默认精度都是highp。对于fragmentshader,float类型的默认精度没有默认值,必须显示的声明。并且在fs中,不一定支持highp,可查询得知是否支持(GL_FRAGMENT_PRECISION_HIGH定义,或者查询OES_fragment_precision_high扩展)。
#ifdefGL_FRAGMENT_PRECISION_HIGH
precisionhighp float;
#else
precisionmediump float;
#endif
Invariance
invariant关键字可以作用于vs输出的任意varying变量上。
shader在编译时,编译器可能进行优化,导致指令被重排。这意味着两个shader间相同的计算,不一定产生精确相等的结果。这对于multipass渲染来说是个问题,一个物体被渲染多次,如果计算出来的位置有差别,就会有瑕疵。比如产生z-fighting。
使用invariant可以在写shader时指定如果使用了相同的计算,输出的结果必须精确一致。
invariant关键字可以使用在varying声明上或者已经声明的varying上。
invariantgl_Position; //内置的已经声明的varying,使用invariant
invariantvarying texCoord; //声明时使用invariant
可以使用#pragma指令器然所有的变量invariant:
#pragmaSTDGL invariant(all)
注意,为了实现invariant,编译器限制了优化,所有仅当需要时才使用invariant。
4 Vertex Attributes, Vertex Arrays, VBO
什么是attributes?
如何指定attributes数据和他们支持的数据类型?
如何将attribute的索引和vertexshader中相应的顶点attribute名字绑定?
什么是attributes?
顶点数据或称为顶点属性,是给每个顶点指定的数据,可以每个顶点逐一指定也可所有顶点使用一个常量值。
在opengles 1.1中,顶点属性有预定义的名字,例如position,normal,color,texturecoordinates。因为固定流水线只需要这些顶点属性,所以预定义这些属性是合理的。在可编程流水线中,开发者需要在vertexshader中使用他们自己的顶点属性名字,因此对于gles2.0,用户自定义顶点属性名是必须的,既然如此,预定义名字也就不需要了。
如何指定顶点属性数据?
逐个顶点指定属性数据使用vertexarray;图元的所有顶点使用相同数据则使用常量值。
查询支持的最大顶点属性数,用glGetIntegerv(GL_MAX_VERTEX_ATTRIBS,&maxVertexAttribs);
这个值至少为8。
图元中所有顶点如果使用相同属性值就只用常量顶点属性
常量顶点属性只能使用GLfloat,通过glVertexAttrib1/2/3/4f[v]指定。例如:
void glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z);
这个函数将(x,y,z,1.0)设定到索引为index的顶点属性上。
顶点数组
vertex arrays为每个顶点指定属性数据,他们是存储在应用程序地址空间的buffer(即client space)。
vertex array提供了一种高效而灵活的方式来指定顶点属性数据。要指定vertex array,需要使用
glVertexAttribPointer函数:
void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *ptr);
index: 指定通用顶点属性的索引,取值为0到支持的最大顶点属性数-1
size: 顶点数组中,index所引用的顶点属性的组件数。有效值为1-4
type: 数据格式。有效值为:GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_FLOAT, GL_FIXED, GL_HALF_FLOAT_OES
normalized: 用于指出是否非浮点数据格式在被转换为浮点数时是否需要归一化。
stride: size参数所指定的顶点属性组件们是为逐顶点顺序存储在顶点数组中的。stride指出了顶点i和顶点i+1数据之间的差值。如果stride是0,所有顶点的属性数据是序列存储的。如果stride>0,stride作为一个pitch值来获取下一个顶点的数据。
顶点数组存储方式:
1)array of structures: 所有顶点属性存储在同一个单一的buffer中
2)structure of arrays: 每种顶点属性存储在一个独立的buffer中
在vertex shader中定义attribute:
attribute vec4 a_position;
attribute vec2 a_texcoord;
attribute vec3 a_normal;
attribute修饰符只能出现在vertex shader中,在fragment shader中会导致编译错误;attribute只能是float, vec2, vec3, vec4, mat2, mat3, mat4类型的。attribute变量不能是数组或者结构。
ES2.0实现支持GL_MAX_VERTEX_ATTRIBS个vec4类型的vertex attributes。float, vec2, vec3被计算做一个vec4。mat2,mat3,mat4分别计算为2,3,4个vec4。不像uniform和varying变量可以被自动pack,attribute不会被pack。
attribute变量在shader中是只读的。
在vs中定义的attribute如果没有使用是不会被认为激活的,也不会计算为使用的容量。
如果attribute的总量超过了GL_MAX_VERTEX_ATTRIBS,vertex shader会link失败。
一旦program成功被link,我们可以查出这个program的vs使用的active的vertex attribute数量:
glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &numActiveAttribs);
相关推荐
OpenGL ES 2.0 Programming Guide中文版!
OpenGLES2.0 Programming Guide
源码非常齐全,Android、iOS、BlackBerry、LinuxX11,Windows,WebGL全平台同步代码
OpenGL ES 2.0 Programming Guide(中文版) 高清pdf.上传的压缩包解压即可.
1. AMD的OpenGL ES2.0的模拟器 2. 《OpenGL ES2.0 Programming guide》里的例子代码
opengles 2.0 programming guide source code 带pdf
OpenGL ES 2.0 编程指南 合集,压缩包包含中英文电子版,均为矢量电子版,可复制文字。
详细讲解OpenGL ES 2.0 的使用; 有针对下列平台的配套代码: iOS Android Windows Web
opengl es 2.0 programming guide source code, including android blackberry iphone linux11 webgl windows
《OpenGL ES 2.0 编程指南 中文版》
### OpenGL ES 2.0 Programming Guide #### 一、引言 《OpenGL ES 2.0 Programming Guide》是一本详尽介绍了OpenGL ES 2.0技术的书籍,由Aaftab Munshi、Dan Ginsburg和Dave Shreiner共同编写。本书主要面向希望在...
### OpenGL ES 2.0 编程指南 #### 一、OpenGL ES 概览 OpenGL ES(OpenGL for Embedded Systems)是OpenGL的一个子集,专为移动设备如智能手机和平板电脑等设计的一种图形库标准。它是由Khronos Group创建并维护的...
### OpenGL ES2.0编程指南知识点总结 #### 一、OpenGL ES2.0概述 **OpenGL ES2.0**(OpenGL for Embedded Systems)是Khronos Group为移动设备设计的一套图形库标准,专为手机、平板电脑和嵌入式系统等资源有限的...
Addison Wesley - OpenGL ES 2.0 Programming Guide, 2009.zip
这是一本介绍iphone openGL_ES开发的书,这里配有书籍及源代码。