正交投影對于透視投影比較容易理解。正交投影把三維世界的部分投影到屏幕上。它是以這樣的一種方式實現(xiàn)這些的,不管物體是遠(yuǎn)還是近,他們看上去的大小都是一樣的,基于這個原因,這種投影類型非常適合實現(xiàn)二維游戲和美術(shù)。
1.1、創(chuàng)建單位正交投影
下面是正交投影矩陣的基本定義:

使用這個給定的矩陣,所有左和右之間、上和下之間、遠(yuǎn)和近之間的坐標(biāo)都會被映射到歸一化設(shè)備坐標(biāo),并且在這個范圍內(nèi)的一切都會在屏幕上可見。
讓我們實際看一下這個矩陣:作為我們的第一個例子,我們將創(chuàng)建一個單位正交投影,讓我們構(gòu)建這個矩陣,把-1傳遞給左、下和近,把+1傳遞給右、上和遠(yuǎn)。經(jīng)過簡單替換,我們得到下面的矩陣。

經(jīng)過簡單的轉(zhuǎn)換之后,我們能得到下面的結(jié)果,再運用加減運算,最后我們簡化這些分?jǐn)?shù),得到最終的矩陣:

它看起來幾乎與單位矩陣完全一樣,之所以是這樣,是因為歸一化設(shè)備坐標(biāo)在每個軸上的范圍是從-1到1,因此,當(dāng)我們把-1和1也傳遞進(jìn)去作為我們的范圍時,實際上要求一個保持其坐標(biāo)不變的正交投影,就想單位矩陣一樣。區(qū)別是z軸是反轉(zhuǎn)的,原因是基于慣例。
1.2、創(chuàng)建常規(guī)單位正交投影
如果我們把所有的坐標(biāo)都制定在范圍[0,1]內(nèi),而不是[-1,1],怎么辦?這意味著,左、下和近都是0,而右、上和遠(yuǎn)都是1。
當(dāng)我們調(diào)用orthoM()的時候,我們要表達(dá)的就是,需要一個矩陣,對于其x、y和z分量,它會把[0,1]映射到范圍[-1,1]上。把[0,1]代入到公式中,運算后得到右邊最后的結(jié)果:

要證明這個矩陣的確把范圍
[0.1]內(nèi)的坐標(biāo)變換為范圍[-1,1] (記住z軸的那特殊反轉(zhuǎn)),讓我們用幾個不同的向量試驗一下。我們用幾個坐標(biāo)來實驗一下,看得到的結(jié)果是不是我們想要的:
按照上面的圖我們能看到,這個向量把
[0,1]中歸一化到[-1,1]中了。我們z用的是一個負(fù)值,盡管我們指定0到1的范圍,但實際上不得不傳遞從0到-1的值,這里要注意。
1.3、使用正交投影
要定義正交矩陣,我們將使用Android的Matrix類,它在android.opengl包中。這個類有一個orthoM()方法,它可以為我們生成一個正交投影。我們將使用這個投影調(diào)整坐標(biāo)控件,我們看一下orthoM()的參數(shù):
/**
* Computes an orthographic projection matrix.
*
* @param m returns the result 目標(biāo)矩陣,這個數(shù)組的長度至少有16個元素,這樣它才能存儲正交投影矩陣;
* @param mOffset 結(jié)果矩陣起始的偏移量
* @param left x軸的最小范圍
* @param right x軸的最大范圍
* @param bottom y軸的最小范圍
* @param top y軸的最大范圍
* @param near z軸的最小范圍
* @param far z軸的最大范圍
*/
orthoM(float[] m, int mOffset, float left, float right, float bottom, float top, float near, float far)
假設(shè)我有一張圖,寬高比為1:2

我們假設(shè)我們需要顯示的view是1:1的正方形,用這張圖歸一化到坐標(biāo)系中,也就是
left,bottom,near為-1,而right,top,far為1:
//orthoM(float[] m, int mOffset, float left, float right, float bottom, float top, float near, float far)
Matrix.orthoM(mvpMatrix, 0, -1f, 1f, -1f, 1f, -1f, 1f);
那顯示出來是下面這樣:

很明顯,圖片會被拉伸成1:1的樣子來鋪滿整個坐標(biāo)系,這也就是坐標(biāo)系的作用。
如果我們想讓他顯示成正常不拉伸的樣子,也就是下面這張圖的樣子,需要怎么設(shè)置呢?

我們觀察并且聯(lián)想上面的正交投影向量,
bottom和top還是保持在[-1,1]不用動,只需要讓left和right變成[-2,2]就好了:
//orthoM(float[] m, int mOffset, float left, float right, float bottom, float top, float near, float far)
Matrix.orthoM(mvpMatrix, 0, -2f, 2f, -1f, 1f, -1f, 1f);
也就是讓原來在-1位置的像素顯示在-0.5的位置,當(dāng)然很多時候展示的GlSurfaceView并不是1:1的,那就需要同時算出來GlSurfaceView的寬高比相除得到比例。
亦或者我們不想讓GlSurfaceView有兩側(cè)的留白,可以接受部分的裁剪,或者只想展示一部分圖像,像下圖,只會展示出來圖片的右下角1/4的圖像

那可以這樣處理
Matrix.orthoM(mvpMatrix, 0, -0f, 1f, -1f, 0f, 0f, 1f);
right和bottom保持不變,left和top變?yōu)?,也就是讓原來顯示在中央的像素移動到左上角,這樣就可以啦~