矩阵变换
Notes
- glm矩阵变换
矩阵相乘顺序 trans * scale * translate * rotate
模型作用顺序 rotate->translate->scale
glm::mat4 trans;
trans = glm::scale(trans, glm::vec3(0.5, 0.5, 0.5));
trans = glm::translate(trans, glm::vec3(1.0f, 1.0f, 0.0f));
trans = glm::rotate(trans, glm::radians(90.0f), glm::vec3(0.0, 0.0, 1.0));
const char* vertexShaderSource = "#version 400 core\n"
"layout (location = 0) in vec3 aPos;\n"
"layout (location = 1) in vec2 aTexCoord;\n"
"out vec2 TexCoord;\n"
"uniform mat4 transform;\n"
"void main()\n"
"{\n"
" gl_Position =transform * vec4(aPos.x, aPos.y, aPos.z, 1.0f);\n"
" TexCoord = aTexCoord;\n"
"}\0";
输出结果
- 坐标系统
局部坐标系相对于局部原点坐标
世界坐标系想对于世界的全局原点
观察坐标相对于相机
裁剪坐标,裁剪坐标处理至[-1,1]范围内
屏幕坐标,裁剪坐标转换为屏幕坐标
- 局部坐标系->世界坐标系(Model矩阵),cubePositions为立方体在世界坐标位置,进行平移和自旋转
model = glm::translate(model, glm::vec3(cubePositions[i]));
model = glm::rotate(model, float(glfwGetTime()), glm::vec3(1.0f, 2.0f, 0.0f));
- 世界坐标系->观察空间坐标(View矩阵),相机位置(0.0f, 0.0f, 3.0f),立方体整体沿z轴平移((0.0f, 0.0f, -3.0f))
view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));
- 观察空间坐标->裁剪空间坐标(Projection矩阵)
-
透视投影(距离越远,看到的东西更小,w可看作另一个维度,坐标范围都在[-w,w],FOV视角内)
projection = glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f);
-
正视投影(定义了一个类似立方体的平截头箱,坐标范围都在这个空间之内
glm::ortho(0.0f, 800.0f, 0.0f, 600.0f, 0.1f, 100.0f);
-
- 裁剪空间坐标->屏幕坐标(ViewportTransform矩阵)
- 将转换矩阵通过uniform的方式给到顶点着色器,计算坐标点位置
glUniformMatrix4fv(glGetUniformLocation(shader.GetShaderProgramID(), "transform"),
1, GL_FALSE, glm::value_ptr(trans));
const char* vertexShaderSource = "#version 400 core\n"
"layout (location = 0) in vec3 aPos;\n"
"layout (location = 1) in vec2 aTexCoord;\n"
"out vec2 TexCoord;\n"
"uniform mat4 transform;\n"
"void main()\n"
"{\n"
" gl_Position =transform * vec4(aPos.x, aPos.y, aPos.z, 1.0f);\n"
" TexCoord = aTexCoord;\n"
"}\0";
- 开启深度测试
OpenGL存储它的所有深度信息于一个z缓冲(Z-buffer)中,也称为深度缓冲(Depth Buffer)。深度值存储在每个片段里面(作为片段的z值),当片段想要输出它的颜色时,OpenGL会将它的深度值和Z缓冲进行比较,如果当前片段在其它片段之后,它将会被丢弃,否则将会覆盖。
每次渲染迭代之前清除深度缓冲(否则前一帧的深度信息仍然保存在缓冲中)
glEnable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
代码示例
https://gitee.com/NiMiKiss/opengl-notes.git
shader.h
#ifndef _SHADER_H_
#define _SHADER_H_
#include<glad/glad.h>
#include<GLFW/glfw3.h>
#include <iostream>
class Shader
{
public:
Shader();
~Shader();
void UseShader() const;
void InitShader();
int GetShaderProgramID() const;
private:
int m_iShaderProgramID;
};
#endif // !_SHADER_H_
shader.cpp
#include "Shader.h"
Shader::Shader()
{
}
Shader::~Shader()
{
}
void Shader::InitShader()
{
const char* vertexShaderSource = "#version 400 core\n"
"layout (location = 0) in vec3 aPos;\n"
"layout (location = 1) in vec2 aTexCoord;\n"
"out vec2 TexCoord;\n"
"uniform mat4 transform;\n"
"void main()\n"
"{\n"
" gl_Position =transform * vec4(aPos.x, aPos.y, aPos.z, 1.0f);\n"
" TexCoord = aTexCoord;\n"
"}\0";
const char* fragmentShaderSource = "#version 400 core\n"
"out vec4 FragColor;\n"
"in vec2 TexCoord;\n"
"uniform sampler2D ourTexture1;\n"
"uniform sampler2D ourTexture2;\n"
"void main()\n"
"{\n"
" FragColor = mix(texture(ourTexture1,TexCoord),texture(ourTexture2,TexCoord),0.2);\n"
"}\n\0";
int vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
m_iShaderProgramID = glCreateProgram();
glAttachShader(m_iShaderProgramID, vertexShader);
glAttachShader(m_iShaderProgramID, fragmentShader);
glLinkProgram(m_iShaderProgramID);
}
void Shader::UseShader() const
{
glUseProgram(m_iShaderProgramID);
}
int Shader::GetShaderProgramID()const
{
return m_iShaderProgramID;
}
OpenGL.cpp
#include "Shader.h"
#include "stb_image.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
Shader shader;
GLFWwindow* window;
unsigned int VAO;
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
float vertices[] = {
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 1.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f
};
glm::vec3 cubePositions[] = {
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(2.0f, 5.0f, -15.0f),
glm::vec3(-1.5f, -2.2f, -2.5f),
glm::vec3(-3.8f, -2.0f, -12.3f),
glm::vec3(2.4f, -0.4f, -3.5f),
glm::vec3(-1.7f, 3.0f, -7.5f),
glm::vec3(1.3f, -2.0f, -2.5f),
glm::vec3(1.5f, 2.0f, -2.5f),
glm::vec3(1.5f, 0.2f, -1.5f),
glm::vec3(-1.3f, 1.0f, -1.5f)
};
void Init()
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return;
}
glfwMakeContextCurrent(window);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return;
}
shader.InitShader();
}
void SetVAO()
{
unsigned int VBO, EBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
}
void Texture()
{
int width(0), height(0), nrChannels(0);
unsigned char* data;
stbi_set_flip_vertically_on_load(true);
unsigned int texture[2];
glGenTextures(2, texture);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
data = stbi_load("../OpenGL/resources/textures/container.jpg", &width, &height, &nrChannels, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
stbi_image_free(data);
glBindTexture(GL_TEXTURE_2D, texture[1]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
data = stbi_load("../OpenGL/resources/textures/awesomeface.png", &width, &height, &nrChannels, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
stbi_image_free(data);
glActiveTexture(GL_TEXTURE0); //先激活再绑定
glBindTexture(GL_TEXTURE_2D, texture[0]);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture[1]);
shader.UseShader();
glUniform1i(glGetUniformLocation(shader.GetShaderProgramID(), "ourTexture1"), 0);
glUniform1i(glGetUniformLocation(shader.GetShaderProgramID(), "ourTexture2"), 1);
}
int main()
{
Init();
SetVAO();
Texture();
glEnable(GL_DEPTH_TEST);
while (!glfwWindowShouldClose(window))
{
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
for (size_t i = 0; i < 10; ++i)
{
glm::mat4 trans(glm::mat4(1.0f)), model(glm::mat4(1.0f)), view(glm::mat4(1.0f)), projection(glm::mat4(1.0f));
model = glm::translate(model, glm::vec3(cubePositions[i]));
model = glm::rotate(model, float(glfwGetTime()), glm::vec3(1.0f, 2.0f, 0.0f));
view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));
projection = glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f);
trans = projection * view * model;
glUniformMatrix4fv(glGetUniformLocation(shader.GetShaderProgramID(), "transform"),
1, GL_FALSE, glm::value_ptr(trans));
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 36);
}
glfwSwapBuffers(window);
glfwPollEvents();
}
}
输出结果
10个旋转的立方体