聯系我們 - 廣告服務 - 聯系電話:
您的當前位置: > 關注 > > 正文

【教程】矩陣相乘時 我們先寫位移再縮放

來源:CSDN 時間:2023-02-03 14:52:15

注意,當矩陣相乘時我們先寫位移再寫縮放變換的。建議您在組合矩陣時,先進行縮放操作,然后是旋轉,最后才是位移,否則它們會(消極地)互相影響。比如,如果你先位移再縮放,位移的向量也會同樣被縮放(譯注:比如向某方向移動2米,2米也許會被縮放成1米)!

(一)矩陣變換


(資料圖)

1、添加頭文件

我們需要的GLM的大多數功能都可以從下面這3個頭文件中找到:

#include#include#include

2、矩陣初始化

GLM庫從0.9.9版本起,默認會將矩陣類型初始化為一個零矩陣(所有元素均為0),而不是單位矩陣(對角元素為1,其它元素為0)。如果你使用的是0.9.9或0.9.9以上的版本,你需要將所有的矩陣初始化改為 glm::mat4 mat = glm::mat4(1.0f)。如果你想與本教程的代碼保持一致,請使用低于0.9.9版本的GLM,或者改用上述代碼初始化所有的矩陣。

我們來看看是否可以利用我們剛學的變換知識把一個向量(1, 0, 0)位移(1, 1, 0)個單位(注意,我們把它定義為一個glm::vec4類型的值,齊次坐標設定為1.0):

glm::vec4 vec(1.0f, 0.0f, 0.0f, 1.0f);// 譯注:下面就是矩陣初始化的一個例子,如果使用的是0.9.9及以上版本// 下面這行代碼就需要改為:// glm::mat4 trans = glm::mat4(1.0f)// 之后將不再進行提示glm::mat4 trans;

我們先用GLM內建的向量類定義一個叫做vec的向量。接下來定義一個mat4類型的trans,默認是一個4×4單位矩陣。

3、變換

我們來做些更有意思的事情,讓我們來旋轉和縮放之前教程中的那個箱子。首先我們把箱子逆時針旋轉90度。然后縮放0.5倍,使它變成原來的一半大。隨時間變化,使用GLFW的時間函數來獲取不同時間的角度

glm::mat4 trans;trans = glm::translate(trans, glm::vec3(0.5f, -0.5f, 0.0f));trans = glm::rotate(trans, (float)glfwGetTime(), glm::vec3(0.0f, 0.0f, 1.0f));

首先,我們把箱子在每個軸都縮放到0.5倍,然后沿z軸旋轉90度。GLM希望它的角度是弧度制的(Radian),所以我們使用glm::radians將角度轉化為弧度。注意有紋理的那面矩形是在XY平面上的,所以我們需要把它繞著z軸旋轉。因為我們把這個矩陣傳遞給了GLM的每個函數,GLM會自動將矩陣相乘,返回的結果是一個包括了多個變換的變換矩陣。

矩陣傳遞給著色器

我們在前面簡單提到過GLSL里也有一個mat4類型。所以我們將修改頂點著色器讓其接收一個mat4的uniform變量,然后再用矩陣uniform乘以位置向量:

#version 330 corelayout (location = 0) in vec3 aPos;layout (location = 1) in vec2 aTexCoord;out vec2 TexCoord;uniform mat4 transform;void main(){    gl_Position = transform * vec4(aPos, 1.0f);    TexCoord = vec2(aTexCoord.x, 1.0 - aTexCoord.y);}

GLSL也有mat2和mat3類型從而允許了像向量一樣的混合運算。前面提到的所有數學運算(像是標量-矩陣相乘,矩陣-向量相乘和矩陣-矩陣相乘)在矩陣類型里都可以使用。當出現特殊的矩陣運算的時候我們會特別說明。

變換矩陣傳遞給著色器:

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

我們首先查詢uniform變量的地址,然后用有Matrix4fv后綴的glUniform函數把矩陣數據發送給著色器。第一個參數你現在應該很熟悉了,它是uniform的位置值。第二個參數告訴OpenGL我們將要發送多少個矩陣,這里是1。第三個參數詢問我們我們是否希望對我們的矩陣進行置換(Transpose),也就是說交換我們矩陣的行和列。OpenGL開發者通常使用一種內部矩陣布局,叫做列主序(Column-major Ordering)布局。GLM的默認布局就是列主序,所以并不需要置換矩陣,我們填GL_FALSE。最后一個參數是真正的矩陣數據,但是GLM并不是把它們的矩陣儲存為OpenGL所希望接受的那種,因此我們要先用GLM的自帶的函數value_ptr來變換這些數據。

(二)畫出立方體

頂點坐標

float vertices[] = {-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 0.0f,0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.0f,-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 0.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 1.0f,0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f,0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f,-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 1.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 1.0f,-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 0.0f,-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 0.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 1.0f,0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.0f,0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 1.0f,0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f,-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 0.0f,0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 1.0f,0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 1.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 0.0f,-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f,0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f,-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 1.0f,-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f};

2、繪制圖元

glDrawArrays(GL_TRIANGLES, 0, 36);  //畫三角形,從第 0 個數據開始畫,到最后一個數據(第 3 個)結束//glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

3、增加深度測試

//glEnable(GL_DEPTH_TEST);  //深度測試//glDepthFunc(GL_LESS);  //深度信息小于當期信息,就把進行測試

4、在清除屏幕的時候,也需要把深度緩存的數據清除掉!

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

附加內容:畫出多個立方體

現在我們想在屏幕上顯示10個立方體。每個立方體看起來都是一樣的,區別在于它們在世界的位置及旋轉角度不同。立方體的圖形布局已經定義好了,所以當渲染更多物體的時候我們不需要改變我們的緩沖數組和屬性數組,我們唯一需要做的只是改變每個對象的模型矩陣來將立方體變換到世界坐標系中。

首先,讓我們為每個立方體定義一個位移向量來指定它在世界空間的位置。我們將在一個glm::vec3數組中定義10個立方體位置:

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)  };

現在,在游戲循環中,我們調用glDrawArrays 10次,但這次在我們渲染之前每次傳入一個不同的模型矩陣到頂點著色器中。我們將會在游戲循環中創建一個小的循環用不同的模型矩陣渲染我們的物體10次。注意我們也對每個箱子加了一點旋轉:

glBindVertexArray(VAO);for(unsigned int i = 0; i < 10; i++){  glm::mat4 model;  model = glm::translate(model, cubePositions[i]);  float angle = 20.0f * i;   model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));  ourShader.setMat4("model", model);  glDrawArrays(GL_TRIANGLES, 0, 36);}

這段代碼將會在每次新立方體繪制出來的時候更新模型矩陣,如此總共重復10次。然后我們應該就能看到一個擁有10個正在奇葩地旋轉著的立方體的世界。

責任編輯:

標簽:

相關推薦:

精彩放送:

新聞聚焦
Top 岛国精品在线