opengl shader 使用札记

本文详细介绍Shader的创建、使用及删除步骤,并深入探讨不同版本GLSL中的数据类型及其传输方式,包括attribute、uniform和varying变量的具体用法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、shader的使用步骤

创建shader

1、创建一个shader对象

  1. GLuint glCreateShader(GLenum shaderType);    
GLuint glCreateShader(GLenum shaderType);  

2、将shader源代码传入前面创建的shader对象

  1. void glShaderSource(GLuint shader, int numOfStrings, const char **strings, int *lenOfStrings);    
void glShaderSource(GLuint shader, int numOfStrings, const char **strings, int *lenOfStrings);  

3、编译shader

  1. void glCompileShader(GLuint shader);   
void glCompileShader(GLuint shader); 

使用shader

1、创建一个对象,作为程序的容器

  1. GLuint glCreateProgram(void);    
GLuint glCreateProgram(void);  

2、编译的shader附加到刚刚创建的程序中

  1. void glAttachShader(GLuint program, GLuint shader);   
void glAttachShader(GLuint program, GLuint shader); 

3、连接程序

  1. void glLinkProgram(GLuint program);    
void glLinkProgram(GLuint program);  

4、使用程序

  1. void glUseProgram(GLuint prog);  
void glUseProgram(GLuint prog);

删除shader

  1. void glDeleteShader(GLuint id);    
  2. 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变量传输

  1. GLint glGetAttribLocation(GLuint program,char *name);   
  2. void glVertexAttrib1f(GLint location, GLfloat v0);    
  3. void glVertexAttrib2f(GLint location, GLfloat v0, GLfloat v1);    
  4. void glVertexAttrib3f(GLint location, GLfloat v0, GLfloat v1,GLfloat v2);    
  5. 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变量传输

  1. GLint glGetUniformLocation(GLuint program, const char *name);    
  2. void glUniform1f(GLint location, GLfloat v0);    
  3. void glUniform2f(GLint location, GLfloat v0, GLfloat v1);    
  4. void glUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);    
  5. 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变量传输

  1. //Vertex Shader     
  2. out vec2 varying_vg_texcoord;      
  3.     
  4. //Geometry Shader     
  5. in  vec2 varying_vg_texcoord[];      
  6. out vec2 varying_gf_texcoord;      
  7.     
  8. //Fragment Shader     
  9. 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代码中指定这些位置值

  1. #version 330     
  2. 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存储空间。

2.2 uniform block
在unifom关键字后直接跟随一个block name和大括号,里面是一个或多个uniform变量.,用于与UBO关联。
  1. uniform BlobSettings {    
  2.   vec4 InnerColor;    
  3.   vec4 OuterColor;    
  4.   float RadiusInner;    
  5.   float RadiusOuter;    
  6. };    
  7.   
  8. uniform BlobSettings{    
  9.     vec4 InnerColor;    
  10.     vec4 OuterColor;    
  11.     float RadiusInner;    
  12.     float RadiusOuter;    
  13. }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关联起来
  1. GLint blockIndex = glGetUniformBlockIndex(nProgramHandler, "BlobSettings");   
  2.    
  3. GLint nBlockDataSize = 0;    
  4.     
  5. glGetActiveUniformBlockiv(nProgramHandler, blockIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &nBlockDataSize);    
  6.   
  7. glGenBuffers(1, &m_nUBO);    
  8.   
  9. glBindBuffer(GL_UNIFORM_BUFFER, m_nUBO);    
  10.   
  11. glBufferData(GL_UNIFORM_BUFFER, nBlockDataSize, NULL, GL_DYNAMIC_DRAW);    
  12.   
  13. glBindBufferRange(GL_UNIFORM_BUFFER, 0, m_nUBO, 0, nBlockDataSize);    
  14.   
  15. glUniformBlockBinding(nProgramHandler, blockIndex, 0);    
  16.   
  17. 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"的类似结构体内变量的样式来表示。
  1. //Vertex Shader     
  2. out Varying    
  3. {    
  4.      vec2 texcoord;    
  5. }VaryingOut;    
  6.     
  7. //Geometry Shader     
  8. in Varying    
  9. {    
  10.      vec2 texcoord;    
  11. }VaryingIn[];    
  12.     
  13. out Varying    
  14. {    
  15.     vec2 texcoord;    
  16. }VaryingOut;    
  17.     
  18. //Fragment Shader     
  19. in Varying    
  20. {    
  21.     vec2  texcoord;       
  22. }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值
  1. /单输出    
  2. layout(location = 0) out vec4 fragColor;    
  3.     
  4. //MRT     
  5. layout(location = 0) out vec4 fragColor0;    
  6. 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而已
  1. layout(location = 0, index = 0) out vec4 fragColor;    
  2. layout(location = 0, index = 1) out vec4 src1Color;   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值