OpenGL笔记十四之GLM数学库的配置与使用
—— 2024-07-20 中午
bilibili赵新政老师的教程看后笔记
code review!
文章目录
把GLM文件夹拷贝thirdParty/include文件夹下
1.旋转变换运行效果
2.平移变换运行效果
3.缩放变换运行效果
4.复合变换:先旋转 再平移运行效果
5.复合变换:先平移 后旋转运行效果
6.每一帧都旋转运行效果
注意:每一帧都是从起始位姿旋转而至
7.关键代码
7.1.vs
代码
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aUV;
out vec3 color;
out vec2 uv;
uniform mat4 transform;
//aPos作为attribute(属性)传入shader
//不允许更改的
void main()
{
vec4 position = vec4(aPos, 1.0);
position = transform * position;
gl_Position = position;
color = aColor;
uv = aUV;
}
7.2.fs
代码
#version 330 core
out vec4 FragColor;
in vec3 color;
in vec2 uv;
uniform sampler2D sampler;
void main()
{
FragColor = texture(sampler, uv);
}
7.3.main.cpp关键片段
main.cpp完整代码
#include <iostream>
#include "glframework/core.h"
#include "glframework/shader.h"
#include <string>
#include <assert.h>//断言
#include "wrapper/checkError.h"
#include "application/Application.h"
#include "glframework/texture.h"
/*
*┌────────────────────────────────────────────────┐
*│ 目 标: 初步学习GLM库的平移/旋转/缩放
*│ 讲 师: 赵新政(Carma Zhao)
*│ 拆分目标:
* -1 引入GLM的头文件
* -2 更改vertexShader,加入uniform变量mat4 transform
* -3 使用传入的transform给我们的顶点坐标进行变换
* -4 为shader类增加uniform矩阵传输的功能
* -5 使用矩阵做复合变换
* -6 连续转动三角形(动画)
*└────────────────────────────────────────────────┘
*/
GLuint vao;
Shader* shader = nullptr;
Texture* texture = nullptr;
glm::mat4 transform(1.0f);
void OnResize(int width, int height) {
GL_CALL(glViewport(0, 0, width, height));
std::cout << "OnResize" << std::endl;
}
void OnKey(int key, int action, int mods) {
std::cout << key << std::endl;
}
void doRotationTransform() {
//构建一个旋转矩阵,绕着z轴旋转45度角
//rotate函数:用于生成旋转矩阵
//bug1:rotate必须得到一个float类型的角度,c++的template
//bug2:rotate函数接受的不是角度(degree),接收的弧度(radians)
//注意点:radians函数也是模板函数,切记要传入float类型数据,加f后缀
transform = glm::rotate(glm::mat4(1.0f),glm::radians(90.0f), glm::vec3(0.0, 0.0, 1.0));
}
//平移变换
void doTranslationTransform() {
transform = glm::translate(glm::mat4(1.0f), glm::vec3(0.5f, 0.0f, 0.0f));
}
//缩放变换
void doScaleTransform() {
transform = glm::scale(glm::mat4(1.0f), glm::vec3(0.1f, 0.5f, 1.0f));
}
//复合变换
void doTransform() {
glm::mat4 rotateMat = glm::rotate(glm::mat4(1.0f), glm::radians(90.0f), glm::vec3(0.0, 0.0, 1.0));
glm::mat4 translateMat = glm::translate(glm::mat4(1.0f), glm::vec3(0.5f, 0.0f, 0.0f));
//先旋转 再平移
// transform = translateMat * rotateMat;
//先平移 后旋转
transform = rotateMat * translateMat;
}
float angle = 0.0f;
void doRotation() {
angle += 2.0f;
//每一帧都会“重新”构建一个旋转矩阵
transform = glm::rotate(glm::mat4(1.0f), glm::radians(angle), glm::vec3(0.0, 0.0, 1.0));
}
void prepareVAO() {
//1 准备positions colors
float positions[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f,
};
float colors[] = {
1.0f, 0.0f,0.0f,
0.0f, 1.0f,0.0f,
0.0f, 0.0f,1.0f,
};
float uvs[] = {
0.0f, 0.0f,
1.0f, 0.0f,
0.5f, 1.0f,
};
unsigned int indices[] = {
0, 1, 2,
};
//2 VBO创建
GLuint posVbo, colorVbo, uvVbo;
glGenBuffers(1, &posVbo);
glBindBuffer(GL_ARRAY_BUFFER, posVbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);
glGenBuffers(1, &colorVbo);
glBindBuffer(GL_ARRAY_BUFFER, colorVbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
glGenBuffers(1, &uvVbo);
glBindBuffer(GL_ARRAY_BUFFER, uvVbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(uvs), uvs, GL_STATIC_DRAW);
//3 EBO创建
GLuint ebo;
glGenBuffers(1, &ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
//4 VAO创建
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
//5 绑定vbo ebo 加入属性描述信息
//5.1 加入位置属性描述信息
glBindBuffer(GL_ARRAY_BUFFER, posVbo);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 3, (void*)0);
//5.2 加入颜色属性描述数据
glBindBuffer(GL_ARRAY_BUFFER, colorVbo);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 3, (void*)0);
//5.3 加入uv属性描述数据
glBindBuffer(GL_ARRAY_BUFFER, uvVbo);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, (void*)0);
//5.4 加入ebo到当前的vao
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBindVertexArray(0);
}
void prepareShader() {
shader = new Shader("assets/shaders/vertex.glsl","assets/shaders/fragment.glsl");
}
void prepareTexture() {
texture = new Texture("assets/textures/goku.jpg", 0);
}
void render() {
//执行opengl画布清理操作
GL_CALL(glClear(GL_COLOR_BUFFER_BIT));
//绑定当前的program
shader->begin();
shader->setInt("sampler", 0);
shader->setMatrix4x4("transform", transform);
//绑定当前的vao
GL_CALL(glBindVertexArray(vao));
//发出绘制指令
GL_CALL(glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0));
GL_CALL(glBindVertexArray(0));
shader->end();
}
int main() {
if (!app->init(800, 600)) {
return -1;
}
app->setResizeCallback(OnResize);
app->setKeyBoardCallback(OnKey);
//设置opengl视口以及清理颜色
GL_CALL(glViewport(0, 0, 800, 600));
GL_CALL(glClearColor(0.2f, 0.3f, 0.3f, 1.0f));
prepareShader();
prepareVAO();
prepareTexture();
// doRotationTransform();
// doTranslationTransform();
// doScaleTransform();
doTransform();
while (app->update()) {
// doRotation();
render();
}
app->destroy();
return 0;
}
7.4.shader.h关键片段
void setMatrix4x4(const std::string& name, glm::mat4 value);
shader.h完整代码
#pragma once
#include "core.h"
#include<string>
class Shader {
public:
Shader(const char* vertexPath, const char* fragmentPath);
~Shader();
void begin();//开始使用当前Shader
void end();//结束使用当前Shader
void setFloat(const std::string& name, float value);
void setVector3(const std::string& name, float x, float y, float z);
void setVector3(const std::string& name, const float* values);
void setInt(const std::string& name, int value);
void setMatrix4x4(const std::string& name, glm::mat4 value);
private:
//shader program
//type:COMPILE LINK
void checkShaderErrors(GLuint target,std::string type);
private:
GLuint mProgram{ 0 };
};
7.5.shader.cpp关键片段
void Shader::setMatrix4x4(const std::string& name, glm::mat4 value) {
//1 通过名称拿到Uniform变量的位置Location
GLint location = GL_CALL(glGetUniformLocation(mProgram, name.c_str()));
//2 通过Location更新Uniform变量的值
//transpose参数:表示是否对传输进去的矩阵数据进行转置
glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(value));
}
shader.cpp完整代码
#include"shader.h"
#include"../wrapper/checkError.h"
#include<string>
#include<fstream>
#include<sstream>
#include<iostream>
Shader::Shader(const char* vertexPath, const char* fragmentPath) {
//声明装入shader代码字符串的两个string
std::string vertexCode;
std::string fragmentCode;
//声明用于读取vs跟fs文件的inFileStream
std::ifstream vShaderFile;
std::ifstream fShaderFile;
//保证ifstream遇到问题的时候可以抛出异常
vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try {
//1 打开文件
vShaderFile.open(vertexPath);
fShaderFile.open(fragmentPath);
//2 将文件输入流当中的字符串输入到stringStream里面
std::stringstream vShaderStream, fShaderStream;
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
//3 关闭文件
vShaderFile.close();
fShaderFile.close();
//4 将字符串从stringStream当中读取出来,转化到code String当中
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
}
catch (std::ifstream::failure& e) {
std::cout << "ERROR: Shader File Error: " << e.what() << std::endl;
}
const char* vertexShaderSource = vertexCode.c_str();
const char* fragmentShaderSource = fragmentCode.c_str();
//1 创建Shader程序(vs、fs)
GLuint vertex, fragment;
vertex = glCreateShader(GL_VERTEX_SHADER);
fragment = glCreateShader(GL_FRAGMENT_SHADER);
//2 为shader程序输入shader代码
glShaderSource(vertex, 1, &vertexShaderSource, NULL);
glShaderSource(fragment, 1, &fragmentShaderSource, NULL);
//3 执行shader代码编译
glCompileShader(vertex);
//检查vertex编译结果
checkShaderErrors(vertex, "COMPILE");
glCompileShader(fragment);
//检查fragment编译结果
checkShaderErrors(fragment, "COMPILE");
//4 创建一个Program壳子
mProgram = glCreateProgram();
//6 将vs与fs编译好的结果放到program这个壳子里
glAttachShader(mProgram, vertex);
glAttachShader(mProgram, fragment);
//7 执行program的链接操作,形成最终可执行shader程序
glLinkProgram(mProgram);
//检查链接错误
checkShaderErrors(mProgram, "LINK");
//清理
glDeleteShader(vertex);
glDeleteShader(fragment);
}
Shader::~Shader() {
}
void Shader::begin() {
GL_CALL(glUseProgram(mProgram));
}
void Shader::end() {
GL_CALL(glUseProgram(0));
}
void Shader::setFloat(const std::string& name, float value) {
//1 通过名称拿到Uniform变量的位置Location
GLint location = GL_CALL(glGetUniformLocation(mProgram, name.c_str()));
//2 通过Location更新Uniform变量的值
GL_CALL(glUniform1f(location, value));
}
void Shader::setVector3(const std::string& name, float x, float y, float z) {
//1 通过名称拿到Uniform变量的位置Location
GLint location = GL_CALL(glGetUniformLocation(mProgram, name.c_str()));
//2 通过Location更新Uniform变量的值
GL_CALL(glUniform3f(location, x, y, z));
}
//重载 overload
void Shader::setVector3(const std::string& name, const float* values) {
//1 通过名称拿到Uniform变量的位置Location
GLint location = GL_CALL(glGetUniformLocation(mProgram, name.c_str()));
//2 通过Location更新Uniform变量的值
//第二个参数:你当前要更新的uniform变量如果是数组,数组里面包括多少个向量vec3
GL_CALL(glUniform3fv(location, 1, values));
}
void Shader::setInt(const std::string& name, int value) {
//1 通过名称拿到Uniform变量的位置Location
GLint location = GL_CALL(glGetUniformLocation(mProgram, name.c_str()));
//2 通过Location更新Uniform变量的值
glUniform1i(location, value);
}
void Shader::setMatrix4x4(const std::string& name, glm::mat4 value) {
//1 通过名称拿到Uniform变量的位置Location
GLint location = GL_CALL(glGetUniformLocation(mProgram, name.c_str()));
//2 通过Location更新Uniform变量的值
//transpose参数:表示是否对传输进去的矩阵数据进行转置
glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(value));
}
void Shader::checkShaderErrors(GLuint target, std::string type) {
int success = 0;
char infoLog[1024];
if (type == "COMPILE") {
glGetShaderiv(target, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(target, 1024, NULL, infoLog);
std::cout << "Error: SHADER COMPILE ERROR" << "\n" << infoLog << std::endl;
}
}
else if (type == "LINK") {
glGetProgramiv(target, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(target, 1024, NULL, infoLog);
std::cout << "Error: SHADER LINK ERROR " << "\n" << infoLog << std::endl;
}
}
else {
std::cout << "Error: Check shader errors Type is wrong" << std::endl;
}
}
7.6.core.h中要把代码包含进来
core.h
#pragma once
//注意:glad头文件必须在glfw引用之前引用
#include <glad/glad.h>
#include <GLFW/glfw3.h>
//GLM
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/string_cast.hpp>