官网学习链接
纹理 - LearnOpenGL CN变换 - LearnOpenGL CN
理论总结:
向量与标量相加减乘除
向量的长度计算
向量取反
向量单位化
向量与向量相加减
向量点乘
向量叉乘
矩阵介绍
线性变换和仿射变换行
主序和列主序
矩阵与标量相加减和数乘
计算虽然复杂,但是我们使用计算机计算,调库传参数足以。
GLM
GLM是OpenGL Mathematics的缩写,它是一个只有头文件的库,也就是说我们只需包含对应的头文件就行了,不用链接和编译。GLM可以在它们的网站上下载。把头文件的根目录复制到你的includes文件夹,然后你就可以使用这个库了。
建议下载0.99版本起
OpenGL 数学 --- OpenGL Mathematics
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
代码实践
我们只需要定义一个矩阵,旋转 缩放 位移的操作,通过矩阵来进行。
可以把矩阵当作状态,设置旋转 缩放 位移,最后应用。
举个例子:
//使用案例 把mat当作属性 复制到mat4的uniform变量中
glm::mat4 trans = glm::mat4(1.0f);
//设置旋转 缩放 位移
trans = glm::translate(trans, glm::vec3(-0.3f));
trans = glm::rotate(trans, glm::radians((float)factor *100 ), glm::vec3(0.0f, 0.0f, 1.0f));
trans = glm::scale(trans, glm::vec3(0.5f, 0.5f, 0.5f));
//应用
ourShader.setMat4("transform", trans);
综合实践
/*
坐标转换
https://learnopengl-cn.github.io/01%20Getting%20started/07%20Transformations/#_20
向量+-* × / 矩阵的+- *
*/
#include"Shader.h"
#define STB_IMAGE_IMPLEMENTATION
#include"stb_image.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include<cmath>
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);
// 定义顶点数组
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
};
int main(int argc, char* argv[])
{
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 << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
// 设置视口
glViewport(0, 0, 800, 600);
glEnable(GL_PROGRAM_POINT_SIZE);
// 注册窗口变化监听
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
Shader ourShader("./vertex.glsl", "./fragment.glsl");
// 创建缓冲对象
unsigned int VBO, VAO, EBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
// 绑定VAO缓冲对象
glBindVertexArray(VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
// 填充EBO数据
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// 绑定VBO缓对象
glBindBuffer(GL_ARRAY_BUFFER, VBO);
// 填充VBO数据
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// 设置顶点位置属性指针
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// 设置顶点颜色属性指针
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
//设置顶点的纹理坐标
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
glBindVertexArray(0);
// 设置线框绘制模式
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
// 图像y轴翻转
stbi_set_flip_vertically_on_load(true);
// 创建纹理对象
unsigned int texture;
// 绑定纹理
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
// 设置环绕和过滤方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
//加载纹理
int width, height, nrChannels;
unsigned char* data = stbi_load("./container.jpg", &width, &height, &nrChannels, 0);
if (!data)
{
std::cout << "Failed to load texture" << std::endl;
return -1;
}
// 加载纹理数据
glTexImage2D(GL_TEXTURE_2D //纹理目标
, 0 //纹理指定多级渐远纹理的级别,如果你希望单独手动设置每个多级渐远纹理的级别的话。这里我们填0,也就是基本级别
, GL_RGB //告诉OpenGL我们希望把纹理储存为何种格式。
, width //纹理图像的宽度
, height //纹理图像的高度
, 0 //历史遗留参数,设置为0
, GL_RGB //纹理图像的格式
, GL_UNSIGNED_BYTE //纹理图像的数据类型
, data //真正的图像数据
);
// 生成多级渐远纹理
glGenerateMipmap(GL_TEXTURE_2D);
// 释放纹理数据
stbi_image_free(data);
// 创建纹理对象2
unsigned int texture2;
glGenTextures(1, &texture2);
// 绑定纹理
glBindTexture(GL_TEXTURE_2D, texture2);
// 设置环绕和过滤方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// 图像y轴翻转
stbi_set_flip_vertically_on_load(true);
//加载纹理
data = stbi_load("./awesomeface.png", &width, &height, &nrChannels, 0);
if (!data)
{
std::cout << "Failed to load texture" << std::endl;
return -1;
}
// 加载纹理数据
glTexImage2D(GL_TEXTURE_2D //纹理目标
, 0 //纹理指定多级渐远纹理的级别,如果你希望单独手动设置每个多级渐远纹理的级别的话。这里我们填0,也就是基本级别
, GL_RGBA //告诉OpenGL我们希望把纹理储存为何种格式。
, width //纹理图像的宽度
, height //纹理图像的高度
, 0 //历史遗留参数,设置为0
, GL_RGBA //纹理图像的格式
, GL_UNSIGNED_BYTE //纹理图像的数据类型
, data //真正的图像数据
);
// 生成多级渐远纹理
glGenerateMipmap(GL_TEXTURE_2D);
// 释放纹理数据
stbi_image_free(data);
//激活和绑定纹理
ourShader.use();
ourShader.setInt("ourTexture", 0);
ourShader.setInt("ourTexture2", 1);
glm::vec4 pos = glm::vec4(0.0f, 0.0f, 0.0f, 1.0f);
//把一个向量(1, 0, 0)位移(1, 1, 0)个单位
glm::mat4 trans = glm::mat4(1.0f);
std::cout<<"start position:" << pos.x << " " << pos.y << " " << pos.z << std::endl;
trans = glm::translate(trans, glm::vec3(0.1f, 0.1f, 0.0f));
pos = trans * pos;
std::cout << pos.x << " " << pos.y << " " << pos.z << std::endl;
//旋转90度
trans = glm::rotate(trans, glm::radians(90.0f), glm::vec3(0.0f, 0.0f, 1.0f));
pos = trans * pos;
std::cout << pos.x << " " << pos.y << " " << pos.z << std::endl;
//缩放0.5
trans = glm::scale(trans, glm::vec3(0.5f, 0.5f, 0.5f));
pos = trans * pos;
std::cout << pos.x << " " << pos.y << " " << pos.z << std::endl;
int factor = 0;
while (!glfwWindowShouldClose(window))
{
processInput(window);
// 渲染指令
// ...
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
/*ourShader.use();
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);*/
//激活一个纹理单元
glActiveTexture(GL_TEXTURE0);
//将texture绑定到当前激活的纹理单元上
glBindTexture(GL_TEXTURE_2D, texture);
//激活另一个纹理单元
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture2);
factor = glfwGetTime();
ourShader.setFloat("factor", factor);
//使用案例 把mat当作属性 复制到mat4的uniform变量中
glm::mat4 trans = glm::mat4(1.0f);
//设置旋转和t
trans = glm::translate(trans, glm::vec3(-0.3f));
trans = glm::rotate(trans, glm::radians((float)factor *100 ), glm::vec3(0.0f, 0.0f, 1.0f));
trans = glm::scale(trans, glm::vec3(0.5f, 0.5f, 0.5f));
//应用
ourShader.setMat4("transform", trans);
// get matrix's uniform location and set matrix
ourShader.use();
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
ourShader.setMat4("transform", trans);
// 第二个案例
// get matrix's uniform location and set matrix
ourShader.use();
trans = glm::mat4(1.0f);
trans = glm::translate(trans, glm::vec3(0.3f));
trans = glm::scale(trans, glm::vec3(0.5f, 0.5f, 0.5f));
ourShader.setMat4("transform", trans);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(window);
glfwPollEvents();
}
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
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);
}
}
源代码
学习资料分享