经过前面着色器的学习,我写了一个可以左右移动,并随时间变换的三色三角形
先是着色器类Shader.h
#ifndef __SHADER_H__
#define __SHADER_H__
#include <glad/glad.h>
#include <glm/glm.hpp>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
class Shader {
private:
unsigned int ID;
public:
//构造器读取并构建着色器
Shader(const char* vertexPath, const char* fragmentPath, const char* geometryPath = nullptr);
//激活着色器程序
void use();
//释放着色器程序
void del();
//uniform工具函数
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;
void setVec2(const std::string& name, const glm::vec2& value) const;
void setVec2(const std::string& name, float x, float y) const;
void setVec3(const std::string& name, const glm::vec3& value) const;
void setVec3(const std::string& name, float x, float y, float z) const;
void setVec4(const std::string& name, const glm::vec4& value) const;
void setVec4(const std::string& name, float x, float y, float z, float w);
void setMat2(const std::string& name, const glm::mat2& mat) const;
void setMat3(const std::string& name, const glm::mat3& mat) const;
void setMat4(const std::string& name, const glm::mat4& mat) const;
//检测编译,链接是否成功
void checkCompileErrors(unsigned int shader, std::string type);
};
#endif // __SHADER_H__
实现着色器类Shader.cpp
#include "Shader.h"
//构造函数
Shader::Shader(const char* vertexPath, const char* fragmentPath, const char* geometryPath)
{
//从文件路径中获取顶点/片段着色器
std::string vertexCode;//存储顶点着色器的代码
std::string fragmentCode;//存储片段着色器的代码
std::string geometryCode;//存储几何着色器的代码
std::ifstream vShaderFile;
std::ifstream fShaderFile;
std::ifstream gShaderFile;
//保证ifstream对象可以抛出异常
vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
gShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try
{
//打开文件
vShaderFile.open(vertexPath);//打开存储顶点着色器代码的文件
fShaderFile.open(fragmentPath);//打开存储片段着色器代码的文件
std::stringstream vShaderStream, fShaderStream;
//读取文件中的内容
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
//关闭文件处理器
vShaderFile.close();
fShaderFile.close();
//将读取的数据转换为string
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
//如果几何着色器也要改
if (geometryPath != nullptr)
{
gShaderFile.open(geometryPath);
std::stringstream gShaderStream;
gShaderStream << gShaderFile.rdbuf();
gShaderFile.close();
geometryCode = gShaderStream.str();
}
}
catch (std::ifstream::failure& e)
{
std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
}
const char* vShaderCode = vertexCode.c_str();//指向顶点着色器的代码
const char* fShaderCode = fragmentCode.c_str();//指向片段着色器的代码
//编译着色器
unsigned int vertex, fragment, geometry;
//编译顶点着色器
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, NULL);
glCompileShader(vertex);
checkCompileErrors(vertex, "VERTEX");//检查编译是否成功
//编译片段着色器
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, NULL);
glCompileShader(fragment);
checkCompileErrors(fragment, "FRAGMENT");//检查编译是否成功
//编译几何着色器
if (geometryPath != nullptr)
{
const char* gShaderCode = geometryCode.c_str();
geometry = glCreateShader(GL_GEOMETRY_SHADER);
glShaderSource(geometry, 1, &gShaderCode, NULL);
glCompileShader(geometry);
checkCompileErrors(geometry, "GEOMETRY");
}
//着色器程序,把顶点,片段着色器链接起来
ID = glCreateProgram();
glAttachShader(ID, vertex);
glAttachShader(ID, fragment);
if (geometryPath != nullptr)
glAttachShader(ID, geometry);
glLinkProgram(ID);
checkCompileErrors(ID, "PROGRAM");//检查链接是否成功
//销毁顶点,片段着色器,因为他们已经链接到程序中了
glDeleteShader(vertex);
glDeleteShader(fragment);
}
//激活着色器程序
void Shader::use() {
glUseProgram(ID);
}
//释放着色器程序
void Shader::del() {
glDeleteProgram(ID);
}
//设置uniform的值
void Shader::setBool(const std::string& name, bool value) const {
glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
}
void Shader::setInt(const std::string& name, int value) const {
glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
}
void Shader::setFloat(const std::string& name, float value) const {
glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
}
void Shader::setVec2(const std::string& name, const glm::vec2& value) const
{
glUniform2fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
}
void Shader::setVec2(const std::string& name, float x, float y) const
{
glUniform2f(glGetUniformLocation(ID, name.c_str()), x, y);
}
void Shader::setVec3(const std::string& name, const glm::vec3& value) const
{
glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
}
void Shader::setVec3(const std::string& name, float x, float y, float z) const
{
glUniform3f(glGetUniformLocation(ID, name.c_str()), x, y, z);
}
void Shader::setVec4(const std::string& name, const glm::vec4& value) const
{
glUniform4fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
}
void Shader::setVec4(const std::string& name, float x, float y, float z, float w)
{
glUniform4f(glGetUniformLocation(ID, name.c_str()), x, y, z, w);
}
void Shader::setMat2(const std::string& name, const glm::mat2& mat) const
{
glUniformMatrix2fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
}
void Shader::setMat3(const std::string& name, const glm::mat3& mat) const
{
glUniformMatrix3fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
}
void Shader::setMat4(const std::string& name, const glm::mat4& mat) const
{
glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
}
//检查链接,编译是否成功
void Shader::checkCompileErrors(unsigned int shader, std::string type) {
int success;
char infoLog[1024];
if (type != "PROGRAM"){
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(shader, 1024, NULL, infoLog);
std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n"
<< infoLog
<< "\n -- --------------------------------------------------- -- "
<< std::endl;
}
}
else {
glGetProgramiv(shader, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shader, 1024, NULL, infoLog);
std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n"
<< infoLog
<< "\n -- --------------------------------------------------- -- "
<< std::endl;
}
}
}
顶点着色器文件(放在源文件里)
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
out vec3 ourColor;
uniform float xOffset;
uniform float colorChange;
void main()
{
gl_Position = vec4(aPos.x + xOffset, -aPos.y, aPos.z, 1.0);
ourColor = vec3(aColor.x + colorChange, aColor.y + colorChange, aColor.z + colorChange);
}
片段着色器
#version 330 core
out vec4 FragColor;
in vec3 ourColor;
void main()
{
FragColor = vec4(ourColor, 1.0f);
}
测试
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include "Shader.h"
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);
void f(int a);
void f(int a = 10) {
std::cout << a;
}
int main() {
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
if (window == NULL) {
std::cout << "打开窗口失败" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "初始化GLAD库失败" << std::endl;
return -1;
}
//自定义构造器
Shader myShader("shader.vs", "shader.fs");
float vertices[] = {
//顶点 //颜色
-0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f,//左下角
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f,//右下角
0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f//顶角
};
unsigned int VBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
while (!glfwWindowShouldClose(window)) {
processInput(window);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
myShader.use();//启用着色器程序
float timeValue = glfwGetTime();
float offset = sin(timeValue);
float color = cos(timeValue);
myShader.setFloat("xOffset", offset);
myShader.setFloat("colorChange", color);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
glfwSwapBuffers(window);
glfwPollEvents();
}
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
myShader.del();
glfwTerminate();
return 0;
}
void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
glViewport(0, 0, width, height);
}
void processInput(GLFWwindow* window) {
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
}