A uniform is a global Shader variable declared with the “uniform” storage qualifier. These act as parameters that the user of a shader program can pass to that program. Their values are stored in a program object.
Uniforms are so named because they do not change from one shader invocation to the next within a particular rendering call thus their value is uniform among all invocations. This makes them unlike shader stage inputs and outputs, which are often different for each invocation of a shader stage.
https://www.khronos.org/opengl/wiki/Uniform_(GLSL)#:~:text=A%20uniform%20is%20a%20global,stored%20in%20a%20program%20object.
#version 330 core
layout (location = 0) in vec2 aPos;
uniform float time; // we define an uniform
void main() {
// we use uniform for manipulating vertex position
gl_Position = vec4(aPos.x * cos(time), aPos.y * sin(time/1), 0.0, 1.0);
}
int location = glGetUniformLocation(shaderID, "time");
glUniform1f(location, 5.0f);
glGetUniformLocation
returns an integer that represents the location of a specific uniform variable within a program object.glUniform
modifies the value of a uniform variable or a uniform variable array.
Shader source
basic.shader
#shader vertex
#version 330 core
layout (location = 0) in vec2 aPos;
uniform float time;
void main() {
gl_Position = vec4(aPos.x * cos(time), aPos.y * sin(time/1), 0.0, 1.0);
}
#shader fragment
#version 330 core
out vec4 FragColor;
void main() {
FragColor = vec4(0.9f, 0.2f, 0.2f, 1.0f);
}
Shader Class
We collect vertex and fragment code to a file “basic.shader”. After that, we create a parser for separate vertex and fragment code. Why do we do that? Instead of reading two files we want to read only one file. Of course, you can read vertex and fragment shader code from different files.
Also, we add functions for getting uniform location and setting uniform. We use unordered-map for caching. (
#pragma once
#include <string>
#include <unordered_map>
struct ShaderProgramSource {
std::string VertexSource;
std::string FragmentSource;
};
class Shader
{
unsigned int ID{};
std::unordered_map<std::string, unsigned int> m_UniformLocationCache;
unsigned int CompileShader(std::string source, unsigned int shader_type);
void CompileProgram(unsigned int vs, unsigned int fs);
ShaderProgramSource ParseShader(const std::string& filepath);
int GetUniformLocation(const std::string& name);
public:
void Compile();
void Bind();
void Unbind();
void SetUniform1f(const std::string& name, float value);
};
#include "Shader.h"
#include "glad/glad.h"
#include <iostream>
#include <fstream>
#include <sstream>
void Shader::Compile(){
auto source = ParseShader("basic.shader");
std::cout << "Vertex shader:\n" << std::endl;
std::cout << source.VertexSource << std::endl << std::endl;
std::cout << "Fragment shader:\n" << std::endl;
std::cout << source.FragmentSource << std::endl;
unsigned int vs = CompileShader(source.VertexSource, GL_VERTEX_SHADER);
unsigned int fs = CompileShader(source.FragmentSource, GL_FRAGMENT_SHADER);
CompileProgram(vs, fs);
}
unsigned int Shader::CompileShader(std::string source, unsigned int shader_type)
{
const char* source_code = source.c_str();
unsigned int shaderID = glCreateShader(shader_type);
glShaderSource(shaderID, 1, &source_code, NULL);
glCompileShader(shaderID);
// check for shader compile errors
int success;
char infoLog[512];
glGetShaderiv(shaderID, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(shaderID, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::" << (shader_type == GL_VERTEX_SHADER ? "VERTEX" : "FRAGMENT") << "::COMPILATION_FAILED\n" << infoLog << std::endl;
}
return shaderID;
}
void Shader::CompileProgram(unsigned int vs, unsigned int fs){
// link shaders to a program
unsigned int shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vs);
glAttachShader(shaderProgram, fs);
glLinkProgram(shaderProgram);
// check for linking errors
int success;
char infoLog[512];
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
}
// delete shader after linking program because we dont need them
glDeleteShader(vs);
glDeleteShader(fs);
ID = shaderProgram;
}
ShaderProgramSource Shader::ParseShader(const std::string& filepath){
std::ifstream stream(filepath);
enum class ShaderType {
NONE = -1, VERTEX = 0, FRAGMENT = 1
};
std::string line;
std::stringstream ss[2];
ShaderType type = ShaderType::NONE;
while (getline(stream, line))
{
if (line.find("#shader") != std::string::npos) {
if (line.find("vertex") != std::string::npos)
type = ShaderType::VERTEX;//set mode to vertex
else if (line.find("fragment") != std::string::npos)
type = ShaderType::FRAGMENT;//set mode to fragment
}
else {
ss[(int)type] << line << "\n";
}
}
return { ss[0].str(),ss[1].str() };
}
int Shader::GetUniformLocation(const std::string& name)
{
if (m_UniformLocationCache.find(name) != m_UniformLocationCache.end())
return m_UniformLocationCache[name];
int location = glGetUniformLocation(ID, name.c_str());
if (location == -1)
std::cout << "Warning: uniform " << name << " doesn't exist!" << std::endl;
else
m_UniformLocationCache[name] = location;
return location;
}
void Shader::Bind(){
glUseProgram(ID);
}
void Shader::Unbind(){
glUseProgram(0);
}
void Shader::SetUniform1f(const std::string& name, float value)
{
glUniform1f(GetUniformLocation(name), value);
}
Render Loop
We only add one line of code to pass the time to the shader program.
// |>----------<>----------<>----------<>----------<>----------<|
// |> RENDER LOOP <|
// |>----------<>----------<>----------<>----------<>----------<|
va.Bind();
while (!glfwWindowShouldClose(window)) {
shader.SetUniform1f("time", glfwGetTime()); // this line
glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(window);
glfwPollEvents();
}
- https://www.khronos.org/opengl/wiki/Uniform_(GLSL)#:~:text=A%20uniform%20is%20a%20global,stored%20in%20a%20program%20object.
- https://registry.khronos.org/OpenGL-Refpages/gl4/html/glGetUniformLocation.xhtml
- https://registry.khronos.org/OpenGL-Refpages/gl4/html/glUniform.xhtml
Leave a Reply