一、shader的使用步骤
创建shader
1、创建一个shader对象- GLuint glCreateShader(GLenum shaderType);
GLuint glCreateShader(GLenum shaderType);
2、将shader源代码传入前面创建的shader对象
- void glShaderSource(GLuint shader, int numOfStrings, const char **strings, int *lenOfStrings);
void glShaderSource(GLuint shader, int numOfStrings, const char **strings, int *lenOfStrings);
3、编译shader
- void glCompileShader(GLuint shader);
void glCompileShader(GLuint shader);
使用shader
1、创建一个对象,作为程序的容器- GLuint glCreateProgram(void);
GLuint glCreateProgram(void);
2、编译的shader附加到刚刚创建的程序中
- void glAttachShader(GLuint program, GLuint shader);
void glAttachShader(GLuint program, GLuint shader);
3、连接程序
- void glLinkProgram(GLuint program);
void glLinkProgram(GLuint program);
4、使用程序
- void glUseProgram(GLuint prog);
void glUseProgram(GLuint prog);
删除shader
- void glDeleteShader(GLuint id);
- void glDeleteProgram(GLuint id);
void glDeleteShader(GLuint id);
void glDeleteProgram(GLuint id);
更加详细内容参见
http://blog.youkuaiyun.com/racehorse/article/details/6616256
二、shader数据类型
1、attribute variables
随不同顶点变化的全局变量,也即可以针对每个顶点设置该变量。
注:个修饰符只能用在顶点shader中,在shader中它是一个只读变量。
2、uniform
随不同图元变化的全局变量,也即不能对每个顶点设置该变量。
注:其值不能在glBegin/glEnd中设置。一致变量适合描述在一个图元中、一帧中甚至一个场景中都不变的值。一致变量在顶点shader和片断shader中都是只读的。
3、varying
用于顶点shader和片断shader间传递的插值数据,在顶点shader中可写,在片断shader中只读
注:须同时在顶点shader和片断shader中声明
三、shader数据传输
(一)、glsl 2.x数据传输:
1、attribute变量传输- GLint glGetAttribLocation(GLuint program,char *name);
- void glVertexAttrib1f(GLint location, GLfloat v0);
- void glVertexAttrib2f(GLint location, GLfloat v0, GLfloat v1);
- void glVertexAttrib3f(GLint location, GLfloat v0, GLfloat v1,GLfloat v2);
- void glVertexAttrib4f(GLint location, GLfloat v0, GLfloat v1,,GLfloat v2, GLfloat v3);
GLint glGetAttribLocation(GLuint program,char *name);
void glVertexAttrib1f(GLint location, GLfloat v0);
void glVertexAttrib2f(GLint location, GLfloat v0, GLfloat v1);
void glVertexAttrib3f(GLint location, GLfloat v0, GLfloat v1,GLfloat v2);
void glVertexAttrib4f(GLint location, GLfloat v0, GLfloat v1,,GLfloat v2, GLfloat v3);
2、uniform变量传输
- GLint glGetUniformLocation(GLuint program, const char *name);
- void glUniform1f(GLint location, GLfloat v0);
- void glUniform2f(GLint location, GLfloat v0, GLfloat v1);
- void glUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
- void glUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
GLint glGetUniformLocation(GLuint program, const char *name);
void glUniform1f(GLint location, GLfloat v0);
void glUniform2f(GLint location, GLfloat v0, GLfloat v1);
void glUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
void glUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
注:getlocation要在program连接之后,因为链接后,会自动为它分配一个位置,我们可以在任何需要的时候获取(查询)这个位置。
3、varying变量传输
- //Vertex Shader
- out vec2 varying_vg_texcoord;
- //Geometry Shader
- in vec2 varying_vg_texcoord[];
- out vec2 varying_gf_texcoord;
- //Fragment Shader
- in vec2 varying_gf_texcoord;
//Vertex Shader
out vec2 varying_vg_texcoord;
//Geometry Shader
in vec2 varying_vg_texcoord[];
out vec2 varying_gf_texcoord;
//Fragment Shader
in vec2 varying_gf_texcoord;
(二)、glsl 3.x数据传输
在GL3.x中,废弃了attribute关键字以及varying关键字,属性变量统一用in/out作为前置关键字。
对每一个Shader stage来说,in表示该属性是作为输入的属性,out表示该属性是用于输出的属性。
1、attribute变量传输
直接在GLSL代码中指定这些位置值
- #version 330
- layout(location = 0) in vec3 attrib_position;
#version 330
layout(location = 0) in vec3 attrib_position;
这里使用了layout关键字。这个关键字用于一个具体变量前,用于显式标明该变量的一些布局属性,这里就是显式设定了该attribute变量的位置值(location)。
优点:
(1)、避免了getlocation的开销;
(2)、重定义了OpenGL和GLSL之间attribute变量属性的依赖。过去我们的OpenGL端必须首先要知道GLSL端某个attribute的名字,才能设置/获得其位置值,如今两者只需要location对应起来就可以完成绘制时顶点属性流的传递了
2、uniform变量传输
2.1 UBO
在一个复杂的shader中,uniform变量可能会很多,用glUniform()来传递数据会显得很臃肿;
另外,一个shader中uniform变量的数目是有上限的,所以不能传入太多的uniform 变量。
鉴于以上原因,提出了Uniform Buffer Object(UBO),这样可以把一个或多个uniform变量交给它,以替代glUniform的方式传递数据。
注意:传给UBO的数据,存储于这个UBO上,而不再是交给ShaderProgram,所以它们不会占用这个ShaderProgram自身的uniform存储空间。
另外,一个shader中uniform变量的数目是有上限的,所以不能传入太多的uniform 变量。
鉴于以上原因,提出了Uniform Buffer Object(UBO),这样可以把一个或多个uniform变量交给它,以替代glUniform的方式传递数据。
注意:传给UBO的数据,存储于这个UBO上,而不再是交给ShaderProgram,所以它们不会占用这个ShaderProgram自身的uniform存储空间。
2.2 uniform block
在unifom关键字后直接跟随一个block name和大括号,里面是一个或多个uniform变量.,用于与UBO关联。
- uniform BlobSettings {
- vec4 InnerColor;
- vec4 OuterColor;
- float RadiusInner;
- float RadiusOuter;
- };
- uniform BlobSettings{
- vec4 InnerColor;
- vec4 OuterColor;
- float RadiusInner;
- float RadiusOuter;
- }Blob;
uniform BlobSettings {
vec4 InnerColor;
vec4 OuterColor;
float RadiusInner;
float RadiusOuter;
};
uniform BlobSettings{
vec4 InnerColor;
vec4 OuterColor;
float RadiusInner;
float RadiusOuter;
}Blob;
在方法一中,Block中的变量依然是全局域的一部分,取用的时候不用Block名。
而在方法二中,Block中的变量则是在Blob名字域中,取用的时候需要加上Block名
2.3关联
对于每一个uniform block,都有一个“索引值”(index),这个索引值我们可以在OpenGL中获得,并把它与一个具体的UBO关联起来
- GLint blockIndex = glGetUniformBlockIndex(nProgramHandler, "BlobSettings");
- GLint nBlockDataSize = 0;
- glGetActiveUniformBlockiv(nProgramHandler, blockIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &nBlockDataSize);
- glGenBuffers(1, &m_nUBO);
- glBindBuffer(GL_UNIFORM_BUFFER, m_nUBO);
- glBufferData(GL_UNIFORM_BUFFER, nBlockDataSize, NULL, GL_DYNAMIC_DRAW);
- glBindBufferRange(GL_UNIFORM_BUFFER, 0, m_nUBO, 0, nBlockDataSize);
- glUniformBlockBinding(nProgramHandler, blockIndex, 0);
- glBindBuffer(GL_UNIFORM_BUFFER, NULL);
GLint blockIndex = glGetUniformBlockIndex(nProgramHandler, "BlobSettings");
GLint nBlockDataSize = 0;
glGetActiveUniformBlockiv(nProgramHandler, blockIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &nBlockDataSize);
glGenBuffers(1, &m_nUBO);
glBindBuffer(GL_UNIFORM_BUFFER, m_nUBO);
glBufferData(GL_UNIFORM_BUFFER, nBlockDataSize, NULL, GL_DYNAMIC_DRAW);
glBindBufferRange(GL_UNIFORM_BUFFER, 0, m_nUBO, 0, nBlockDataSize);
glUniformBlockBinding(nProgramHandler, blockIndex, 0);
glBindBuffer(GL_UNIFORM_BUFFER, NULL);
2.4 采用Block的原因
如果你的程序中包含了多个着色器,而且这些着色器使用了相同的Uniform变量,你就不得不为每个着色器分别管理这些变量。Uniform变量的location是在程序链接的时候产生的,因此Uniform变量的location会随着着色器的不同而发生变化。因此,这些Uniform变量的数据必须重新产生,然后应用到新的location上。
而Uniform Block正是为了使在着色器间共享Uniform数据变得更加容易而设计的。有了Uniform Block,我们可以创建一个缓冲区对象来存储这些Uniform变量的值,然后将缓冲区对象绑定到Uniform Block。当着色器程序改变的时候,只需要将同样的缓冲区对重新绑定到在新的着色器中与之相关的Block即可。
3、varing变量传输
in block和out block这两种可用于varing变量的
注意这里使用了block insatnce name(紧随大括号后的那个名字),这个名字对各Shader Stage来说都是独特的,所以改成上面这样的话,
block之间也不会发生名字冲突,block内的varying变量也就可以用同一个名字了。使用时需要按"blockInstanceName.varyingVariable"的类似结构体内变量的样式来表示。
注意这里使用了block insatnce name(紧随大括号后的那个名字),这个名字对各Shader Stage来说都是独特的,所以改成上面这样的话,
block之间也不会发生名字冲突,block内的varying变量也就可以用同一个名字了。使用时需要按"blockInstanceName.varyingVariable"的类似结构体内变量的样式来表示。
- //Vertex Shader
- out Varying
- {
- vec2 texcoord;
- }VaryingOut;
- //Geometry Shader
- in Varying
- {
- vec2 texcoord;
- }VaryingIn[];
- out Varying
- {
- vec2 texcoord;
- }VaryingOut;
- //Fragment Shader
- in Varying
- {
- vec2 texcoord;
- }VaryingIn;
//Vertex Shader
out Varying
{
vec2 texcoord;
}VaryingOut;
//Geometry Shader
in Varying
{
vec2 texcoord;
}VaryingIn[];
out Varying
{
vec2 texcoord;
}VaryingOut;
//Fragment Shader
in Varying
{
vec2 texcoord;
}VaryingIn;
4、fragmentShader输出
类似于上述的attribute变量,我们也可以直接通过layout来指定这个location值
- /单输出
- layout(location = 0) out vec4 fragColor;
- //MRT
- layout(location = 0) out vec4 fragColor0;
- layout(location = 1) out vec4 fragColor1;
/单输出
layout(location = 0) out vec4 fragColor;
//MRT
layout(location = 0) out vec4 fragColor0;
layout(location = 1) out vec4 fragColor1;
这些layout里的关键字其实还有个index——只是默认为0而已
- layout(location = 0, index = 0) out vec4 fragColor;
- layout(location = 0, index = 1) out vec4 src1Color;