GL01-09: 3D变换

本文主要讲3D的变换,3D的旋转在OpenGL扩展辅助库中有GLM实现,本文主要从理解角度,手工实现3D变换,其中使用的是4元矩阵。
  1. 缩放
  2. 平移
  3. 旋转


缩放

缩放公式

  • \begin{bmatrix} \color{red}{S_1} & \color{red}0 & \color{red}0 & \color{red}0 \\ \color{green}0 & \color{green}{S_2} & \color{green}0 & \color{green}0 \\ \color{blue}0 & \color{blue}0 & \color{blue}{S_3} & \color{blue}0 \\ \color{purple}0 & \color{purple}0 & \color{purple}0 & \color{purple}1 \end{bmatrix} \cdot \begin{pmatrix} x \\ y \\ z \\ 1 \end{pmatrix} = \begin{pmatrix} \color{red}{S_1} \cdot x \\ \color{green}{S_2} \cdot y \\ \color{blue}{S_3} \cdot z \\ 1 \end{pmatrix}

实现:

- 只要直接构造一个$4 \times 4$矩阵即可实现缩放。 
- 构造方式:
    1. C/C++风格
    2. 使用glm
void transform(GLuint pid, GLfloat sx, GLfloat sy, GLfloat sz){
    /**
     * 这里使用的是专门遵循GLSL标准的数学运算库:GLM,该库的使用可以从上面头文件的说明得到;
     * 官方网页说明速度慢,更加详细的说明可以参考官方github文档:https://github.com/g-truc/glm/blob/master/manual.md
     */
    // glm::mat4 trans = glm::mat4(1.0f);
    // trans = glm::scale(trans, glm::vec3(0.5, 0.5, 0.5)); 

    GLfloat scale[] ={
          sx, 0.0f, 0.0f, 0.0f,
        0.0f,   sy, 0.0f, 0.0f,
        0.0f, 0.0f,   sz, 0.0f,
        0.0f, 0.0f, 0.0f, 1.0f
    };
    unsigned int transformLoc = glGetUniformLocation(pid, "transform");
    // glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans));
    glUniformMatrix4fv(transformLoc, 1, GL_FALSE, scale);
}
  1. C/C++风格
 GLfloat scale[] ={
          sx, 0.0f, 0.0f, 0.0f,
        0.0f,   sy, 0.0f, 0.0f,
        0.0f, 0.0f,   sz, 0.0f,
        0.0f, 0.0f, 0.0f, 1.0f
    };
    unsigned int transformLoc = glGetUniformLocation(pid, "transform");
    glUniformMatrix4fv(transformLoc, 1, GL_FALSE, scale);
  1. glm风格
    glm::mat4 trans = glm::mat4(1.0f);
    trans = glm::scale(trans, glm::vec3(0.5, 0.5, 0.5)); 

    unsigned int transformLoc = glGetUniformLocation(pid, "transform");
    glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans));

平移

平移公式

  • \begin{bmatrix} \color{red}1 & \color{red}0 & \color{red}0 & \color{red}{T_x} \\ \color{green}0 & \color{green}1 & \color{green}0 & \color{green}{T_y} \\ \color{blue}0 & \color{blue}0 & \color{blue}1 & \color{blue}{T_z} \\ \color{purple}0 & \color{purple}0 & \color{purple}0 & \color{purple}1 \end{bmatrix} \cdot \begin{pmatrix} x \\ y \\ z \\ 1 \end{pmatrix} = \begin{pmatrix} x + \color{red}{T_x} \\ y + \color{green}{T_y} \\ z + \color{blue}{T_z} \\ 1 \end{pmatrix}

实现

void transform(GLuint pid, GLfloat sx, GLfloat sy, GLfloat sz){
    /**
     * 这里使用的是专门遵循GLSL标准的数学运算库:GLM,该库的使用可以从上面头文件的说明得到;
     * 官方网页说明速度慢,更加详细的说明可以参考官方github文档:https://github.com/g-truc/glm/blob/master/manual.md
     */
    // glm::mat4 trans = glm::mat4(1.0f);
    // trans = glm::translate(trans, glm::vec3(sx, sy, sz));

    GLfloat translate[] ={
        1.0f, 0.0f, 0.0f, 0.0f,
        0.0f, 1.0f, 0.0f, 0.0f,
        0.0f, 0.0f, 1.0f, 0.0f,
        sx,   sy,   sz, 1.0f
    };
    unsigned int transformLoc = glGetUniformLocation(pid, "transform");
    // glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans));
    glUniformMatrix4fv(transformLoc, 1, GL_FALSE, translate);
}
  • 注意:
    • 因为内存表达的缘故,所以最后一列,在表示为数组的时候是最后一行。

旋转

旋转公式

  1. 常见的2D平面中的旋转公式

    • \begin{bmatrix} \color{red}{\cos \theta} & - \color{red}{\sin \theta} \\ \color{green}{\sin \theta} & \color{green}{\cos \theta} \end{bmatrix} \cdot \begin{pmatrix} x \\ y \end{pmatrix} = \begin{pmatrix} \color{red}{\cos \theta} \cdot x - \color{red}{\sin \theta} \cdot y \\ \color{green}{\sin \theta} \cdot x + \color{green}{\cos \theta} \cdot y \end{pmatrix}
  2. 3D中按照z轴旋转的公式

    • \begin{bmatrix} \color{red}{\cos \theta} & - \color{red}{\sin \theta} & \color{red}0 & \color{red}0 \\ \color{green}{\sin \theta} & \color{green}{\cos \theta} & \color{green}0 & \color{green}0 \\ \color{blue}0 & \color{blue}0 & \color{blue}1 & \color{blue}0 \\ \color{purple}0 & \color{purple}0 & \color{purple}0 & \color{purple}1 \end{bmatrix} \cdot \begin{pmatrix} x \\ y \\ z \\ 1 \end{pmatrix} = \begin{pmatrix} \color{red}{\cos \theta} \cdot x - \color{red}{\sin \theta} \cdot y \\ \color{green}{\sin \theta} \cdot x + \color{green}{\cos \theta} \cdot y \\ z \\ 1 \end{pmatrix}
  3. 3D中按照x轴旋转的公式

    • \begin{bmatrix} \color{red}1 & \color{red}0 & \color{red}0 & \color{red}0 \\ \color{green}0 & \color{green}{\cos \theta} & - \color{green}{\sin \theta} & \color{green}0 \\ \color{blue}0 & \color{blue}{\sin \theta} & \color{blue}{\cos \theta} & \color{blue}0 \\ \color{purple}0 & \color{purple}0 & \color{purple}0 & \color{purple}1 \end{bmatrix} \cdot \begin{pmatrix} x \\ y \\ z \\ 1 \end{pmatrix} = \begin{pmatrix} x \\ \color{green}{\cos \theta} \cdot y - \color{green}{\sin \theta} \cdot z \\ \color{blue}{\sin \theta} \cdot y + \color{blue}{\cos \theta} \cdot z \\ 1 \end{pmatrix}
  4. 3D中按照y旋转的公式

    • \begin{bmatrix} \color{red}{\cos \theta} & \color{red}0 & \color{red}{\sin \theta} & \color{red}0 \\ \color{green}0 & \color{green}1 & \color{green}0 & \color{green}0 \\ - \color{blue}{\sin \theta} & \color{blue}0 & \color{blue}{\cos \theta} & \color{blue}0 \\ \color{purple}0 & \color{purple}0 & \color{purple}0 & \color{purple}1 \end{bmatrix} \cdot \begin{pmatrix} x \\ y \\ z \\ 1 \end{pmatrix} = \begin{pmatrix} \color{red}{\cos \theta} \cdot x + \color{red}{\sin \theta} \cdot z \\ y \\ - \color{blue}{\sin \theta} \cdot x + \color{blue}{\cos \theta} \cdot z \\ 1 \end{pmatrix}
  5. 3D中按照指定向量(\color{red}{R_x}, \color{green}{R_y}, \color{blue}{R_z})旋转的公式

    • \begin{bmatrix} \cos \theta + \color{red}{R_x}^2(1 - \cos \theta) & \color{red}{R_x}\color{green}{R_y}(1 - \cos \theta) - \color{blue}{R_z} \sin \theta & \color{red}{R_x}\color{blue}{R_z}(1 - \cos \theta) + \color{green}{R_y} \sin \theta & 0 \\ \color{green}{R_y}\color{red}{R_x} (1 - \cos \theta) + \color{blue}{R_z} \sin \theta & \cos \theta + \color{green}{R_y}^2(1 - \cos \theta) & \color{green}{R_y}\color{blue}{R_z}(1 - \cos \theta) - \color{red}{R_x} \sin \theta & 0 \\ \color{blue}{R_z}\color{red}{R_x}(1 - \cos \theta) - \color{green}{R_y} \sin \theta & \color{blue}{R_z}\color{green}{R_y}(1 - \cos \theta) + \color{red}{R_x} \sin \theta & \cos \theta + \color{blue}{R_z}^2(1 - \cos \theta) & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}

实现

void transform(GLuint pid, GLfloat angle, GLfloat sx, GLfloat sy, GLfloat sz){
    /**
     * 这里使用的是专门遵循GLSL标准的数学运算库:GLM,该库的使用可以从上面头文件的说明得到;
     * 官方网页说明速度慢,更加详细的说明可以参考官方github文档:https://github.com/g-truc/glm/blob/master/manual.md
     */
    glm::mat4 trans = glm::mat4(1.0f);
    trans = glm::rotate(trans, glm::radians(angle), glm::vec3(sx, sy, sz));
    
    GLfloat r_sin = sinf(angle * (3.14159f / 180.0f));
    GLfloat r_cos = cosf(angle * (3.14159f / 180.0f));
    GLfloat dis = sqrt(sx * sx + sy * sy + sz * sz);   // 注意旋转向量(轴)必须单位化,否会引起缩放效果
    sx /= dis;
    sy /= dis;
    sz /= dis;

    GLfloat rotate[] ={
        sx*sx*(1-r_cos)+r_cos,       sy*sx*(1-r_cos)+sz*r_sin,       sz*sx*(1-r_cos)-sy*r_sin,        0.0f,
        sx*sy*(1-r_cos)-sz*r_sin,    sy*sy*(1-r_cos)+r_cos,           sz*sy*(1-r_cos)+sx*r_sin,       0.0f,
        sx*sz*(1-r_cos)+sy*r_sin,    sy*sz*(1-r_cos)-sx*r_sin,       sz*sz*(1-r_cos)+r_cos,           0.0f,
        0.0f,                                 0.0f ,                                   0.0f,                                    1.0f
    };

    unsigned int transformLoc = glGetUniformLocation(pid, "transform");
    glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans));
    // glUniformMatrix4fv(transformLoc, 1, GL_FALSE, rotate);
}

GLM使用

  • GLM的向量与矩阵都是结构体,具备结构体的知识,结合.h文件,不使用API帮助都可以调用。

    • 需要注意的是使用下标访问,访问的是列(这也是内存的结构表示的问题)
  • 下面是一个简答的入门例子

// https://github.com/g-truc/glm
/*
下载后直接拷贝到系统的include目录使用即可
*/
#include <stdio.h>
#include <stdlib.h>
#include <glm/vec3.hpp> // glm::vec3
#include <glm/vec4.hpp> // glm::vec4
#include <glm/mat4x4.hpp> // glm::mat4
#include <glm/ext/matrix_transform.hpp> // glm::translate, glm::rotate, glm::scale
#include <glm/ext/matrix_clip_space.hpp> // glm::perspective
#include <glm/ext/scalar_constants.hpp>  // glm::pi
#include <glm/gtc/type_ptr.hpp>

int main(int argc, char const *argv[])
{
    /* code */
    glm::vec4 vec(1.0f, 0.0f, 0.0f, 1.0f);  // 向量
    glm::mat4 trans = glm::mat4(1.0f);      // 矩阵
    trans = glm::scale(trans, glm::vec3(0.5, 0.5, 0.5)); 
    // vec = trans * vec; 
    float *m = glm::value_ptr(trans);       // 返回glm对象的内存地址

    for(int i = 0; i < 16; i++){   // 使用指针访问数据
        printf("%f\t", m[I]);
        if((i+ 1)%4==0){
            printf("\n");
        }
    }
    printf("\n=================\n");

    glm::vec4 c= trans[3];          // 使用glm对象访问数据
    printf("%f,%f,%f,%f\n", c.x, c.y, c.z,c.w);
    
    return 0;
}

// g++ glm01_mat.cpp  -omain


完整代码结构

  1. 公用glfw封装头文件
#ifndef COMMON_H

#define COMMON_H
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>

GLFWwindow* initContext();  // 上下文初始化
void destroyConext();
GLboolean initOpenGL();     // OpenGL初始化与加载
////////////////////////////////

#endif
  1. 公用glfw封装实现
#include "common.h"

// 上下文初始化
GLFWwindow* initContext(){
    if(!glfwInit()){
        printf("GLFW初始化失败!\n");
        return NULL;
    }
    // 设置提示
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
    GLFWwindow* win = glfwCreateWindow(600,400, "OpenGL着色器", NULL, NULL);
    if(! win){
        printf("创建窗体失败!\n");
        return NULL;
    }
    // 设置当前调用线程的上下文为win;
    glfwMakeContextCurrent(win);
    return win;
}
void destroyConext(){
    glfwTerminate();
}
// OpenGL初始化与加载
GLboolean initOpenGL(){
    if(glewInit() != GLEW_OK){   // GLEW_OK:#define GLEW_OK 0
        printf("OpenGL加载失败!\n");
        return GL_FALSE;
    }
    return GL_TRUE;
}
  1. 主体结构实现
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include "common.h"

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#include <glm/vec3.hpp> // glm::vec3
#include <glm/vec4.hpp> // glm::vec4
#include <glm/mat4x4.hpp> // glm::mat4
#include <glm/ext/matrix_transform.hpp> // glm::translate, glm::rotate, glm::scale
#include <glm/ext/matrix_clip_space.hpp> // glm::perspective
#include <glm/ext/scalar_constants.hpp>  // glm::pi
#include <glm/gtc/type_ptr.hpp>

GLuint yqData();        // 数据准备
GLuint yqIndecies();    // 索引
void yqTexture(GLuint textureID[2]);     // 纹理

GLuint yqShader();      // GLSL
void transform(GLuint pid, GLfloat angle, GLfloat sx, GLfloat sy, GLfloat sz);    // 变换

int main(int argc, char const *argv[]){
    GLFWwindow *win = initContext(); 
    if(!win){
        return -1;
    }
    if(!initOpenGL()){
        destroyConext();
        return -1;
    }
    GLuint arrayID = yqData();
    glBindVertexArray(arrayID);     // 必须开启顶点分组
    GLuint indeciesID = yqIndecies();
    glBindVertexArray(0);           // 关闭顶点分组
    GLuint programmID = yqShader();
    GLuint textureID[2];
    yqTexture(textureID);
    /**
     * 需要把纹理对象传递给Shader处理
     */
    // 获取Shader中的sTexture对象
    // 激活Shader程序
    glUseProgram(programmID); // 已经激活,就无需再激活
    // 获取Shader程序中
    GLint location = glGetUniformLocation(programmID, "sTexture");
    glUniform1i(location, 0);  // 设置纹理对象为索引为0,
    // 纹理也是与顶点类似,使用所用管理,纹理与顶点的管理采用16个单元完成,使用都需要激活
    // 顶点激活:glVertexAttribPointer
    // 纹理激活:glActiveTexture
    GLint location_2 = glGetUniformLocation(programmID, "sTexture_2");
    glUniform1i(location_2, 1);  // 设置纹理对象为索引为0,
    
    glUseProgram(0); // 关闭Shader程序

    GLdouble oldTime = glfwGetTime();
    GLfloat angle = 0.0f;
    while(!glfwWindowShouldClose(win)){
        if(glfwGetTime() - oldTime > 0.1){
            glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
            glClear(GL_COLOR_BUFFER_BIT);
            glBindVertexArray(arrayID);     // 绑定顶点分组
            glUseProgram(programmID);       // 使用Shader
            transform(programmID, angle, 1.0f, 1.0f, 1.0f); 
            
            angle -= 1.0f;

            glDrawElements(GL_TRIANGLES, 12, GL_UNSIGNED_INT, 0);
            glUseProgram(0);                // 解除使用Shader
            glBindVertexArray(0);           // 接触顶点分组
            glfwSwapBuffers(win);
            oldTime = glfwGetTime();
        }
        // glfwWaitEvents();
        glfwPollEvents();
    }
    destroyConext();
    return 0;
}
GLuint yqData(){
    // 顶点属性数组
    GLuint arrayID;
    glGenVertexArrays(1, &arrayID); 
    glBindVertexArray(arrayID);  
    
    // 数据(顶点坐标 + 纹理坐标)
    GLfloat  vertices[] = {    // 纹理坐标按照(0,0) - (1,1)之间的4个点确定
         0.0f,  0.8f,  0.0f,     0.5f, 1.0f,   1.0f, 1.0f, 1.0f, 1.0f,
        -0.5f,  0.0f,  0.0f,     0.0f, 0.0f,   1.0f, 1.0f, 1.0f, 1.0f,
         0.5f,  0.0f,  0.0f,     1.0f, 0.0f,   1.0f, 1.0f, 1.0f, 1.0f,
        -0.3f, -0.5f,  0.5f,     1.0f, 1.0f,   1.0f, 1.0f, 1.0f, 1.0f   
    };
    // 数据缓冲
    GLuint bufferID;
    glGenBuffers(1, &bufferID);
    glBindBuffer(GL_ARRAY_BUFFER, bufferID);
    glBufferData(GL_ARRAY_BUFFER,sizeof(vertices), vertices, GL_STATIC_DRAW);

    // 顶点属性
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(GLfloat), NULL);  
    glEnableVertexAttribArray(0);  
    // 文理属性
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 9 * sizeof(GLfloat), (const void *)(3 * sizeof(GLfloat)));  // 顶点属性(输入):注意location=3,对应的顶点索引也是3
    glEnableVertexAttribArray(1); 
    // 颜色索引
    glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 9 * sizeof(GLfloat), (const void *)(5 * sizeof(GLfloat)));  // 顶点属性(输入):注意location=3,对应的顶点索引也是3
    glEnableVertexAttribArray(2); 

    // 关闭顶点分组的操作
    glBindVertexArray(0); // 要使用再切换回来
    return arrayID;
}

GLuint yqIndecies(){
    unsigned int indices[] = { // 注意绘制的顺序
        0, 1, 2,  
        0, 1, 3, 
        1, 2, 3,
        0, 2, 3
    };
    GLuint indexID;
    glGenBuffers(1, &indexID);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexID);  // 指定索引缓冲的类型
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);   // 拷贝索引数据
    return  indexID;
}

GLuint yqShader(){    
    // 纹理坐标的传递,纹理坐标的使用
    const char *vertexShaderSource = ""
        "#version 410 core\n" 
        "layout (location = 0) in vec3 aPos;\n"         // 顶点坐标
        "layout (location = 1) in vec2 aTexture;\n"     // 纹理坐标
        "layout (location = 2) in vec4 aColor;\n"     // 颜色坐标
        "out vec2 vTexture;\n"         // 传递纹理坐标到片着色器
        "out vec4 vColor;\n"         // 传递颜色坐标到片着色器
        "uniform mat4 transform;\n"
        "void main(){\n" 
        "   gl_Position = transform * vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
        "   vTexture = aTexture;\n"     // 输出到下一个着色器
        "   vColor = aColor;\n"     // 输出到下一个着色器
        "}\0";   // 空字符

    const char *fragmentShaderSource = ""
        "#version 410 core\n"
        "out vec4 FragColor;\n" 
        "in vec2 vTexture;\n"               // 上面顶点着色器传递过来的纹理坐标,用来生成采样
        "in vec4 vColor;\n"               // 上面顶点着色器传递过来的纹理坐标,用来生成采样
        "uniform sampler2D sTexture;\n"
        "uniform sampler2D sTexture_2;\n"
        "void main(){\n"
        "   FragColor = mix(texture(sTexture, vTexture), texture(sTexture_2, vTexture), 0.2) * vColor;\n"   // 采样
        "}\n\0";
    unsigned int vertexShader;
    vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);  

    unsigned int fragmentShader;
    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader);

    unsigned int shaderProgram;
    shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);

    // glUseProgram(shaderProgram);

    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);
    return shaderProgram;
}

void yqTexture(GLuint textureID[2]){
    // 创建一个纹理ID
    glGenTextures(1, textureID);
    // 绑定纹理ID到纹理的管理数据
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, textureID[0]);   //指定内存的纹理类型
    
    // 使用第三方库加载图像
    int width, height, depth;
    unsigned char *data = stbi_load("texture.png", &width, &height, &depth, 0);
    printf("图像大小:(%d,%d,%d)\n", width, height, depth);
    // 设置纹理使用的图像数据
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
    glGenerateMipmap(GL_TEXTURE_2D);  // 生成类型为2D的纹理映射
    // 释放图像
    stbi_image_free(data);

    //////////////////////////////////////////////////
    // 绑定纹理ID到纹理的管理数据
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, textureID[1]);   //指定内存的纹理类型
    
    // 使用第三方库加载图像
    data = stbi_load("arrow.jpeg", &width, &height, &depth, 0);
    printf("图像大小:(%d,%d,%d)\n", width, height, depth);
    // 设置纹理使用的图像数据
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
    glGenerateMipmap(GL_TEXTURE_2D);  // 生成类型为2D的纹理映射
    // 释放图像
    stbi_image_free(data);
}


void transform(GLuint pid, GLfloat angle, GLfloat sx, GLfloat sy, GLfloat sz){
    /**
     * 这里使用的是专门遵循GLSL标准的数学运算库:GLM,该库的使用可以从上面头文件的说明得到;
     * 官方网页说明速度慢,更加详细的说明可以参考官方github文档:https://github.com/g-truc/glm/blob/master/manual.md
     */
    glm::mat4 trans = glm::mat4(1.0f);
    trans = glm::rotate(trans, glm::radians(angle), glm::vec3(sx, sy, sz));
    GLfloat r_sin = sinf(angle * (3.14159f / 180.0f));
    GLfloat r_cos = cosf(angle * (3.14159f / 180.0f));
    GLfloat dis = sqrt(sx * sx + sy * sy + sz * sz);
    sx /= dis;
    sy /= dis;
    sz /= dis;

    GLfloat rotate[] ={
        sx*sx*(1 - r_cos) + r_cos,         sy*sx*(1 - r_cos) + sz * r_sin,    sz*sx*(1 - r_cos) - sy * r_sin,   0.0f,
        sx*sy*(1 - r_cos) - sz * r_sin,    sy*sy*(1 - r_cos) + r_cos,         sz*sy*(1 - r_cos) + sx * r_sin,   0.0f,
        sx*sz*(1 - r_cos) + sy * r_sin,    sy*sz*(1 - r_cos) - sx * r_sin,   sz*sz*(1 - r_cos) + r_cos,         0.0f,
        0.0f,                                       0.0f ,                                     0.0f,                                      1.0f
    };

    unsigned int transformLoc = glGetUniformLocation(pid, "transform");
    glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans));
    // glUniformMatrix4fv(transformLoc, 1, GL_FALSE, rotate);
}
// g++ -o main gl03_rotate.cpp common.cpp -l glfw -l glew -framework opengl

  1. 效果


    3D旋转运行效果

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 变换(Transformations) 我们可以尝试着在每一帧改变物体的顶点并且重设缓冲区从而使他们移动,但这太繁...
    IceMJ阅读 4,224评论 0 1
  • 版本记录 前言 OpenGL 图形库项目中一直也没用过,最近也想学着使用这个图形库,感觉还是很有意思,也就自然想着...
    刀客传奇阅读 5,304评论 0 3
  • OpenGL本身没有摄像机的概念,但我们可以通过把场景中的所有物体往相反方向移动的方式来模拟出摄像机,这样感觉就像...
    IceMJ阅读 2,591评论 0 7
  • 引言 请不要质疑你的眼睛,文章的题目就是“3D图形学基础理论”。可能有人要疑惑了,作为一个 iOS 开发者为什么要...
    ZhengYaWei阅读 8,704评论 5 36
  • today扩展是啥就不说了,直接开始记录怎么给自己的app添加扩展,免得自己忘记了 首先是appID 的准备进入开...
    爆炸的白菜君阅读 288评论 0 0