大佬教程收集整理的这篇文章主要介绍了Cocos2D-X shader(三) Shader and Program编程基本概念,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
一、本文关注的问题:
• Shader and program 对象介绍
•创建并编译一个Shader对象
• 创建并链接一个Program对象
• 获取并设置uniforms
• 获取并设置attributes
在OpenGL ES中,每个program对象有且仅有一个Vertex Shader对象和一个Fragment Shader对象连接到它。
Shader:类似于C编译器
Program:类似于C链接器
glLinkProgram操作产生最后的可执行程序,它包含最后可以在硬件上执行的硬件指令。
二、Shader和Program编程概述
1. 创建Shader
1)编写Vertex Shader和Fragment Shader源码。
2)创建两个shader 实例:GLuint glCreateShader(GLenum typE);
3)给Shader实例指定源码。 glShadersource
4)在线编译shaer源码 void glCompileShader(GLuint shader)
2. 创建Program
1)创建program GLuint glCreateProgram(void)
2)绑定shader到program 。 void glAttachShader(GLuint program,GLuint shader)。每个program必须绑定一个Vertex Shader 和一个Fragment Shader。
3)链接program 。 void glLinkProgram(GLuint program)
4)使用porgram 。 void glUseProgram(GLuint program)
对于使用独立shader编译器编译的二进制shader代码,可使用glShaderBinary来加载到一个shader实例中。
三、Shading Language中的数据类型与变量
1. Uniforms and Attributes
Uniforms 是一个program 中统一分配的,vertext 和fragment中同名的Uniform必须同类型。对应于不经常变化的变量(用于存储只读常量值的变量)。
Attributes 变化率高的变量。主要用来定义输入的每个点属性。
Uniforms and Attributes 在shader中通过LOCATIOn 和 name 来对应的。
2. 数据类型
1)三类基本数据类型:float,int,Boolean
2)复合类型:浮点、整型、布尔向量 vec2,vec3,vec4。vector访问方式有以下两种:
(1).操作:数学{x,y,z,w},颜色{r,g,b,a}或 纹理坐标{s,t,r,q},但不能混用,举例如下:
vec3 myVec3 = vec3(0.0,1.0,2.0); // myVec3 = {0.0,2.0}
vec3 temp;
temp = myVec3.xyz; // temp = {0.0,2.0}
temp = myVec3.xxx; // temp = {0.0,0.0,0.0}
temp = myVec3.zyx; // temp = {2.0,0.0}
(2)[ ]操作:[0]对应x,[1]对应y,[2]对应z,[3]对应w。[ ]中只能为常量或uniform变量,不能为整数量变量(如:i,j,k)。
3)矩阵:mat2,mat3,mat4 (按列顺序存储)
mat3 mymat3 = mat3(1.0,// 第一列
0.0,// 第二列
0.5,1.0); // 第三列
可用[ ]或.操作符来访问:
mat4 mymat4 = mat4(1.0);// Initialize diagonal to 1.0 (identity)
vec4 col0 = mymat4[0];// Get col0 vector out of the matrix
float m1_1 = mymat4[1][1];// Get element at [1][1] in matrix
float m2_2 = mymat4[2].z; // Get element at [2][2] in matrix
4)常量
const float zero = 0.0;
const float pi = 3.14159;
const vec4 red = vec4(1.0,1.0);
const mat4 identity = mat4(1.0);
5)结构体: 用基本类型和复合类型构建结构体。
struct fogStruct
{
vec4 color;
float start;
float end;
} fogVar;
fogVar = fogStruct(vec4(0.0,0.0),// color
0.5,// start
2.0); // end
vec4 color = fogVar.color;
float start = fogVar.start;
float end = fogVar.end;
6)数组:类似于C语言,索引从0开始。在创建时不能被初始化,索引只能为常量或uniform变量。
float floatArraY[4];
vec4 vecarray[2];
7)操作
支持的操作有:*,/,+,-,++,--,=,+=,-=,*=,/=,==,!=,<,>,<=,>=,&&,^^,||
前面矩阵的行数就是结果矩阵的行数,后面矩阵的列数就是结果矩阵的列数。
8)自定义函数:
函数不能递归调用,因为GPU不一定有Stack和流控。
9)Shading Language内嵌函数
主要有以下几类函数:
(1)角度和三角函数
(2)指数函数
(3)通用函数(绝对值、取整、取余、取小数部分等)
(4)几何函数
(5)矩阵函数
(6)向量比较函数
(7)纹理查找函数
(8)Derivative函数
10)控制流
以下不允许(因为下标为变量或loop次数为变量):
它用于存储shader需要的各种数据,如:变换矩阵、光照参数和颜色。基本上,对于Shader是一个常量,但在编译时其值未知,则应当作为一个uniform变量。
Uniform变量在Vertex Shader和Fragment Shader之间共享。当使用glUniform***设置了一个uniform变量的值之后,Vertex Shader和Fragment Shader中具有相同的值。
Uniform变量被存储在GPU中的“常量存储区”,其空间大小是固定的,可通过API<glGetIntegerv>查询(GL_MAX_VERTEX_UNIFORM_VECTORS或 GL_MAX_FRAGMENT_UNIFORM_VECTORS)。
12)Attributes(前辍修改)
Attribute类型的变量只有Vertex Shader才有。Attribute前辍修饰的变量定义的是每个Vertex的属性变量,包括位置,颜色,法线和纹理坐标
Attribute类型的变量在Vertex Shader中是只读的,只能由外部主机程序传入值。
Attribute类型的变量:是为每个被正在画的顶点所指定的数据。在画图前,每个顶点的属性由应用程序输入。
与Uniform变量一样,其存储数量也是有限制的。可用glGetIntegerv(GL_MAX_VERTEX_ATTRIBS)进行查询。GPU至少支持8个属性,所以Vertex Shader源码中不要超过8个attributes。
13)Varyings
Varying变量用于存储Vertex Shader的输出和Fragment Shader的输入。在Vertex Shader和Fragment Shader中必须申明同一个Varying变量。
与Uniform和Attribute一样,其存储数量也是有限制的,可用glGetIntegerv(GL_MAX_VARYING_VECTORS)进行查询。GPU至少支持8个Varying vector,所以Vertex Shader源码中不要超过8个Varying vector。
GLint maxVertexAttribs; // n will be >= 8
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS,&maxVertexAttribs);
14)预处理
15) Uniform Attribute Varying存储空间最小值
变量类型 @H_262_772@ | GPU必须支持的最小个数 @H_262_772@ |
Vertex Uniform Vectors @H_262_772@ | 128 @H_262_772@ |
Fragment Uniform Vectors @H_262_772@ | 16 @H_262_772@ |
Vertex Attributes @H_262_772@ | 8 @H_262_772@ |
Varying Vectors @H_262_772@ | 8 @H_262_772@ |
关键词:lowp highp mediump
(1)指定变量精度(放在数据类型之前):
(2)指定默认精度(放在Vertex和Fragment shader源码的开始处):
在Vertex Shader中,如果没有默认的精度,则float和int精度都为highp;在Fragment Shader中,float没有默认的精度,所以必须在Fragment Shader中为float指定一个默认精度或为每个float变量指定精度。
17)结果一致性
invariant可被应用于任何Vertex ShaderVarying输出变量,其目前是保证相同的操作和相同的输入,其结果一样。因为由于Shader精度不一样,其结果有可能不一样。
也可指定所有的输出变量都为:invariant
四、获取和设置Uniforms
通过GLint glGetUniformLOCATIOn(GLuint program,const char* Name).根据一个Uniform的名称获取其LOCATIOn.
通过 glUniform***系列函数可以给一个LOCATIOn 设置一个Uniform的值。
为矩阵uniform变量设置值的函数中的transpose必须为GL_falSE,它目的为兼容性,但在 OpenGL ES 2.0中并没有工作。
一旦你设置了一个Program中unifrom变量的值之后,即使你激活了另外一个Program,此uniform的值不变。即uniform变量是Program的局部变量。
五、VertexAttributes
Vertex属性即顶点数据,它指定了每个顶点的数据。在OpenGL ES1.1中,顶点属性有四个预定义的名字:position(位置),normal(法线),color(颜色),和 texture coordinates(纹理坐标)。在OpenGL ES2.0中,用户必须定义“顶点属性的名字”。
1. 常量顶点属性(Constant Vertex Attribute)
常量顶点属性对所有顶点都是一样的。因此只需要指定一个值就可以应用于所有顶点。一般很少使用。其设置函数有:
2.如何装载顶点数据?(Vertex Arrays)
Vertex Array(顶点数组):是一个存储在应用程序空间(Client)中的内存buffer,它存储了每个顶点的属性数据。
如何把顶点数据组的数据传递给GPU呢?
void glVertexAttribPointer(GLuint index,
GLint size,//每个属性元素个数有效值1-4(x,w)
GLenum type,//数组中每个元素的数据类型
GLBoolean normalized,
GLsizei @R_618_10495@de,//如果数据连续存放,则为0或
//size*sizeof(typE)
const void *ptr) //顶点数组指针
举例如下:
copy
2.1一个顶点的所有属性存储在一起(Array of Structures)
如下图所示,顶点的位置(x,z)、法线(x,z)和两个纹理坐标(s,t)存储在一起,如下图所示:
例子代码如下(当然,此代码在CPU上运动):
2.2 顶点的每个属性单独存储(Structure of Arrays)
例子代码如下(当然,此代码在CPU上运动):
#define VERTEX_POS_SIZE 3 // x,y and z #define VERTEX_NORMAL_SIZE 3 // x,y and z #define VERTEX_TEXCOORD0_SIZE 2 // s and t #define VERTEX_TEXCOORD1_SIZE 2 // s and t #define VERTEX_POS_INDX 0 #define VERTEX_NORMAL_INDX 1 #define VERTEX_TEXCOORD0_INDX 2 #define VERTEX_TEXCOORD1_INDX 3 #define VERTEX_ATTRIB_SIZE VERTEX_POS_SIZE + \ VERTEX_NORMAL_SIZE + \ VERTEX_TEXCOORD0_SIZE + \ VERTEX_TEXCOORD1_SIZE float *position = malloc(numVertices * VERTEX_POS_SIZE * sizeof(float)); float *normal = malloc(numVertices * VERTEX_NORMAL_SIZE * sizeof(float)); float *texcoord0 = malloc(numVertices * VERTEX_TEXCOORD0_SIZE * sizeof(float)); float *texcoord1 = malloc(numVertices * VERTEX_TEXCOORD1_SIZE * sizeof(float)); // position is vertex attribute 0 glVertexAttribPointer(VERTEX_POS_INDX,VERTEX_POS_SIZE * sizeof(float),position); // normal is vertex attribute 1 glVertexAttribPointer(VERTEX_NORMAL_INDX,VERTEX_NORMAL_SIZE * sizeof(float),normal); // texture coordinate 0 is vertex attribute 2 glVertexAttribPointer(VERTEX_TEXCOORD0_INDX,VERTEX_TEXCOORD0_SIZE * sizeof(float),texcoord0); // texture coordinate 1 is vertex attribute 3 glVertexAttribPointer(VERTEX_TEXCOORD1_INDX,VERTEX_TEXCOORD1_SIZE * sizeof(float),//也可为0,因为数据是紧接着存放的 texcoord1);
2.3. 哪种顶点属性数据存储方式在GPU上性能更好?
答案是:把一个顶点的所有属性放在一起(array of structures)。其原因是每个顶点的属性数据以连续的方式读取,使内存访问效率更高。其缺点是,如果要修改其中部分属性数据,将导致整个属性buffer全部重新装载,解决此问题的方法是把这些需要动态修改的属性数据放在单独的buffer中。
顶点属性数据类型不会影响在GPU上每个顶点占用的内存,但在Render a Frame时,它影响CPU与GPU之间的内存带宽。推荐尽量使用GL_HALF_FLOAT_OES。
如果normalized为GL_falSE:则直接把数据转换为GLfloat,因为Vertex Shader内部把顶点属性当作GLfloat(32位)来进行存储。
GL_BYTE,GL_SHORT or GL_FIXED被归一化为[-1,1];GL_UNSIGNED_BYTE or GL_UNSIGNED_SHORT被归一化为[0.0,1.0]。具体转换公式为:
@H_74_1616@@H_851_1618@3、选择常量或顶点数组Vertex Attribute
可通过以下函数来Enable或Disable顶点数组(Vertex Array)。
void glEnableVertexAttribArray(GLuint indeX);
void glDisableVertexAttribArray(GLuint indeX);
其关系如下图所示:
Attribute变量的数据类型只能为:float,vec2,vec4,mat2,and mat4;Attribute变量不能为数组或结构。如下面的申明是错误的:
每个GPU支持GL_MAX_VERTEX_ATTRIBS vec4。float、vec2和vec3也被当作一个vec4来进行存储;mat2、mat3、mat4被分别当作2、3、和4个vec4来进行存储。
把“顶点属性索引”绑定到“顶点属性名”有以下两个方法:
1)OpenGL ES 2.0把“顶点属性索引”绑定到“顶点属性名”,当link program时,OpengGL ES 2.0执行此绑定。然后应用程序通过glGetAttribLOCATIOn(失败时返回-1)获取“顶点属性索引”。
2)应用程序通过glBindAttribLOCATIOn把“顶点属性索引”绑定到“顶点属性名”,glBindAttribLOCATIOn在program被link之前执行。
在link program时,OpenGL ES 2.0对每个顶点属性执行如下操作:
(1)首先检查属性变量是否被通过glBindAttribLOCATIOn绑定了属性索引,如果是,则使用此绑定的属性索引;否则,为之分配一个属性索引。
在应用程序中,一般使用函数glBindAttribLOCATIOn来绑定每个attribute变量的位置,然后用函数glVertexAttribPointer为每个attribute变量赋值。
顶点数组(Vertex Array)被保存在客户端内存,当执行glDrawArrays或 glDrawElements时,才把它们从客户端内存copy到图形内存。这样占用了大量的内存带宽,Vertex Buffer Objects允许OpengGL ES2.0应用在高性能的图形内存中分配并cache顶点数据,然后从此图形内存中执行render,这样避免了每次画一个原语都要重发送数据。
Vertex Buffer Objects有以下两种类型:
(1)array buffer objects:通过GL_ARRAY_BUFFER标记创建,并存储vertex data。
(2)element array buffer objects:通过GL_ELEMENT_ARRAY_BUFFER标记创建,并存储inDices of a primitive。
创建和绑定Vertex Buffer Objects例子代码如下:
@H_195_1772@@H_195_1772@
以上是大佬教程为你收集整理的Cocos2D-X shader(三) Shader and Program编程基本概念全部内容,希望文章能够帮你解决Cocos2D-X shader(三) Shader and Program编程基本概念所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。