前面的文章中有提到,要绘制出简单的图形,我们需要提供顶点着色器和片段着色器。在前面绘制三角形和矩形的过程中,顶点着色器处理了我们输入的顶点坐标数据,然后片段着色器是固定输出了颜色。
现在,我们通过一定的方法,让片段着色器可以输出不同的颜色,这个方法就是借助:uniform关键词。
在片段着色器中,我们将在变量声明前面加上uniform关键词,就能在外部调整这个变量的值,从而影响到着色器程序的运行效果:
const char* fragmentShaderSource = "#version 330 core " "out vec4 FragColor; " "uniform vec4 u_color; " "void main() {" " FragColor = u_color; " "} ";
上述片段着色器代码中,u_color变量前面加上了uniform关键词,然后将这个变量赋值给FragColor,这样片段着色器输出的颜色,就由u_color的值决定。
那么如何给uniform声明的变量赋值?
首先,我们需要找到这个变量的索引:
glGetUniformLocation(shaderProgram2, "u_color")
glGetUniformLocation方法,参数1为我们创建的着色器程序的索引ID,参数2为uniform变量的名字,该方法返回该变量的索引,如果返回的是-1,说明该变量不存在。
获取到了位置之后,我们就可以给该变量赋值了:
glUniform4f(uniformLocation, 0.0f, 1.0f, 0.0f, 1.0f);
因为opengl是c实现的,没有函数的重载功能。但是我们知道变量有多种类型,像float、int等,所以只能创建各种命名为glUniformxxx的函数,来针对各种不同类型的变量进行赋值处理,在这里我们的uniform变量的类型是vec4,即4个浮点类型的数据,所以我们用到的函数是glUniform4f,参数1是我们前面找到的变量地址,后面4个值就对应vec4的4个值了。
要使我们的赋值生效,我们需要在调用赋值方法之前,先调用glUseProgram方法。
另外需要注意的是,如果我们在着色器代码中声明了uniform类型的变量,但是在代码中又没有用到这个变量,那么着色器编译的时候就会去掉这个变量,就导致我们在想改变这个变量值的时候,发现改变不了。这个是需要我们注意的。原文作者的话是:If you declare a uniform that isn't used anywhere in your GLSL code the compiler will silently remove the variable from the compiled version which is the cause for several frustrating errors; keep this in mind! 我觉得应该就是我说的意思。
对应的代码在这里。