OpenGL custom shader

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)