目录
一、前言
二、向量
三、矩阵
四、旋转的箱子
4.1 GLM库
4.2 构建
一、前言
前面了解渲染架构中uniform可以传递矩阵变换,如从RGBA到YUV,同时它也可以使物体通过矩阵变换动起来。
二、向量
向量是包含方向和大小的矢量,平面2D坐标可以看作在3D坐标系下Z坐标为0的向量,已知起始点向终点画出一条指向性箭头。标量只是一个数字,没有方向。
向量加减:
点乘:两个向量的点乘等于它们的数乘结果乘以两个向量之间夹角的余弦值
叉乘:运算结果是一个向量,并且与这两个向量都垂直,是这两个向量所在平面的法线向量。如果输入的两个向量也是正交的,那么叉乘之后将会产生3个互相正交的向量。
使用右手定则确定其方向
三维向量叉乘:
三、矩阵
单位矩阵:除了对角线外都是0的NxN矩阵,特性是这种变换使一个向量完全不变:
缩放:
位移:
旋转:在3D空间中需要定义一个角和一个旋转轴。当2D向量在3D空间中旋转时,把旋转轴设为Z轴。
沿x轴旋转:
沿y轴旋转:
沿Z轴旋转:
四、旋转的箱子
4.1 GLM库
GLM是OpenGL Mathematics 也是头文件库,下载地址这里。GLM支持向量、矩阵、变换运算
4.2 构建
逆时针旋转90度,缩放0.5倍
glm::mat4 trans;
trans = glm::rotate(trans, glm::radians(90.0f), glm::vec3(0.0, 0.0, 1.0));
trans = glm::scale(trans, glm::vec3(0.5, 0.5, 0.5));
增加uniform变量,将旋转矩阵传入到顶点着色器中:
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;
out vec2 TexCoord;
uniform mat4 transform;
void main()
{
gl_Position = transform * vec4(aPos, 1.0f);
TexCoord = vec2(aTexCoord.x, 1.0 - aTexCoord.y);
}
将变换矩阵转化为transform变量:
unsigned int transformLoc = glGetUniformLocation(ourShader.ID, "transform");
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans));
/*
参数1:uniform位置
参数2:发送几个矩阵
参数3:是否转置 , (列排序)
参数4:矩阵数据,使用value_ptr变换数据
*/
源码:
#include <iostream>
#include <string>
#include "glad.h"
#include "GL/glfw3.h"
#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>
// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow* window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
}
// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
// make sure the viewport matches the new window dimensions; note that width and
// height will be significantly larger than specified on retina displays.
glViewport(0, 0, width, height);
}
int main()
{
// glfw: 初始化、配置
// ------------------------------
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
// glfw: 创建窗口、绑定回调
// --------------------
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
// glad: 加载OpenGL相关函数指针
// ---------------------------------------
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
// 构建、编译着色器
// ------------------------------------
Shader ourShader("vertexTexture.vs", "fragmentTexture.fms");
// 顶点数据
// ------------------------------------------------------------------
float vertices[] = {
// 位置 // 颜色 // 纹理坐标
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top right
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // top left
};
unsigned int indices[] = {
0, 1, 3, // 第一个三角形
1, 2, 3 // 第二个三角形
};
//创建顶点对象
unsigned int VAO, VBO, EBO;
glGenVertexArrays(1, &VAO);//顶点数组
glGenBuffers(1, &VBO);//数据缓存
glGenBuffers(1, &EBO);//数据缓存
//绑定数据
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);
//解释数据
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);
//创建纹理对象1
unsigned int texture1;
glGenTextures(1, &texture1);
glBindTexture(GL_TEXTURE_2D, texture1);
//设置纹理环绕方式
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_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//加载图片1到纹理数据
int width, height, nrChannels;
unsigned char* data = stbi_load(std::string("container.jpg").c_str(), &width, &height, &nrChannels, 0);
if (data)
{
//加载数据,生成OpenGL纹理图
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
//多级渐远纹理
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
std::cout << "Failed to load texture" << std::endl;
}
//释放内存
stbi_image_free(data);
//创建纹理对象2
unsigned int texture2;
// texture 2
// ---------
glGenTextures(1, &texture2);
glBindTexture(GL_TEXTURE_2D, texture2);
// set the texture wrapping parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // set texture wrapping to GL_REPEAT (default wrapping method)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// set texture filtering parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// load image, create texture and generate mipmaps
stbi_set_flip_vertically_on_load(true);
data = stbi_load(std::string("awesomeface.png").c_str(), &width, &height, &nrChannels, 0);
if (data)
{
// note that the awesomeface.png has transparency and thus an alpha channel, so make sure to tell OpenGL the data type is of GL_RGBA
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
std::cout << "Failed to load texture" << std::endl;
}
stbi_image_free(data);
//OpenGL解释纹理单元的编号
ourShader.use();
ourShader.setInt("textur1", 0);
ourShader.setInt("textur2", 1);
//旋转90度,缩放0.5倍
//glm::mat4 trans = glm::mat4(1.0f);
// trans = glm::rotate(trans, glm::radians(90.0f), glm::vec3(0, 0, 1.0));
//trans = glm::scale(trans, glm::vec3(0.5, 0.5, 0.5));
//渲染
while (!glfwWindowShouldClose(window))
{
processInput(window);
//背景颜色
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
//绑定对应的纹理
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture2);
glm::mat4 trans = glm::mat4(1.0f);
trans = glm::translate(trans, glm::vec3(0.5f, -0.5f, 0.0f));
trans = glm::rotate(trans, (float)glfwGetTime(), glm::vec3(0.0f, 0.0f, 1.0f));
//着色器引用
ourShader.use();
unsigned int transformLoc = glGetUniformLocation(ourShader.ID, "transform");
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans));
//绘图
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
/*
*
void glDrawElements( GLenum mode,
GLsizei count,
GLenum type,
const GLvoid * indices);
*/
//刷新
glfwSwapBuffers(window);
glfwPollEvents();
}
//释放缓存资源
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
//释放glfw资源
glfwTerminate();
return 0;
}