背景知識:
在這個課程中我們開始關注乙個物體在3d中的各種變換,並使它在螢幕上顯示時呈現一種縱深的錯覺。通常的做法是分別用一種矩陣表示變換,逐個相乘,用最終的式子再乘頂點位置。每節課會專門講解乙個變換。
這裡我們看一下這個平移變換,這個變換負責沿著乙個任意長和方向的向量移動物體。就說你想把三角形從左圖移到右圖吧。
其中乙個方法是提供乙個向量偏移(例如-1,1)作為統一變數給著色器然後簡單的新增到處理中的頂點。然而,這打破了一組矩陣相乘的、從而成為乙個完整變換的整體。此外,你之後會看到平移常常不是第乙個變換,可能在平移前要用點乘一堆其他變換的矩陣,加上位置,最後再乘隨後的平移變換矩陣。這是很尷尬的。乙個比較好的方法是找到另一種平移矩陣然後加入所有其他矩陣的相乘中。不過你能找到乙個矩陣,使其乘(0,0)得到(1,1)嗎?事實是你不能用乙個2d的矩陣(同樣不能用3d矩陣對(0,0,0))。通常我們會說我們需要的是乙個矩陣m,使其可以在給出點p(x,y,z)和乙個向量v(v1,v2,v3)的情況下提供m*p=p1(x + v1, y + v2, z + v3)。簡單的說這意味幀矩陣m把p平移到位置p+v。在p1我們可以看到每個分量是p和v對應分量的和。相加式子的左邊是乙個單位矩陣:i * p = p(x, y, z)。因此看起來我們應該先基於單位矩陣,再找出導致式子右邊部分(...+v1, ...+v2, ...+v3)的改變。單位矩陣看起來如下:
我們得修改單位矩陣,使結果變成這個樣子:
如果我們拘泥於3*3的矩陣,還真沒有容易的方法,可是我們可以改成4*4的矩陣,如下圖所示:
像這樣用乙個4-向量表示乙個3-向量被稱作【齊次座標】,對於3d影象非常流行和管用。第四個分量被稱為'w'。事實上,在我們之前課程中的那個著色器內部符號gl_position就是乙個4-向量而且w分量對於3d到2d的投影有著重要的作用。通常的表示方法是,對於點用w=1,對於向量用w=0。原因在於點是可以被平移的,向量卻不可以。你可以改變向量的長度或者方向,但所有有相同長度和方向的向量被認為是等價的,並不關心所謂的「開始位置」。所以對於所有的向量,你可以簡單的使用源點(譯者注:作為它們的開始位置)。把乙個平移矩陣的w設為0,用乙個向量乘這個平移矩陣,得到的還是一樣的向量。
原始碼實踐:
struct matrix4f ;
我們給math_3d.h新增了乙個4*4矩陣的定義。這從現在開始對於我們大部分的變化矩陣有很大作用。
gluint gworldlocation;
我們用這個控制代碼來訪問著色器中的統一變數世界矩陣。起名為「世界」是因為我們正在做的是把乙個物體的位置移動到我們的虛擬「世界」座標系統中。
matrix4f world;
world.m[0][0] = 1.0f; world.m[0][1] = 0.0f; world.m[0][2] = 0.0f; world.m[0][3] = sinf(scale);
world.m[1][0] = 0.0f; world.m[1][1] = 1.0f; world.m[1][2] = 0.0f; world.m[1][3] = 0.0f;
world.m[2][0] = 0.0f; world.m[2][1] = 0.0f; world.m[2][2] = 1.0f; world.m[2][3] = 0.0f;
world.m[3][0] = 0.0f; world.m[3][1] = 0.0f; world.m[3][2] = 0.0f; world.m[3][3] = 1.0f;
在渲染函式中,我們準備乙個4*4的矩陣,然後按照上面的說明填充它。我們把v2和v3設為0,因此我們期望物體在y和z軸上沒有改變,我們設v1為正弦函式的返回結果。這將會借助乙個在-1和1間波動的平滑的值來平移x座標。現在我們需要把矩陣載入如著色器。
gluniformmatrix4fv(gworldlocation, 1, gl_true, &world.m[0][0]);
這是另乙個gluniform*函式把資料載入進統一著色器變數的例子。這個特定的函式載入了4*4矩陣,當然也有2*2,3*3,3*2,2*4,4*2,3*4和4*3的版本。第乙個引數是統一變數的位置(在著色器編譯後由glgetuniformlocation()返回)。第二個引數指代我們正在更新的矩陣的數量。我們使用1代表1個矩陣,但是我們也使用這個函式在一次呼叫中去更新相乘矩陣。第三引數經常困擾著新人。它指代提供的矩陣是主行還是主列命令。主行意味著提供的矩陣是一行行的,從最上端開始。主列同理。問題是c/c++預設是主行的語言。這意味著當你用值填充乙個二維陣列時,它們被一行行地排布進記憶體,以最上端為低位址位。例如,我們看下面的陣列:
int a[2][3];
a[0][0] = 1;
a[0][1] = 2;
a[0][2] = 3;
a[1][0] = 4;
a[1][1] = 5;
a[1][2] = 6;
可以看見,陣列很像下面的矩陣:
1 2 3
4 5 6
記憶體布局像這樣1 2 3 4 5 6(1在低位址位)。
所以我們給gluniformmatrix4fv()的第三個引數是gl_true因為我們提供了主行命令的矩陣。我們也可以使第三個引數為gl_false但是我們需要反轉矩陣的值(c/c++記憶體布局保留不變,而opengl會「認為」我們提供的前4個值實際上是乙個矩陣的列以及它會根據這點去解析)。第四個引數就是簡單的矩陣的記憶體起始位址。
剩下就是著色器**了。
uniform mat4 gworld;
gl_position = gworld * vec4(position, 1.0);
在頂點緩衝中三角形的頂點位置是乙個3分量的向量,不過我們都同意了還需要第4個向量,它的值為1。有兩個方法:把4個分量的頂點放入頂點緩衝中,或者在頂點緩衝中新增第4個分量。第一種方法並沒有優勢。對於每個頂點位置,1個分量會消耗額外4bytes,可這個分量卻總是1。更有效率的做法是保留3分量的向量,然後在著色器中串聯w分量。在glsl中使用 'vec4(position, 1.0)'來完成。我們用向量乘矩陣,把結果放入gl_position中。做個總結,對於每一幀我們產生乙個平移矩陣,通過乙個在-1和1之間來回走動的值平移x座標。著色器用這個矩陣乘每個頂點的位置,造成整個物體向左或向右移動。在大多數情況下,在頂點著色器起作用後,三角形的邊會跑到標準盒子外面,接著被裁剪器剪掉外面的部分。我們僅僅能夠看到在標準盒子內部的區域。
OpenGL座標變換 平移,縮放與旋轉
opengl座標變換 平移,縮放與旋轉 opengl有內建的座標系,事實上opengl有兩套座標系,乙個座標系被稱為眼睛座標 eye coordinate system 簡稱ecs opengl還有一套座標,被稱為 object coordinate system 簡稱ocs 而這個才是更為重要的,...
Python之OpenGL筆記 8 平移變換
1 使用glsl實現圖形的平移。平移變換的任務是將乙個物件沿著乙個任意長度和方向的向量移動。對於三維空間上的一點 x,y,z 我們使用4 4齊次矩陣的形式來表示平移變換 使用四維向量來表示三維向量的做法稱作齊次座標,這對3d圖形學來說普遍而又實用。向量的第四個分量稱之為 w 事實上,我們在以前教程中...
OpenGL教程翻譯 第七課 旋轉變換
接下來的變換是旋轉,就是說給定乙個角度和點,我們將點繞著乙個座標軸旋轉。我們總是變化 三個裡面的兩個,而不讓第三部分變化。這意味著,旋轉路徑總在三個座標軸平面中的乙個之中 繞z軸的是xy面 繞x軸的是yz面 繞y軸的是xy面。還有許多複雜的旋轉轉變可以讓你繞任意乙個向量旋轉,但是眼下我們並不需要這些...