GL01-09: 3D變換

本文主要講3D的變換绍弟,3D的旋轉(zhuǎn)在OpenGL擴展輔助庫中有GLM實現(xiàn)澈蚌,本文主要從理解角度毁腿,手工實現(xiàn)3D變換嵌莉,其中使用的是4元矩陣。
??1. 縮放
??2. 平移
??3. 旋轉(zhuǎn)


縮放

縮放公式

  • \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}

實現(xiàn):

- 只要直接構(gòu)造一個$4 \times 4$矩陣即可實現(xiàn)縮放筛谚。 
- 構(gòu)造方式:
    1. C/C++風格
    2. 使用glm
void transform(GLuint pid, GLfloat sx, GLfloat sy, GLfloat sz){
    /**
     * 這里使用的是專門遵循GLSL標準的數(shù)學運算庫:GLM磁玉,該庫的使用可以從上面頭文件的說明得到;
     * 官方網(wǎng)頁說明速度慢驾讲,更加詳細的說明可以參考官方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}

實現(xiàn)

void transform(GLuint pid, GLfloat sx, GLfloat sy, GLfloat sz){
    /**
     * 這里使用的是專門遵循GLSL標準的數(shù)學運算庫:GLM蚊伞,該庫的使用可以從上面頭文件的說明得到;
     * 官方網(wǎng)頁說明速度慢吮铭,更加詳細的說明可以參考官方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);
}
  • 注意:
    • 因為內(nèi)存表達的緣故时迫,所以最后一列,在表示為數(shù)組的時候是最后一行谓晌。

旋轉(zhuǎn)

旋轉(zhuǎn)公式

  1. 常見的2D平面中的旋轉(zhuǎn)公式

    • \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軸旋轉(zhuǎn)的公式

    • \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軸旋轉(zhuǎn)的公式

    • \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旋轉(zhuǎn)的公式

    • \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})旋轉(zhuǎn)的公式

    • \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}

實現(xiàn)

void transform(GLuint pid, GLfloat angle, GLfloat sx, GLfloat sy, GLfloat sz){
    /**
     * 這里使用的是專門遵循GLSL標準的數(shù)學運算庫:GLM掠拳,該庫的使用可以從上面頭文件的說明得到;
     * 官方網(wǎng)頁說明速度慢纸肉,更加詳細的說明可以參考官方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);   // 注意旋轉(zhuǎn)向量(軸)必須單位化碳想,否會引起縮放效果
    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的向量與矩陣都是結(jié)構(gòu)體,具備結(jié)構(gòu)體的知識毁靶,結(jié)合.h文件胧奔,不使用API幫助都可以調(diào)用。

    • 需要注意的是使用下標訪問预吆,訪問的是列(這也是內(nèi)存的結(jié)構(gòu)表示的問題)
  • 下面是一個簡答的入門例子

// https://github.com/g-truc/glm
/*
下載后直接拷貝到系統(tǒng)的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對象的內(nèi)存地址

    for(int i = 0; i < 16; i++){   // 使用指針訪問數(shù)據(jù)
        printf("%f\t", m[I]);
        if((i+ 1)%4==0){
            printf("\n");
        }
    }
    printf("\n=================\n");

    glm::vec4 c= trans[3];          // 使用glm對象訪問數(shù)據(jù)
    printf("%f,%f,%f,%f\n", c.x, c.y, c.z,c.w);
    
    return 0;
}

// g++ glm01_mat.cpp  -omain


完整代碼結(jié)構(gòu)

  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封裝實現(xiàn)
#include "common.h"

// 上下文初始化
GLFWwindow* initContext(){
    if(!glfwInit()){
        printf("GLFW初始化失斄睢!\n");
        return NULL;
    }
    // 設(shè)置提示
    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("創(chuàng)建窗體失敼詹妗岩遗!\n");
        return NULL;
    }
    // 設(shè)置當前調(diào)用線程的上下文為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. 主體結(jié)構(gòu)實現(xiàn)
#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();        // 數(shù)據(jù)準備
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);           // 關(guān)閉頂點分組
    GLuint programmID = yqShader();
    GLuint textureID[2];
    yqTexture(textureID);
    /**
     * 需要把紋理對象傳遞給Shader處理
     */
    // 獲取Shader中的sTexture對象
    // 激活Shader程序
    glUseProgram(programmID); // 已經(jīng)激活,就無需再激活
    // 獲取Shader程序中
    GLint location = glGetUniformLocation(programmID, "sTexture");
    glUniform1i(location, 0);  // 設(shè)置紋理對象為索引為0蔬芥,
    // 紋理也是與頂點類似梆靖,使用所用管理控汉,紋理與頂點的管理采用16個單元完成,使用都需要激活
    // 頂點激活:glVertexAttribPointer
    // 紋理激活:glActiveTexture
    GLint location_2 = glGetUniformLocation(programmID, "sTexture_2");
    glUniform1i(location_2, 1);  // 設(shè)置紋理對象為索引為0返吻,
    
    glUseProgram(0); // 關(guān)閉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(){
    // 頂點屬性數(shù)組
    GLuint arrayID;
    glGenVertexArrays(1, &arrayID); 
    glBindVertexArray(arrayID);  
    
    // 數(shù)據(jù)(頂點坐標 + 紋理坐標)
    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   
    };
    // 數(shù)據(jù)緩沖
    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); 

    // 關(guān)閉頂點分組的操作
    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);   // 拷貝索引數(shù)據(jù)
    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]){
    // 創(chuàng)建一個紋理ID
    glGenTextures(1, textureID);
    // 綁定紋理ID到紋理的管理數(shù)據(jù)
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, textureID[0]);   //指定內(nèi)存的紋理類型
    
    // 使用第三方庫加載圖像
    int width, height, depth;
    unsigned char *data = stbi_load("texture.png", &width, &height, &depth, 0);
    printf("圖像大小:(%d,%d,%d)\n", width, height, depth);
    // 設(shè)置紋理使用的圖像數(shù)據(jù)
    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到紋理的管理數(shù)據(jù)
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, textureID[1]);   //指定內(nèi)存的紋理類型
    
    // 使用第三方庫加載圖像
    data = stbi_load("arrow.jpeg", &width, &height, &depth, 0);
    printf("圖像大小:(%d,%d,%d)\n", width, height, depth);
    // 設(shè)置紋理使用的圖像數(shù)據(jù)
    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標準的數(shù)學運算庫:GLM,該庫的使用可以從上面頭文件的說明得到榨婆;
     * 官方網(wǎng)頁說明速度慢磁携,更加詳細的說明可以參考官方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旋轉(zhuǎn)運行效果

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市纲辽,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌璃搜,老刑警劉巖拖吼,帶你破解...
    沈念sama閱讀 216,919評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異这吻,居然都是意外死亡吊档,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評論 3 392
  • 文/潘曉璐 我一進店門唾糯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來怠硼,“玉大人,你說我怎么就攤上這事移怯∠懔В” “怎么了?”我有些...
    開封第一講書人閱讀 163,316評論 0 353
  • 文/不壞的土叔 我叫張陵舟误,是天一觀的道長葡秒。 經(jīng)常有香客問我,道長嵌溢,這世上最難降的妖魔是什么眯牧? 我笑而不...
    開封第一講書人閱讀 58,294評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮赖草,結(jié)果婚禮上学少,老公的妹妹穿的比我還像新娘。我一直安慰自己秧骑,他們只是感情好版确,可當我...
    茶點故事閱讀 67,318評論 6 390
  • 文/花漫 我一把揭開白布扣囊。 她就那樣靜靜地躺著,像睡著了一般阀坏。 火紅的嫁衣襯著肌膚如雪如暖。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,245評論 1 299
  • 那天忌堂,我揣著相機與錄音盒至,去河邊找鬼。 笑死士修,一個胖子當著我的面吹牛枷遂,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播棋嘲,決...
    沈念sama閱讀 40,120評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼酒唉,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了沸移?” 一聲冷哼從身側(cè)響起痪伦,我...
    開封第一講書人閱讀 38,964評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎雹锣,沒想到半個月后网沾,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,376評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡蕊爵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,592評論 2 333
  • 正文 我和宋清朗相戀三年辉哥,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片攒射。...
    茶點故事閱讀 39,764評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡醋旦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出会放,到底是詐尸還是另有隱情饲齐,我是刑警寧澤,帶...
    沈念sama閱讀 35,460評論 5 344
  • 正文 年R本政府宣布咧最,位于F島的核電站箩张,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏窗市。R本人自食惡果不足惜先慷,卻給世界環(huán)境...
    茶點故事閱讀 41,070評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望咨察。 院中可真熱鬧论熙,春花似錦、人聲如沸摄狱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至祝谚,卻和暖如春宪迟,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背交惯。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評論 1 269
  • 我被黑心中介騙來泰國打工次泽, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人席爽。 一個月前我還...
    沈念sama閱讀 47,819評論 2 370
  • 正文 我出身青樓意荤,卻偏偏與公主長得像,于是被迫代替她去往敵國和親只锻。 傳聞我的和親對象是個殘疾皇子玖像,可洞房花燭夜當晚...
    茶點故事閱讀 44,665評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 變換(Transformations) 我們可以嘗試著在每一幀改變物體的頂點并且重設(shè)緩沖區(qū)從而使他們移動,但這太繁...
    IceMJ閱讀 4,122評論 0 1
  • 版本記錄 前言 OpenGL 圖形庫項目中一直也沒用過齐饮,最近也想學著使用這個圖形庫捐寥,感覺還是很有意思,也就自然想著...
    刀客傳奇閱讀 5,154評論 0 3
  • OpenGL本身沒有攝像機的概念祖驱,但我們可以通過把場景中的所有物體往相反方向移動的方式來模擬出攝像機握恳,這樣感覺就像...
    IceMJ閱讀 2,492評論 0 7
  • 引言 請不要質(zhì)疑你的眼睛,文章的題目就是“3D圖形學基礎(chǔ)理論”羹膳∷ィ可能有人要疑惑了根竿,作為一個 iOS 開發(fā)者為什么要...
    ZhengYaWei閱讀 8,576評論 5 36
  • today擴展是啥就不說了陵像,直接開始記錄怎么給自己的app添加擴展,免得自己忘記了 首先是appID 的準備進入開...
    爆炸的白菜君閱讀 274評論 0 0