先提供头文件下载地址:OpenGL Mathematics
我用的是0.9.9的版本,要注意声明mat4时,默认是初始化为0矩阵,而不再是单位矩阵,需要设置
类代码:
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>class Translate
{
public:glm::mat4 transform_matrix;Translate(){transform_matrix = glm::mat4(1.0f);}/// @brief 位移/// @param x 沿x轴/// @param y 沿y轴/// @param z 沿z轴void Move(float x, float y, float z){transform_matrix = glm::translate(transform_matrix, glm::vec3(x, y, z));}/// @brief 旋转/// @param angle 旋转角度/// @param rotatingShaft 旋转轴void Rotate(float angle, glm::vec3 rotatingShaft){transform_matrix = glm::rotate(transform_matrix, angle, rotatingShaft);}/// @brief 缩放/// @param x 沿x轴缩放/// @param y 沿y轴缩放/// @param z 沿z轴缩放void Scale(float x, float y, float z){transform_matrix = glm::scale(transform_matrix, glm::vec3(x, y, z));}
};
shadertool全代码,注意增加了一个传递uniform的mat4的函数
#ifndef SHADERTOOL_H
#define SHADERTOOL_H#include <glad/glad.h>#include <string>
#include <fstream>
#include <sstream>
#include <iostream>#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>class Translate
{
public:glm::mat4 transform_matrix;Translate(){transform_matrix = glm::mat4(1.0f);}/// @brief 位移/// @param x 沿x轴/// @param y 沿y轴/// @param z 沿z轴void Move(float x, float y, float z){transform_matrix = glm::translate(transform_matrix, glm::vec3(x, y, z));}/// @brief 旋转/// @param angle 旋转角度/// @param rotatingShaft 旋转轴void Rotate(float angle, glm::vec3 rotatingShaft){transform_matrix = glm::rotate(transform_matrix, angle, rotatingShaft);}/// @brief 缩放/// @param x 沿x轴缩放/// @param y 沿y轴缩放/// @param z 沿z轴缩放void Scale(float x, float y, float z){transform_matrix = glm::scale(transform_matrix, glm::vec3(x, y, z));}
};class Shader
{
public:unsigned int ID;Shader(const char *vertexPath, const char *fragmentPath){// 声明临时变量std::string vertexCode;std::string fragmentCode;std::ifstream vShaderFile;std::ifstream fShaderFile;// 确保文件流可以输出错误信息vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);try{// 打开文件vShaderFile.open(vertexPath);fShaderFile.open(fragmentPath);std::stringstream vShaderStream, fShaderStream;// 读取文件buffer到流vShaderStream << vShaderFile.rdbuf();fShaderStream << fShaderFile.rdbuf();// 关闭文件vShaderFile.close();fShaderFile.close();// 将流转换为stringvertexCode = vShaderStream.str();fragmentCode = fShaderStream.str();}catch (std::ifstream::failure &e){std::cout << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ: " << e.what() << std::endl;}const char *vShaderCode = vertexCode.c_str();const char *fShaderCode = fragmentCode.c_str();// 组合shaderunsigned int vertex, fragment;// vertex shadervertex = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertex, 1, &vShaderCode, NULL);glCompileShader(vertex);checkCompileErrors(vertex, "VERTEX");// fragment Shaderfragment = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragment, 1, &fShaderCode, NULL);glCompileShader(fragment);checkCompileErrors(fragment, "FRAGMENT");// shader ProgramID = glCreateProgram();glAttachShader(ID, vertex);glAttachShader(ID, fragment);glLinkProgram(ID);checkCompileErrors(ID, "PROGRAM");glDeleteShader(vertex);glDeleteShader(fragment);}/// @brief 调用Shadervoid use(){glUseProgram(ID);}/// @brief Shader全局bool参数设置/// @param name Shader参数名/// @param value 参数值void setBool(const std::string &name, bool value) const{glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);}/// @brief Shader全局int参数设置/// @param name Shader属性名/// @param value 属性值void setInt(const std::string &name, int value) const{glUniform1i(glGetUniformLocation(ID, name.c_str()), value);}/// @brief Shader全局float参数设置/// @param name Shader属性名/// @param value 属性值void setFloat(const std::string &name, float value) const{glUniform1f(glGetUniformLocation(ID, name.c_str()), value);}void setMat4(const std::string &name, glm::mat4 value){glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, glm::value_ptr(value));}/// @brief 销毁进程void release(){glDeleteProgram(ID);}private:/// @brief 检测Shader组合与编译的工具方法/// @param shader shaderID/// @param type 检测的类型void 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::PROGRAM_LINKING_ERROR of type: " << type << "\n"<< infoLog << "\n -- --------------------------------------------------- -- " << std::endl;}}}
};
#endif#ifndef STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"class Texture2D
{
public:unsigned int ID;int width, height, colorChannels;/// @brief 2D贴图/// @param filename 贴图路径/// @param ST_WARP_MINMAX_FILTER ST的Warp模式,缩小和放大的纹理过滤模式/// @param internalformat 保存的颜色格式/// @param format 源文件的颜色格式/// @param type 源文件的数据类型/// @param mipmap_level 手动设置mimap级别,默认为0Texture2D(const char *filename, GLint ST_WARP_MINMAX_FILTER[4], GLint internalformat, GLenum format, GLenum type, int mipmap_level = 0){glGenTextures(1, &ID);glBindTexture(GL_TEXTURE_2D, ID);// 为当前绑定的纹理对象设置环绕、过滤方式glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, ST_WARP_MINMAX_FILTER[0]);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, ST_WARP_MINMAX_FILTER[1]);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, ST_WARP_MINMAX_FILTER[2]);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, ST_WARP_MINMAX_FILTER[3]);// 加载并生成纹理unsigned char *data = stbi_load(filename, &width, &height, &colorChannels, 0);if (data){glTexImage2D(GL_TEXTURE_2D, mipmap_level, internalformat, width, height, 0, format, type, data);glGenerateMipmap(GL_TEXTURE_2D);}else{std::cout << "Failed to load texture" << std::endl;}stbi_image_free(data);};/// @brief 2D贴图,图像翻转/// @param filename 贴图路径/// @param ST_WARP_MINMAX_FILTER ST的Warp模式,缩小和放大的纹理过滤模式/// @param internalformat 保存的颜色格式/// @param format 源文件的颜色格式/// @param type 源文件的数据类型/// @param flipY 加载前是否反转图像/// @param mipmap_level 手动设置mimap级别,默认为0Texture2D(const char *filename, GLint ST_WARP_MINMAX_FILTER[4], GLint internalformat, GLenum format, GLenum type, bool flipY, int mipmap_level = 0){glGenTextures(1, &ID);glBindTexture(GL_TEXTURE_2D, ID);// 为当前绑定的纹理对象设置环绕、过滤方式glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, ST_WARP_MINMAX_FILTER[0]);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, ST_WARP_MINMAX_FILTER[1]);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, ST_WARP_MINMAX_FILTER[2]);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, ST_WARP_MINMAX_FILTER[3]);// 加载并生成纹理stbi_set_flip_vertically_on_load(flipY);unsigned char *data = stbi_load(filename, &width, &height, &colorChannels, 0);if (data){glTexImage2D(GL_TEXTURE_2D, mipmap_level, internalformat, width, height, 0, format, type, data);glGenerateMipmap(GL_TEXTURE_2D);}else{std::cout << "Failed to load texture" << std::endl;}stbi_image_free(data);};
};#endif
调用函数:
顶点Shader:
#version 330 core
layout (location=0) in vec3 aPos;
layout (location=1) in vec3 color;
layout (location=2) in vec2 texcoord;out vec3 vertexColor;
out vec2 uv;
uniform mat4 transform;
void main()
{gl_Position = transform*vec4(aPos.x,aPos.y,aPos.z,1.0);vertexColor = color;uv=texcoord;
}
片元Shader:
#version 330 core
out vec4 fragColor;
in vec3 vertexColor;
in vec2 uv;uniform sampler2D mainTexture;
uniform sampler2D secondTexture;void main()
{vec4 baseColor=texture(mainTexture,uv);vec4 addColor = texture(secondTexture,vec2(-uv.x*2.,uv.y*2.));fragColor=mix(baseColor,addColor,addColor.a);
}
主函数:
#include <shadertool.h>
#include <GLFW/glfw3.h>unsigned int Screen_Width = 600;
unsigned int Screen_Height = 600;void player_input(GLFWwindow *window)
{if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)glfwSetWindowShouldClose(window, true);
}void frame_sizebuffer_callback(GLFWwindow *window, int width, int height)
{glViewport(0, 0, width, height);
}int main()
{glfwInit();glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_COMPAT_PROFILE, GLFW_OPENGL_CORE_PROFILE);#ifdef __APPLE__glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
#endifGLFWwindow *window = glfwCreateWindow(Screen_Width, Screen_Height, "DrawTriangle", NULL, NULL);if (window == NULL){std::cout << "Fail to create window !" << std::endl;glfwTerminate();return -1;}glfwMakeContextCurrent(window);glfwSetFramebufferSizeCallback(window, frame_sizebuffer_callback);if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){std::cout << "Fail to initialize glad !" << std::endl;return -1;}Shader triangle_shader("shaders/vertex.vs", "shaders/fragment.fs");float vertices[] = {// ---- 位置 ---- ---- 颜色 ---- - 纹理坐标 -0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 右上0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 右下-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // 左下-0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // 左上};unsigned int indices[] = {0, 1, 3, // first triangle1, 2, 3 // second triangle};unsigned int VBO, VAO, EBO;glGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);glGenBuffers(1, &EBO);// 先绑定VAO,再绑定和设置VBO,然后配置顶点属性glBindVertexArray(VAO);glBindBuffer(GL_ARRAY_BUFFER, VBO);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);// position attributeglVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)0);glEnableVertexAttribArray(0);// color attributeglVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)(3 * sizeof(float)));glEnableVertexAttribArray(1);// texture coord attributeglVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)(6 * sizeof(float)));glEnableVertexAttribArray(2);GLint wrapFilterParams[4] = {GL_REPEAT, GL_REPEAT, GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR};Texture2D texture("textures/container.jpg", wrapFilterParams, GL_RGB, GL_RGB, GL_UNSIGNED_BYTE);Texture2D texture2("textures/awesomeface.png", wrapFilterParams, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, true);triangle_shader.use(); // 设置uniform变量之前激活着色器程序!glUniform1i(glGetUniformLocation(triangle_shader.ID, "mainTexture"), 0); // 手动设置贴图采样器绑定triangle_shader.setInt("secondTexture", 1); // 或者使用着色器类设置贴图采样器绑定while (!glfwWindowShouldClose(window)){/* code */player_input(window);glClear(GL_COLOR_BUFFER_BIT);// render containerglActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_2D, texture.ID);glActiveTexture(GL_TEXTURE1);glBindTexture(GL_TEXTURE_2D, texture2.ID);Translate transform;transform.Move(0.0f, 0.1f, 0.0f);transform.Rotate((float)glfwGetTime(), glm::vec3(0.0f, 0.0f, 1.0f));// unsigned int transformLoc = glGetUniformLocation(triangle_shader.ID, "transform");// glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(transform.transform_matrix));triangle_shader.setMat4("transform", transform.transform_matrix);triangle_shader.use();glBindVertexArray(VAO);glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);glfwSwapBuffers(window);glfwPollEvents();}glDeleteVertexArrays(1, &VAO);glDeleteBuffers(1, &VBO);glDeleteBuffers(1, &EBO);triangle_shader.release();glfwTerminate();return 0;
}
效果: