美文网首页
LearnOpenGL 变换

LearnOpenGL 变换

作者: li_礼光 | 来源:发表于2020-09-23 00:43 被阅读0次

变化的矩阵原理参照: 变换-LearnOpenGL CN


基础变换 : 缩放, 旋转, 平移


GLM

GitHub 下载 GLM. 把GLM里面的glm放入到项目中.

PS : 1 . 复制到项目中的时候不要勾选Target.
PS : 2 . 头文件导入报错的注意修改一下.

GLM

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));
旋转

相关文章

网友评论

      本文标题:LearnOpenGL 变换

      本文链接:https://www.haomeiwen.com/subject/gpnqyktx.html