当前位置: 首页 > 工具软件 > Uniform > 使用案例 >

GLSL (4)Uniform

高展
2023-12-01

1. Uniform是一种从CPU中的应用向GPU中的着色器发送数据的方式

OpenGL在其核心是一个C库,不支持类型重载,在函数参数不同的时候就要为其定义新的函数;每当配置一个OpenGL的选项时就可以简单地根据这些规则选择适合的数据类型的重载函数。

glUniform是一个典型例子。这个函数有一个特定的后缀,标识设定的uniform的类型。

eg.

设定uniform的4个float值
glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f);
后缀含义
f函数需要一个float作为它的值
i函数需要一个int作为它的值
ui函数需要一个unsigned int作为它的值
3f函数需要3个float作为它的值
fv函数需要一个float向量/数组作为它的值

1.1 vs 顶点属性

uniform是全局的(Global)。

  • uniform变量必须在每个着色器程序对象中都是独一无二的,而且它可以被着色器程序的任意着色器在任意阶段访问。
  • 无论uniform值被设置成什么,uniform会一直保存它们的数据,直到它们被重置或更新。

1.2 如果声明了一个uniform却在GLSL代码中没用过,编译器会静默移除这个变量,导致最后编译出的版本中并不会包含它

2. 使用步骤

step1. 声明一个GLSL的uniform。

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

#version 330 core
out vec4 FragColor;

uniform vec4 ourColor; // 在OpenGL程序代码中设定这个变量

void main()
{
FragColor = ourColor;
}

step2. 添加数据

首先需要找到着色器中uniform属性的索引/位置值。当我们得到uniform的索引/位置值后,我们就可以更新它的值了

//让变量随着时间改变颜色:我们通过glfwGetTime()获取运行的秒数。
//使用sin函数让颜色在0.0到1.0之间改变,最后将结果储存到greenValue里。
float timeValue = glfwGetTime();
float greenValue = (sin(timeValue) / 2.0f) + 0.5f;
int vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor");//查询uniform ourColor的位置值,需要提供着色器程序和uniform的名字
glUseProgram(shaderProgram);
glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f);/设置uniform值

如果glGetUniformLocation返回-1就代表没有找到这个位置值。
注意,查询uniform地址不要求你之前使用过着色器程序,但是更新一个uniform之前你必须先使用程序(调用glUseProgram),因为它是在当前激活的着色器程序中设置uniform的。

eg.

while(!glfwWindowShouldClose(window))
{
    // 输入
    processInput(window);
    
    // 渲染
    // 清除颜色缓冲
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    
    // 记得激活着色器
    glUseProgram(shaderProgram);
    
    // 更新uniform颜色
    float timeValue = glfwGetTime();
    float greenValue = sin(timeValue) / 2.0f + 0.5f;
    int vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor");
    glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f);
    
    // 绘制三角形
    glBindVertexArray(VAO);
    glDrawArrays(GL_TRIANGLES, 0, 3);
    
    // 交换缓冲并查询IO事件
    glfwSwapBuffers(window);
    glfwPollEvents();
}
 类似资料: