原地址:http://blog.csdn.net/myarrow/article/details/7737313

一、本文关注的问题:

• 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, 1.0, 2.0}
        vec3 temp;
        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}

(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.0,  // 第一列
                                  0.0, 1.0, 0.0,  // 第二列
                                  0.5, 1.0, 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, 0.0, 0.0, 1.0);
     const mat4 identity = mat4(1.0);

5)结构体: 用基本类型和复合类型构建结构体。

struct fogStruct
     {
         vec4 color;
         float start;
         float end;
     } fogVar;
     fogVar = fogStruct(vec4(0.0, 1.0, 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)操作

支持的操作有:*,/,+,-,++,--,=,+=, -=, *=, /=,==, !=, <, >, <=, >=,&&,^^,||

  1. float myFloat;
  2. vec4 myVec4;
  3. mat4 myMat4;
  4. myVec4 = myVec4 * myFloat; // Multiplies each component of myVec4
  5. // by a scalar myFloat
  6. myVec4 = myVec4 * myVec4;  // Multiplies each component of myVec4
  7. // together (e.g., myVec4 ^ 2 )
  8. myVec4 = myMat4 * myVec4;  // Does a matrix * vector multiply of
  9. // myMat4 * myVec4
  10. myMat4 = myMat4 * myMat4;  // Does a matrix * matrix multiply of
  11. // myMat4 * myMat4
  12. myMat4 = myMat4 * myFloat; // Multiplies each matrix component by
  13. // the scalar myFloat

前面矩阵的行数就是结果矩阵的行数,后面矩阵的列数就是结果矩阵的列数。

8)自定义函数:

  1. vec4 myFunc(inout float myFloat,  // inout parameter
  2. out vec4 myVec4,      // out parameter
  3. mat4 myMat4);         // in parameter (default)

函数不能递归调用,因为GPU不一定有Stack和流控。

9)Shading Language内嵌函数

主要有以下几类函数:

(1)角度和三角函数

(2)指数函数

(3)通用函数(绝对值、取整、取余、取小数部分等)

(4)几何函数

(5)矩阵函数

(6)向量比较函数

(7)纹理查找函数

(8)Derivative函数

10)控制流

  1. if(color.a < 0.25)
  2. {
  3. color *= color.a;
  4. }
  5. else
  6. {
  7. color = vec4(0.0);
  8. }
  9. //For循环。只支持常数循环次数。
  10. //无论下标,还是循环变量,都只能使用编译时可确定的常数。
  11. for(int i = 0; i < 3; i++)
  12. {
  13. sum += i;
  14. }

以下不允许(因为下标为变量或loop次数为变量):

  1. float myArr[4];
  2. for(int i = 0; i < 3; i++)
  3. {
  4. sum += myArr[i]; // NOT ALLOWED IN OPENGL ES, CANNOT DO
  5. // INDEXING WITH NONCONSTANT EXPRESSION
  6. }
  7. ...
  8. uniform int loopIter;
  9. // NOT ALLOWED IN OPENGL ES, loopIter ITERATION COUNT IS NONCONSTANT
  10. for(int i = 0; i < loopIter; i++)
  11. {
  12. sum += i;
  13. }

11)Uniforms(前辍修改)
       Uniform前辍修饰的变量初始值由外部程序赋值。在program中具有统一访问空间,存储空间有限。在Shader中是只读的,只能由外部主机程序传入值。

它用于存储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)预处理

 

  1. #define
  2. #undef
  3. #if
  4. #ifdef
  5. #ifndef
  6. #else
  7. #elif
  8. #endif
  9. __LINE__ // Replaced with the current line number in a shader
  10. __FILE__ // Always 0 in OpenGL ES 2.0
  11. __VERSION__ // The OpenGL ES shading language version (e.g., 100)
  12. GL_ES // This will be defined for ES shaders to a value of 1

15) Uniform Attribute Varying存储空间最小值

变量类型

GPU必须支持的最小个数

Vertex Uniform Vectors

128

Fragment Uniform Vectors

16

Vertex Attributes

8

Varying Vectors

8

16) 精度限定(Precision Qualifiers)

关键词:lowp highp mediump

(1)指定变量精度(放在数据类型之前):

  1. highp vec4 position;
  2. varying lowp vec4 color;
  3. mediump float specularExp;

(2)指定默认精度(放在Vertex和Fragment shader源码的开始处):

  1. precision highp float;
  2. precision mediump int;

在Vertex Shader中,如果没有默认的精度,则float和int精度都为highp;在Fragment Shader中,float没有默认的精度,所以必须在Fragment Shader中为float指定一个默认精度或为每个float变量指定精度。

17)结果一致性

invariant可被应用于任何Vertex Shader Varying输出变量,其目前是保证相同的操作和相同的输入,其结果一样。因为由于Shader精度不一样,其结果有可能不一样。

  1. uniform mat4 u_viewProjMatrix;
  2. attribute vec4 a_vertex;
  3. invariant gl_Position;
  4. void main
  5. {
  6. // …
  7. gl_Position = u_viewProjMatrix * a_vertex; // Will be the same
  8. // value in all
  9. // shaders with the
  10. // same viewProjMatrix
  11. // and vertex
  12. }

也可指定所有的输出变量都为:invariant

  1. #pragma STDGL invariant(all)

四、获取和设置Uniforms

通过GLint   glGetUniformLocation(GLuint program,const char* name).根据一个Uniform的名称获取其location.

通过 glUniform***系列函数可以给一个location 设置一个Uniform的值。

  1. void glUniform1f(GLint location, GLfloat x)
  2. void glUniform1fv(GLint location, GLsizei count,const GLfloat* v)
  3. void glUniform1i(GLint location, GLint x)
  4. void glUniform1iv(GLint location, GLsizei count,const GLint* v)
  5. void glUniform2f(GLint location, GLfloat x, GLfloat y)
  6. void glUniform2fv(GLint location, GLsizei count,const GLfloat* v)
  7. void glUniform2i(GLint location, GLint x, GLint y)
  8. void glUniform2iv(GLint location, GLsizei count,const GLint* v)
  9. void glUniform3f(GLint location, GLfloat x, GLfloat y,GLfloat z)
  10. void glUniform3fv(GLint location, GLsizei count,const GLfloat* v)
  11. void glUniform3i(GLint location, GLint x, GLint y,GLint z)
  12. void glUniform3iv(GLint location, GLsizei count,const GLint* v)
  13. void glUniform4f(GLint location, GLfloat x, GLfloat y,GLfloat z, GLfloat w);
  14. void glUniform4fv(GLint location, GLsizei count,const GLfloat* v)
  15. void glUniform4i(GLint location, GLint x, GLint y,GLint z, GLint w)
  16. void glUniform4iv(GLint location, GLsizei count,const GLint* v)
  17. void glUniformMatrix2fv(GLint location, GLsizei count,
  18. GLboolean transpose,const GLfloat* value)
  19. void glUniformMatrix3fv(GLint location, GLsizei count,
  20. GLboolean transpose,const GLfloat* value)
  21. void glUniformMatrix4fv(GLint location, GLsizei count,
  22. GLboolean transpose,const GLfloat* value)

为矩阵uniform变量设置值的函数中的transpose必须为GL_FALSE,它目的为兼容性,但在 OpenGL ES 2.0中并没有工作。

一旦你设置了一个Program中unifrom变量的值之后,即使你激活了另外一个Program,此uniform的值不变。即uniform变量是Program的局部变量。

五、Vertex Attributes

Vertex属性即顶点数据,它指定了每个顶点的数据。在OpenGL ES1.1中,顶点属性有四个预定义的名字:position(位置), normal(法线), color(颜色), 和 texture coordinates(纹理坐标)。在OpenGL ES2.0中,用户必须定义“顶点属性的名字”。

1. 常量顶点属性(Constant Vertex Attribute)

常量顶点属性对所有顶点都是一样的。因此只需要指定一个值就可以应用于所有顶点。一般很少使用。其设置函数有:

  1. void glVertexAttrib1f(GLuint index, GLfloat x);
  2. void glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y);
  3. void glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z);
  4. void glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z,GLfloat w);
  5. void glVertexAttrib1fv(GLuint index, const GLfloat *values);
  6. void glVertexAttrib2fv(GLuint index, const GLfloat *values);
  7. void glVertexAttrib3fv(GLuint index, const GLfloat *values);
  8. void glVertexAttrib4fv(GLuint index, const GLfloat *values);

2. 如何装载顶点数据?(Vertex Arrays)

Vertex Array(顶点数组):是一个存储在应用程序空间(Client)中的内存buffer,它存储了每个顶点的属性数据。

如何把顶点数据组的数据传递给GPU呢?

void glVertexAttribPointer(GLuint index,

GLint size,     //每个属性元素个数有效值1-4(x,y,z,w)
                                                GLenum type, //数组中每个元素的数据类型
                                                GLboolean normalized,
                                                GLsizei stride, //如果数据连续存放,则为0或

//size*sizeof(type)
                                                const void *ptr)  //顶点数组指针

举例如下:

  1. GLfloat vVertices[] = {  0.0f,  0.5f, 0.0f,
  2. -0.5f, -0.5f, 0.0f,
  3. 0.5f, -0.5f, 0.0f };
  4. // Set the viewport
  5. glViewport ( 0, 0, esContext->width, esContext->height );
  6. // Clear the color buffer
  7. glClear ( GL_COLOR_BUFFER_BIT );
  8. // Use the program object
  9. glUseProgram (programObject );
  10. // Load the vertex data
  11. glVertexAttribPointer ( 0, 3, GL_FLOAT, GL_FALSE, 0, vVertices );

2.1 一个顶点的所有属性存储在一起(Array of Structures)

如下图所示,顶点的位置(x,y,z)、法线(x,y,z)和两个纹理坐标(s,t)存储在一起,如下图所示:

2.2 顶点的每个属性单独存储(Structure of Arrays)

Shader and Program编程基本概念 - 转的更多相关文章

  1. [转]C#网络编程(基本概念和操作) - Part.1

    本文转自:http://www.tracefact.net/CSharp-Programming/Network-Programming-Part1.aspx 引言 C#网络编程系列文章计划简单地讲述 ...

  2. 可以在任何时候attach一个shader到program对象

      可以在任何时候attach一个shader到program对象,不一定非要在指定source和编译以后,具体的描述如下: Once you have a program object create ...

  3. 一、动态网络编程的概念 二、Tomcat服务器搭建 三、Servlet组件介绍

    一.动态网络编程的概念 动态网页:结合了HTML以外的高级程序编程语言和数据库技术生成的页面. 动态网页编程技术: ASP,PHP,JSP HTTP协议:规范浏览器和服务器之间通信的数据格式. 浏览器 ...

  4. C#网络编程(基本概念和操作) - Part.1

    引言 C#网络编程系列文章计划简单地讲述网络编程方面的基础知识,由于本人在这方面功力有限,所以只能提供一些初步的入门知识,希望能对刚开始学习的朋友提供一些帮助.如果想要更加深入的内容,可以参考相关书籍 ...

  5. Python笔记002-Python编程基础概念

    第二章(1):Python编程基础概念 1. Python 程序的构成 Python 程序有模块组成.一个模块对应 Python 源文件,一般后缀名是:.py. 模块有语句组成.运行 Python程序 ...

  6. Java 网络编程----基本概念

    网络现在是一个非常普遍的概念. 以下是维基百科上的解释: 网络一词有多种意义,可解作: 网络流也简称为网络(network).一般用于管道系统.交通系统.通讯系统建模. 有时特指计算机网络. 或特指其 ...

  7. 关于网络协议和socket编程基本概念

    TCP协议可以说已经是IT人耳熟能详的协议,最近在学习socket网络编程时后重新温习一下这个协议,针对一些问题做了一些总结,很多理解可能还不是很准确. 1. 协议是什么?所谓的各种网络协议无非是一种 ...

  8. error: stray '\357' in program编程出错的总结

    错误: 编译报错:error: stray '\357' in program 原因:在程序中打入了全角字符   具体分析产生原因: 在编程中,由于打字的快速,按下ctrl键后紧接着按下了space键 ...

  9. [三]java8 函数式编程Stream 概念深入理解 Stream 运行原理 Stream设计思路

    Stream的概念定义   官方文档是永远的圣经~     表格内容来自https://docs.oracle.com/javase/8/docs/api/   Package java.util.s ...

随机推荐

  1. [转载]解决clickonce不支持administer权限问题

    转自ClickOnce deployment vs. requestedExecutionLevel = requireAdministrator ClickOnce方式部署应用简单方便,估计很多人都 ...

  2. sql 批量更新表中多字段为不同的值

    ,),,),rand()) select newid() ,) update tablename , FB,)) , ), FC,)) , )

  3. LeetCode the longest palindrome substring

    回文检测,参考http://blog.csdn.net/feliciafay/article/details/16984031 使用时间复杂度和空间复杂度相对较低的动态规划法来检测,具体的做法 图一 ...

  4. JAVA Eclipse 教程

    http://www.runoob.com/eclipse/eclipse-tutorial.html

  5. udp端口测试连接

    udp端口测试连接 http://www.361way.com/nc-udp-port/2949.html

  6. 慎用Java递归调用

    总结:慎用Java递归调用,测试时可以尝试该方法,否则尽量不要使用递归!递归过多调用时,最好改为for或者whlie来代替. 在java语言中,使用递归调用时,如果过多的调用容易造成java.lang ...

  7. JavaScript的字符串详解

    #转载请留言联系 字符串合并 + var str1="chi"; var str2="chung"; console.log(str1+str2) 输出:chi ...

  8. Django之模型ORM

    ORM介绍 ORM概念 对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术. 简单的说,ORM是通过使用描述 ...

  9. Win10系统解决C盘分区限制一半的问题

    1,按照网上的方法还不行,如链接 2,安装如下软件,里面有激活码,链接 链接:https://pan.baidu.com/s/14ifYpnCMGwJIbgykTYQR6Q 密码:whh3 3,安装并 ...

  10. Android仿QQ登录下拉历史列表

    demo中包含了Sqlite数据库增删改查,对存储的账号进行按照最新的时间排序,限制了最多存储5条数据. 效果图: 1.首先创建MyHelper建表: public class MyHelper ex ...