上一节中有提到着色器中可以定义uniform变量,而查询和设置uniform的变量要用到特定的函数,且需要知道该着色器所在的着色器程序的ID,由于现在我们已经把着色器的创建过程封装成一个类,虽然目前着色器程序的ID值是公有成员,可以通过对象来获知ID然后自行去设置uniform的值,但把查询和设置uniform变量的功能整合到着色器类中显然是更方便的。
在上节类的定义中,我们应该补充几个set函数的声明,来设置不同类型的uniform变量的值。
class Shader
{
public:
Shader(const GLchar* vertexPath, const GLchar* fragmentPath);
void use();
unsigned int ID;
void setBool(const std::string &name, bool value)const;
void setInt(const std::string &name, int value)const;
void setFloat(const std::string &name, float value)const;
};
然后在cpp档定义这3个函数:
void Shader::setBool(const std::string &name, bool value)const {
glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
}
void Shader::setFloat(const std::string &name, float value)const {
glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
}
void Shader::setInt(const std::string &name, int value)const {
glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
}
我们把glGetUniformLocation()
函数返回的uniform变量位置值直接作为glUniform1i/1f
函数的第一个参数。这样就能一行代码搞定查询和设值了。
现在我们就可以给定义了uniform变量的着色器程序设置其值了。既然要测试这几个函数能否如常的工作,那我就顺便把练习也做了:
使用uniform定义一个水平偏移量,在顶点着色器中使用这个偏移量把三角形移动到屏幕右侧
我们现在顶点着色器的源码中定义一个uniform变量用作水平偏移量,把它加到aPos的x分量上,这就实现了三角形的水平偏移:
#version 330 core
layout (location = 0) in vec3 aPos; // 位置变量的属性位置值为 0
layout (location = 1) in vec3 aColor; // 颜色变量的属性位置值为 1
out vec3 ourColor; // 向片段着色器输出一个颜色
uniform float horizontalOffset; //水平偏移量
void main()
{
gl_Position = vec4(aPos.x + horizontalOffset, aPos.y, aPos.z, 1.0f);
ourColor = aColor; // 将ourColor设置为我们从顶点数据那里得到的输入颜色
}
然后在cpp档中调用我们刚定义好的SetFloat函数,设置上面宣告的uniform变量的值,切记在调用SetFloat函数前要先激活着色器程序,就是先调用use()
函数,不然输出毫无变化:
shader.use();
shader.setFloat("horizontalOffset", 0.5f);
现在可以点击运行看看结果了,可以看到三角着实往右偏移了:
修改顶点着色器让三角形上下颠倒
这其实很简单嘛,在顶点着色器的源码中把输入进来的aPos的y分量负值化在传递给gl_Position就好了:
#version 330 core
layout (location = 0) in vec3 aPos; // 位置变量的属性位置值为 0
layout (location = 1) in vec3 aColor; // 颜色变量的属性位置值为 1
out vec3 ourColor; // 向片段着色器输出一个颜色
uniform float horizontalOffset;
void main()
{
gl_Position = vec4(aPos.x, -aPos.y, aPos.z, 1.0f);
ourColor = aColor; // 将ourColor设置为我们从顶点数据那里得到的输入颜色
}
使用out关键字把顶点位置输出到片段着色器,并将片段的颜色设置为与顶点位置相等(来看看连顶点位置值都在三角形中被插值的结果)
这其实也不难,就是直接把读取到的顶点数据(aPos)直接输出给片段着色器(ourColor):
#version 330 core
layout (location = 0) in vec3 aPos; // 位置变量的属性位置值为 0
layout (location = 1) in vec3 aColor; // 颜色变量的属性位置值为 1
out vec3 ourColor; // 向片段着色器输出一个颜色
uniform float horizontalOffset;
void main()
{
gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0f);
ourColor = aPos; // 将ourColor设置为我们从顶点数据那里得到的输入颜色
}
得到的结果如下:
这个题目虽然简单,但呈现的结果值得思考:为什么三角形的左下部分是黑色的呢?
因为现在是顶点位置直接作为颜色输出,那左下的顶点坐标是什么?是(-0.5, -0.5 ,0)。因为xy是负值,在转换为rgb值就固定在了0.0f值上,所以该点呈现黑色,那左下区域都是黑色该怎么解释,这其实跟上节讲到的片段插值有关,片段着色器会自动帮两个顶点所连直线做颜色内插处理。黑色一直到了三角形的中线才停止是因为在那一点被插值之后才出现正值。就例如中点,该点的颜色值应该是((-0.5*50%+0.0*50%),(-0.5*50%+0.25*50%), (0*50%+0*50%)) = (-0.25, 0, 0)=(RGB)(0, 0, 0)。所以从这点开始再往上才逐渐出现颜色。