先提供头文件下载地址: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();
// 将流转换为string
vertexCode = 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();
// 组合shader
unsigned int vertex, fragment;
// vertex shader
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, NULL);
glCompileShader(vertex);
checkCompileErrors(vertex, "VERTEX");
// fragment Shader
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, NULL);
glCompileShader(fragment);
checkCompileErrors(fragment, "FRAGMENT");
// shader Program
ID = glCreateProgram();
glAttachShader(ID, vertex);
glAttachShader(ID, fragment);
glLinkProgram(ID);
checkCompileErrors(ID, "PROGRAM");
glDeleteShader(vertex);
glDeleteShader(fragment);
}
/// @brief 调用Shader
void 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级别,默认为0
Texture2D(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级别,默认为0
Texture2D(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);
#endif
GLFWwindow *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 triangle
1, 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 attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)0);
glEnableVertexAttribArray(0);
// color attribute
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
// texture coord attribute
glVertexAttribPointer(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 container
glActiveTexture(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;
}
效果:
