The purpose of this article is how to use OpenGL to customize Shader.
First make sure you can draw forms and triangles: portal
Previously, Shader was written directly in the code, which was very inconvenient to use.
The general method for projects is to customize the shader file and then read the text content
How to achieve?
1. Custom Shader class
shader.h header file
The main function:
a)Program ID
b) Read the text and build the compiled shader
c)Activate/release program
d) Set custom parameters (uniform)
#ifndef SHADER #define SHADER #include <glad/glad.h> //Include glad to get all required OpenGL header files #include <string> #include <fstream> #include <sstream> #include <iostream> classShader {<!-- --> public: //Program ID unsigned int ID; //Constructor, build shader Shader(const char* vertexPath, const char* fragmentPath); //Use/activate program void use(); void del(); //uniform tool function void setB(const std::string & amp;name, bool v1) const; void setF(const std::string & amp; name, float v1) const; void setF3(const std::string & amp; name, float v1, float v2, float v3) const; }; #endif SHADER
shader.cpp implementation file
Detailed explanations of functions are all commented in the code.
The main function:
a) Read the file content through ifsteam
b) Compile shader link shader program
c) For Uniform settings
#include "Shader.h" Shader::Shader(const char* vertexPath, const char* fragmentPath) {<!-- --> //1. Get the shader from the file path //Source code definition std::string vertexCode; std::string fragmentCode; //ifstream stream definition std::ifstream vShaderFile; std::ifstream fShaderFile; // Ensure that the ifstream object can throw exceptions: vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); try {<!-- --> \t\t// open a file vShaderFile.open("Shader/" + std::string(vertexPath)); fShaderFile.open("Shader/" + std::string(fragmentPath)); std::stringstream vShaderStream, fShaderStream; //Read the buffer contents of the file into the data stream vShaderStream << vShaderFile.rdbuf(); fShaderStream << fShaderFile.rdbuf(); // Close the file handler vShaderFile.close(); fShaderFile.close(); //Convert data stream to string vertexCode = vShaderStream.str(); fragmentCode = fShaderStream.str(); } catch (std::ifstream::failure e) {<!-- --> std::cout << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ" << std::endl; } const char* vShaderCode = vertexCode.c_str(); const char* fShaderCode = fragmentCode.c_str(); //2. Compile shader //vertex shader unsigned int vertexShader; vertexShader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertexShader, 1, & amp;vShaderCode, NULL); glCompileShader(vertexShader); int success; char infoLog[512]; glGetShaderiv(vertexShader, GL_COMPILE_STATUS, & amp;success); if (!success) {<!-- --> glGetShaderInfoLog(vertexShader, 512, NULL, infoLog); std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\\ " << infoLog << std::endl; } //fragment shader unsigned int fragmentShader; fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragmentShader, 1, & amp;fShaderCode, NULL); glCompileShader(fragmentShader); glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, & amp;success); if (!success) {<!-- --> glGetShaderInfoLog(vertexShader, 512, NULL, infoLog); std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\\ " << infoLog << std::endl; } \t//Link ID = glCreateProgram(); glAttachShader(ID, vertexShader); glAttachShader(ID, fragmentShader); glLinkProgram(ID); glGetProgramiv(ID, GL_LINK_STATUS, & amp;success); if (!success) {<!-- --> glGetProgramInfoLog(ID, 512, NULL, infoLog); std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\\ " << infoLog << std::endl; } glDeleteShader(vertexShader); glDeleteShader(fragmentShader); } void Shader::use() {<!-- --> glUseProgram(ID); } void Shader::del() {<!-- --> glDeleteProgram(ID); } void Shader::setB(const std::string & amp; name, bool v1) const {<!-- --> //glGetUniformLocation query function provides the name of the shader program and uniform // If -1 is returned, it means not found auto location = glGetUniformLocation(ID, name.c_str()); //glUniform1i sets the uniform value (1i is 1 int) // Before updating a uniform, you must first use it and set the uniform in the currently activated shader program. glUniform1i(location, (int)v1); } void Shader::setF(const std::string & amp; name, float v1) const {<!-- --> auto location = glGetUniformLocation(ID, name.c_str()); glUniform1f(location, v1); } void Shader::setF3(const std::string & amp; name, float v1, float v2, float v3) const {<!-- --> auto location = glGetUniformLocation(ID, name.c_str()); glUniform3f(location, v1, v2, v3); }
2. Define shader source code
Naming: vertex shader xx.vs fragment shader xx.fs
test.vs, fixed-point shader code
//test.vs #version 330 core layout (location=0) in vec3 aPos; //0 is the vertex position layout (location=1) in vec3 aCol; //1 is the vertex color uniform vec3 center; //custom parameters, code transfer out vec3 outCol; //Color returned to fragment shader void main() { //Move according to the passed center vec3 pos = aPos + (center)*0.5f; //flip triangle pos.y *= -1; //Return cropping coordinates gl_Position = vec4(pos, 1.0f); //Calculate distance as mask to affect color float dist = distance(pos, vec3(0.0f, 0.0f, 0.0f)); outCol = aCol * dist; }
test.fs, fragment shader code
//test.fs #version 330 core in vec3 outCol; //Accept the color value returned by the vertex shader out vec4 FragColor; //Output the final color void main() { FragColor = vec4(outCol.rgb, 1.0f); }
3. Program use
Pseudocode
//...Create window Shader testShader("test.vs", "test.fs"); //... Build VBO VAO EBO //Rendering loop while(..) { //... Clear screen and bind VAO \t testShader.use(); //Current elapsed time in seconds float timeValue = (float)glfwGetTime(); testShader.use(); testShader.setF3("center", sin(timeValue), cos(timeValue), 0.0f); //... draw } testShader.del(); //... freed
Effect (actually it still moves)