OpenGL ES 投影和坐標[轉]

1.寬高比問題

http://blog.csdn.net/liyuanjinglyj/article/details/46624901

我們現在相當熟悉這樣一個事實,在OpenGL里,我們要渲染的一切物體都要映射到X軸和Y軸上[-1,1]的范圍內,對于Z軸也一樣。這個范圍內的坐標被稱為歸一化設備坐標,其獨立于屏幕實際尺寸或形狀。

不幸的是,因為它們獨立于實際的屏幕尺寸,如果直接使用它們,我們就會遇到問題,例如在橫屏模式下被壓扁的桌子。

假設實際的設備分辨率以像素為單位是1280*720,這在新的Android設備上是一個常用的分辨率。為了使討論更加容易,讓我們也暫時假定OpenGL占用整個顯示屏。

如果設備是在豎屏模式下,那么[-1,1]的范圍對應1280像素高,卻只有720像素寬。圖像會在X軸顯得扁平,如果在橫屏模式,同樣的問題也會發生在Y軸上。

歸一化設備坐標假定坐標空間是一個正方形,如下圖所示:

然而,因為實際的視口可能不是一個正方形,圖像就會在一個方向上被拉伸,在另一個方向上被壓扁。在一個豎屏設備上,歸一化設備坐標上定義的圖像看上去就是在水平方向上被壓扁了:

在橫屏模式下,同樣的圖像就在另一個方向上看起來被壓扁的。

2.適應寬高比

我們需要調整坐標空間,以使它把屏幕的形狀考慮在內,可行的一個方法是把較小的范圍固定在[-1,1]內,而按屏幕尺寸的比例調整較大的范圍。

舉例來說,在豎屏情況下,其寬度是720,而高度是1280,因此我們可以把寬度范圍限定在[-1,1],并把高度范圍調整為[-1280/720,1280/720]或[-1.78,1.78]。同理在橫屏模式情況下,把高度范圍設為[-1.78,1.78],而把高度范圍設為[-1,1]。

通過調整已有的坐標空間,最終會改變我們可用的空間。

通過這個方法,不論是豎屏模式還是橫屏模式,物體看起來就都一樣了。

3.使用虛擬坐標空間

調整坐標空間,以便我們把屏幕方向考慮進來,我們需要停止直接在歸一化設備坐標上工作,遙開始在虛擬坐標空間里工作。接下來,我們需要找到某種可以把虛擬空間坐標轉化回歸依化設備坐標的方法,讓OpenGL可以正確的渲染它們。這種轉換應該把屏幕方向計算在內,以使圖像在豎屏模式和橫屏模式看上去都一樣。

我們想要進行的操作叫作正交投影。使用正交投影,不管多遠或者多近,所有物體看上去大小總是相同的。為了更高的理解這種投影是做什么的,想象一下,在我們的場景中有一個火車軌道,直接從空中俯瞰,這些軌道看起來是這樣的:

還有一種特殊類型的正交投影,被稱為等軸測投影,它是從側角觀察一種正交投影。正如在一些城市模擬和策略游戲中看到的,這種類型的投影能用來重新創建一個經典的三維角。

當我們使用正交投影把虛擬坐標變換回歸化設備坐標時,實際上定義了三維世界內部的一個區域。在這個區域內的所有東西都會顯示在屏幕上,而區域外的所有東西都會被剪裁掉。

利用正交投影矩陣改變立方體的大小,以使我們可以在屏幕上看到或多或少的場景。我們也能改變立方體的形狀彌補屏幕的寬高比的影響。

4.線性代數基礎

OpenGL大量使用了向量和矩陣,矩陣的最重要的用途之一就是建立正交和透視投影。其原因之一是,從本質上來說,使用矩陣做投影只涉及對一組數據按順序執行大量的加法和乘法,這些運算在現代GPU上執行的非??臁?/p>

4.1向量

一個向量是一個有多個元素的一維數組。在OpenGL里,一個位置通常是一個四元素向量,顏色也一樣。我們使用的大多數向量一般都有四個元素。在下面的例子中, 我們可看到一個位置向量,它有一個X,一個Y,一個Z,一個W分量。

4.2矩陣

一個矩陣是一個有多個元素的二維數組。在OpenGL里,我們一般使用矩陣作向量投影,如正交或者透視投影,并且也用它們旋轉物體,平移物體以及縮放物體。我們把矩陣與每個要變換的向量相乘可實現這些變換。下面就是一個矩陣:

4.3矩陣與向量的乘法

要讓矩陣乘以一個向量,我們把矩陣放在左邊,向量放在右邊。如下:

規則就是矩陣第一行乘以向量第一列,以第一行為例:矩陣第一行第一個元素乘以向量第一列第一個元素,加上矩陣第一行第二個元素乘以向量第一列第二個元素,加上矩陣第一行第三個元素乘以向量第一列第三個元素,加上矩陣第一行第四個元素乘以向量第一列第四個元素。矩陣二,三,四行同理。

4.4單位矩陣

單位矩陣如下:

之所以被稱為單位矩陣,是因為這個矩陣乘以任何向量總是得到與原來相同的向量。就像把任何數字乘以1會得到原來的數字一樣。

4.5平移矩陣

既然理解了單位矩陣,讓我們看一個非常簡單的矩陣類型---平移矩陣。它在OpenGL里十分常用。使用這種類型的矩陣,我們可以把一個物體沿著指定的距離移動。這個矩陣和單位矩陣差不多,但在右側指定了三個額外的元素:

讓我們盾一個位置(2,2)的例子,這個位置Z默認是0,W默認是1.我們把這個向量沿X軸平移3,沿Y軸也平移3,因此,把Xtranslation賦值為3,Ytranslation賦值為3。結果如下:

這個位置正是我們所期望和(5,5)。

5.正交投影

要定義正交投影,我們將使用Android的Matrix類,它在android.opengl包中。這個類有一個稱為orthoM()的方法,它可以為我們生成一個正交投影。

我們來看一下orthoM()參數:

orthom(float[] m,int mOffset,float left,float rigth,float bottom,float top,float near,float far)

float[] m:目標數組,這個數組長度至少有16個元素,這樣它才能存儲正交投影矩陣。

int mOffset:結果矩陣起始的偏移值。

float left:X軸的最小范圍。

float right:X軸的最大范圍。

float bottom:Y軸的最小范圍。

float top:Y軸的最大范圍。

float near:Z軸的最小范圍。

float far:Z軸的最大范圍。

當我們調用這個方法的時候,它應該產生下面的正交投影矩陣:

這個正交投影矩陣會把所有在左右之間,上下之間和遠近之間的事物映射到歸一化設備坐標中從-1到1的范圍,在這個范圍內所有事物在屏幕上都是可見的。

主要的區別就是Z軸有一個負值符號,它的效果是反轉Z坐標。這就意味著,物體離得越遠,Z坐標的負值會越來越小。之所以這樣完全是歷史和傳統的原因。

6.左手與右手坐標系統

為了更好的理解Z軸問題,我們需要理解左手坐標系統與右手坐標系統之間的區別。想知道一個坐標系統是左手的還是右手的,你拿出一只手,把大拇指指向X軸正值方向,然后把食指指向Y軸正值方向。

現在,把你的中指指向Z軸。如果你需要用左手做這些,那你看到的就是一個左手坐標系統;如果你需要用右手,那你看到的就是一個右手坐標系統。把你的中指指向Z軸,記住要把大拇指指向X軸方向,食指指向Y軸正值方向。如下圖:

其實左手還是右手選擇都沒關系,只是一個簡單的轉換。歸一化設備坐標使用的是左手坐標系統,而在OpenGL的早期版本,默認使用的確實右手坐標系統,其使用Z的負值增加表示距離增加。這就是為什么Android的Matrix會默認生成反轉Z的矩陣。

7.更新程序

7.1更新著色器

修改前一章的頂點著色器中的代碼如下:

uniform mat4 u_Matrix;

attribute vec4 a_Position;

attribute vec4 a_Color;

varying vec4 v_Color;

void main()

{

v_Color=a_Color;

gl_Position =u_Matrix*a_Position;

gl_PointSize = 10.0;

}

我們這里添加了一個新的uniform定義的“u_Matrix”,并把它定義為一個mat4類型,意思是這個uniform代表一個4*4的矩陣。更新位置負值那一行:

gl_Position =u_Matrix*a_Position;

我們沒有傳遞數組中定義的位置,而是傳遞那個位置與一個矩陣的乘積。它意味著頂點數組不用再被翻譯為歸一化設備的坐標了,其將被理解為存在于這個矩陣所定義的虛擬坐標空間中。這個矩陣會把坐標從虛擬坐標空間變化回歸一化設備坐標。

7.2添加矩陣數組和一個新的uniform

打開上一節的LYJRenderer添加成員變量:

private static final String U_MATRIX="u_Matrix";

我們還需要一個頂點數組存儲矩陣:

private final float[] projectionMatrix=new float[16];

我們也需要一個整型值用于保存那個矩陣uniform的位置:

private int uMatrixLocation;

然后我們只需要在onSurfaceCreated()中加入如下代碼:

uMatrixLocation=GLES20.glGetUniformLocation(program,U_MATRIX);

7.3創建正交投影矩陣

更新onSurfaceChanged(),在GLES20.glViewport()調用后面加入如下代碼:

final float aspectRatio=width>height?(float)width/(float)heigth:(float)height/(float)width;

if(width>height){

orthoM(projectionMatrix,0,-aspectRatio,aspectRatio,-1f,1f,-1f,1f);

}else{

orthoM(projectionMatrix,0,-1f,1f,-aspectRatio,aspectRatio,-1f,1f);

}

這段代碼會創建一個正交投影矩陣,這個矩陣會把屏幕的當前方向計算在內。注意在Android中不只有一個Matrix類,因此你要確保導入了android.opengl.Matrix。

我們首先計算了寬高比,它使用寬和高中的較大值除以寬和高的較小值。不管是豎屏還是橫屏,這個值都一樣。

7.4傳遞矩陣給著色器

在LYJRenderer中的onDrawFrame()中,我們在glClear()調用之后加入如下代碼:

GLES20.glUniformMatrix4fv(uMatrixLocation,1,false,projectionMatrix,0);

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,247評論 6 543
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,520評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,362評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,805評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,541評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,896評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,887評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,062評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,608評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,356評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,555評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,077評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,769評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,175評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,489評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,289評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,516評論 2 379

推薦閱讀更多精彩內容