变化的矩阵原理参照: 变换-LearnOpenGL CN
基础变换 : 缩放, 旋转, 平移
GLM
GitHub 下载 GLM. 把GLM里面的glm放入到项目中.
PS : 1 . 复制到项目中的时候不要勾选Target.
PS : 2 . 头文件导入报错的注意修改一下.
GLM常用的数据类型
- vec2 二维向量
- vec3 三维向量
- vec4 四维向量
- mat2 二阶矩阵
- mat3 三阶矩阵
- mat4 四阶矩阵
常用的函数
- glm::radians() 角度制转弧度制
- glm::translate() 创建一个平移矩阵,第一个参数是目标矩阵,第二个参数是平移的方向向量
- glm::rotate() 创建一个将点绕某个轴旋转x弧度的旋转矩阵,第一个参数是弧度,第二个参数是旋转轴
- glm::scale() 创建一个缩放矩阵,第一个参数是目标矩阵,第二个参数是缩放系数
创建裁剪矩阵的函数,位于glm/ext/matrix_clip_space.hpp,这个文件存放裁剪空间相关的API
-
glm::ortho(float left, float right, float bottom, float top, float zNear, float zFar); 前两个参数指定了平截头体的左右坐标,第三和第四参数指定了平截头体的底部和顶部。通过这四个参数我们定义了近平面和远平面的大小,然后第五和第六个参数则定义了近平面和远平面的距离。
-
glm::perspective(float fovy, float aspect, float zNear, float zFar); 第一个参数为视锥上下面之间的夹角,第二个参数为宽高比,即视窗的宽/高,第三第四个参数分别为近截面和远界面的深度
其实上面提到的大多数函数基本都是模板函数,只不过我们平时习惯用float的特化,为了测试GLM库,可以试一下简单的对一个点进行位移的操作
用法
头文件
#include "glm.hpp"
#include "matrix_transform.hpp"
创建一个vec4向量
glm::vec4 v4 = glm::vec4(1.0f, 0.0f, 0.0f, 1.0f);//创建一个vec4
printf("x : %.1f, y : %.1f, z : %.1f, w : %.1f", v4.x, v4.y, v4.z, v4.w); //向量的w分量也叫齐次坐标
创建一个mat4*4的单位矩阵
glm::mat4 trans = glm::mat4(1.0f);//创建单位矩阵
for (int i = 0; i<4; i++) {
for (int j = 0; j<4; j++) {
printf("%.1f, ",trans[i][j]);
}
printf("\n");
}
打印结果 :
x : 1.0, y : 0.0, z : 0.0, w : 1.0
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0,
矩阵的变换 : 缩放, 旋转, 平移
单位矩阵
glm::mat4 trans = glm::mat4(1.0f);//创建单位矩阵
缩放
trans = glm::scale(trans, glm::vec3(1.5f , 1.5f, 1.5f));
旋转
trans = glm::rotate(trans, glm::radians(90.0f) , glm::vec3(1.5f , 1.5f, 1.5f));
平移
trans = glm::translate(trans, glm::vec3(1.5f , 1.5f, 1.5f));
结合到Demo中.
shader
#ifndef TransformShader_h
#define TransformShader_h
#define STRINGIZE(x) #x
#define SHADER(shader) STRINGIZE(shader)
/// 着色器程序之间的数据传递
static char *myTransformVertexShaderStr = SHADER(
\#version 330 core\n
layout (location = 0) in vec3 position; //顶点数据源输入
layout (location = 1) in vec3 color; //颜色数据源输入
out vec4 vertexColor;//把片元着色器的颜色从这里输出
uniform mat4 myTransform;//变换
void main()
{
gl_Position = myTransform * vec4(position, 1.0f);
vertexColor = vec4(color, 1.0f); //输出给片元着色器
}
);
//片元着色器程序
static char *myTransformFragmentShaderSrc = SHADER(
\#version 330 core\n
in vec4 vertexColor;//从顶点着色器中拿color的值
out vec4 color;
void main()
{
color = vertexColor;//获取值
}
);
#endif /* TransformShader_h */
顶点数据
#ifndef TransformVertex_h
#define TransformVertex_h
#include "glad.h"
#include <GLFW/glfw3.h>
//正方形
static GLfloat myTransformVertices[] = {
-0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, //左下 红
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, //右下 绿
0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, //右上 绿
-0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, //左上 红
};
//索引
static GLint myTransformVerticesIndices[] = { // 注意索引从0开始!
0, 1, 2, // 第一个三角形
0, 3, 2 // 第二个三角形
};
#endif /* TransformVertex_h */
Demo
#include <iostream>
#include "MyTransform.hpp"
#include "MyProgram.hpp"
#include "glm.hpp"
#include "matrix_transform.hpp"
#include "type_ptr.hpp"
int runMyTransform() {
int result = glfwInit();
if (result == GL_FALSE) {
printf("glfwInit 初始化失败");
return -1;
}
//这里的宏不好提示出来, 根据LearnOpenGL的文档提示, 用这三个
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
//Mac平台需要加入
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
//创建一个Window
GLFWwindow *window = glfwCreateWindow(600, 400, "My Opengl Window", NULL, NULL);
if(!window) {
printf("window 创建失败");
}
//opengl运行模式 -- 单线程, 理解为跟当前的Window做一次绑定操作.
glfwMakeContextCurrent(window);
//任何的OpenGL接口调用都必须在初始化GLAD库后才可以正常访问。如果成功的话,该接口将返回GL_TRUE,否则就会返回GL_FALSE。
gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
//----------------------------------------------------------------------
//先创建我们的Program对象, 加载顶点着色器程序和片元着色器程序
MyProgram myProgram = MyProgram(myTransformVertexShaderStr, myTransformFragmentShaderSrc);
GLuint VBO , VAO , EBO;
unsigned int squareIndicesCount = 0;
//创建VBO
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(myTransformVertices), myTransformVertices, GL_STATIC_DRAW);
//创建VAO
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
//创建EBO, 这里的EBO相当于索引的作用
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(myTransformVerticesIndices), myTransformVerticesIndices, GL_STATIC_DRAW);
//解绑VAO
glBindVertexArray(0);
//计算索引个数
squareIndicesCount = sizeof(myTransformVerticesIndices)/sizeof(myTransformVerticesIndices[0]);
//进行绘制
while(!glfwWindowShouldClose(window)){
//检查事件
glfwPollEvents();
//渲染指令
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(myProgram.program);
///变换处理
GLint transformLoc = glGetUniformLocation(myProgram.program,"myTransform");
//单位矩阵
glm::mat4 trans = glm::mat4(1.0f);
//缩放,旋转,平移
trans = glm::scale(trans, glm::vec3(0.5, 0.5, 0.5));
trans = glm::rotate(trans, glm::radians(45.0f), glm::vec3(0.0, 0.0, 1.0));
trans = glm::translate(trans, glm::vec3(1.0, 0.0, 0.0));
//矩阵赋值
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans));
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, squareIndicesCount, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
//交换缓冲
glfwSwapBuffers(window);
}
//程序销毁
glfwTerminate();
return 1;
}
变换前
变换前变换后
变换后在Shader中使用了 uniform mat4 myTransform , 获取myTransform的location. 用变换改变顶点数据的内容.
在变换中实现动画. 围绕着z轴旋转
trans = glm::rotate(trans,(GLfloat)glfwGetTime() * 1.0f, glm::vec3(0.0f, 0.0f, 1.0f));
旋转
网友评论