着色器详解

在顶点着色器中,每个输入变量叫做顶点属性

着色器语言之变量类型
1>uniform:

其实就是统一(全局)变量,统一变量通常保存在所谓的“常量存储”中,uniform变量是外部(cpu)application程序传递给(顶点和片元)(GPU)着色器的变量,该变量不会随着顶点或片元的变化而变化,除非应用程序对它进行了更新。在GLSL语言中,其类似于C语言中的常量const,它不能被shader程序修改,也就是个只读变量,只能读,不能更改。

uniform 的空间被顶点和片元着色器共享,因此若在一个顶点着色器中声明了uniform,相当于在片元着色器中也声明过了。

uniform变量一般用来表示:变换矩阵,材质,光照参数和颜色等信息。

uniform变量在所有可用的着色阶段之间都是共享的。

例如:

我们设置一个给图元着色的颜色值,此时可以声明一个uniform变量,将颜色值信息传递到着色器中。而着色器中会进行如下声明:

uniform vec4 color;

在片元着色器中设置:

1 #version 330 core
2 out vec4 FragColor;
3 
4 uniform vec4 ourColor; // 在OpenGL程序代码中设定这个变量
5 
6 void main()
7 {
8     FragColor = ourColor;
9 }

我们在片段着色器中声明了一个uniform vec4ourColor,并把片段着色器的输出颜色设置为uniform值的内容。因为uniform是全局变量,我们可以在任何着色器中定义它们,而无需通过顶点着色器作为中介。顶点着色器中不需要这个uniform,所以我们不用在顶点着色器中定义颜色。

这个uniform现在还是空的;我们还没有给它添加任何数据,所以下面我们就做这件事。我们首先需要找到着色器中uniform属性的索引/位置值。当我们得到uniform的索引/位置值后,我们就可以更新它的值了。这次我们不去给像素传递单独一个颜色,而是让它随着时间改变颜色:

1 float timeValue = glfwGetTime();
2 float greenValue = (sin(timeValue) / 2.0f) + 0.5f;
3 int vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor");
4 glUseProgram(shaderProgram);
5 glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f);

首先我们通过glfwGetTime()获取运行的秒数。然后我们使用sin函数让颜色在0.0到1.0之间改变,最后将结果储存到greenValue里。

接着,我们用glGetUniformLocation查询uniform ourColor的位置值。我们为查询函数提供着色器程序和uniform的名字(这是我们希望获得的位置值的来源)。如果glGetUniformLocation返回-1就代表没有找到这个位置值。

最后,我们可以通过glUniform4f函数设置uniform值。注意,查询uniform地址不要求你之前使用过着色器程序,但是更新一个uniform之前你必须先使用程序(调用glUseProgram),因为它是在当前激活的着色器程序中设置uniform的。

如果我们打算让颜色慢慢变化,我们就要在游戏循环的每一次迭代中(所以他会逐帧改变)更新这个uniform,否则三角形就不会改变颜色。所以我们把这5行代码放在渲染循环中。

glUniform的功能:为当前程序对象指定Uniform变量的值
void glUniform4f(GLint location,  GLfloat v0,  GLfloat v1,  GLfloat v2,  GLfloat v3); 

location指明要更改的uniform变量的位置,

v0,v1,v2,v3指明在指定的uniform变量中要使用的新值

1、为什么是greenValue?

只因为放在了RGB中第二个位置,如果放在第一个位置,则为红色。

2、为什么是变成了黑色?

因为用了sin让值在0-1中渐变,当为0的时候,就变成了黑色。同理,如果设置了另外的RGB中的值,视情况而定。

2>attribute变量

attribute变量是只能在vertex shader中使用的变量。(它不能在fragment shader中声明attribute变量,也不能被fragment shader中使用)

一般用attribute变量来表示一些顶点的数据,如:顶点坐标,法线,纹理坐标,顶点颜色等。

例如:

1 uniform mat4 u_matViewProjection;
2 attribute vec4 a_position;
3 attribute vec2 a_texCoord0;
4 varying vec2 v_texCoord;
5 void main(void)
6 {
7 gl_Position = u_matViewProjection * a_position;
8 v_texCoord = a_texCoord0;
9 }

3>varying变量

varying变量是vertex和fragment shader之间做数据传递用的。一般vertex shader修改varying变量的值,然后fragment shader使用该varying变量的值。因此varying变量在vertex和fragment shader二者之间的声明必须是一致的。

例如:

 1 // Vertex shader
 2 uniform mat4 u_matViewProjection;
 3 attribute vec4 a_position;
 4 attribute vec2 a_texCoord0;
 5 varying vec2 v_texCoord; // Varying in vertex shader
 6 void main(void)
 7 {
 8 gl_Position = u_matViewProjection * a_position;
 9 v_texCoord = a_texCoord0;//被修改
10 }
11 
12 
13 // Fragment shader
14 precision mediump float;
15 varying vec2 v_texCoord; // Varying in fragment shader
16 uniform sampler2D s_baseMap;
17 uniform sampler2D s_lightMap;
18 void main()
19 {
20 vec4 baseColor;
21 vec4 lightColor;
22 baseColor = texture2D(s_baseMap, v_texCoord);
23 lightColor = texture2D(s_lightMap, v_texCoord);//被使用
24 gl_FragColor = baseColor * (lightColor + 0.25);
25 }

4>in/out

in –输入

out–输出

在顶点着色器中的out变量在片元着色器中就是对应的in变量,因为片元着色器的输入就是顶点着色器的输出

in out定义的变量的值会在openGL每次执行着色器的时候更新(如果处理的是顶点,那么这里会为每个顶点传递新的值;如果处理的是片元,那么会为每个片元传递新的值)

Published by

风君子

独自遨游何稽首 揭天掀地慰生平

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注