OpenGL ES 2.0 (iOS)[04]:坐標空間 與 OpenGL ES 2 3D空間


目錄

一立莉、多坐標系

1.  世界坐標系
2.  物體(模型)坐標系
3.  攝像機坐標系
4.  慣性坐標系

二绢彤、坐標空間

1.  世界空間
2.  模型空間
3.  攝像機空間
4.  裁剪空間
5.  屏幕空間

三、OpenGL ES 2 3D 空間

1.  變換發(fā)生的過程
2.  各個變換流程分解簡述
3.  四次變換與編程應(yīng)用

四蜓耻、工程例子

五茫舶、參考書籍


一、多坐標系

1. 世界坐標系

  • 即物體存在的空間刹淌,以此空間某點為原點饶氏,建立的坐標系

  • 世界坐標系是最大的坐標系,世界坐標系不一定是指“世界”芦鳍,準確來說是一個空間或者區(qū)域嚷往,就是足以描述區(qū)域內(nèi)所有物體的最大空間坐標,是我們關(guān)心的最大坐標空間柠衅;

  • 例子

    • ep1:
      比如我現(xiàn)在身處廣州皮仁,要描述我現(xiàn)在所在的空間,對我而言最有意義就是菲宴,我身處廣州的那里贷祈,而此時的廣州就是我關(guān)心的“世界坐標系”,而不用描述我現(xiàn)在的經(jīng)緯坐標是多少喝峦,不需要知道我身處地球的那個經(jīng)緯位置势誊。
      這個例子是以物體的方向思考的最合適世界坐標系;(當然是排除我要與廣州以外的區(qū)域進行行為交互的情況咯Rゴ馈)
  • ep2:
    如果現(xiàn)在要描述廣州城的全貌粟耻,那么對于我們而言查近,最大的坐標系是不是就是廣州這個世界坐標系,也就是所謂的我們最關(guān)心的坐標系挤忙;
    這個例子是以全局的方向思考的最合適世界坐標系霜威;

  • 世界坐標系主要研究的問題:

  1. 每個物體的位置和方向
  2. 攝像機的位置和方向
  3. 世界的環(huán)境(如:地形)
  4. 物體的運動(從哪到哪)

2. 物體(模型)坐標系

  • 模型自身的坐標系,坐標原點在模型的某一點上册烈,一般是幾何中心位置為原點

  • 模型坐標系是會跟隨模型的運動而運動戈泼,因為它是模型本身的 “一部份” ;

  • 模型內(nèi)部的構(gòu)件都是以模型坐標系為參考進而描述的赏僧;

  • ep:
    比如有一架飛機大猛,機翼位于飛機的兩側(cè),那么描述機翼最合適的坐標系淀零,當然是相對于飛機本身挽绩,機翼位于那里;飛機在飛行的時候窑滞,飛機本身的坐標系是不是在跟隨運動琼牧,機翼是不是在飛機的坐標中同時運動著。

3. 攝像機坐標系

  • 攝像機坐標系就是以攝像機本身為原點建立的坐標系哀卫,攝像機本身并不可見巨坊,它表示的是有多少區(qū)域可以被顯示(渲染)

  • 白色線所圍成的空間,就是攝像機所能捕捉到的最大空間此改,而物體則位于空間內(nèi)部趾撵;

  • 位于攝像機捕捉空間外的圖形會直接被剔除掉;

4. 慣性坐標系

  • 它的 X 軸與世界坐標系的 X 軸平行且方向相同共啃,Y 軸亦然占调,它的原點與模型坐標系相同

  • 它的存在的核心價值是,簡化坐標系的轉(zhuǎn)換移剪,即簡化模型坐標系到世界坐標系的轉(zhuǎn)換究珊;


二、坐標空間

坐標空間就是坐標系形成的空間

1. 世界空間

世界坐標系形成的空間纵苛,光線計算一般是在此空間統(tǒng)一進行剿涮;

2. 模型空間

模型坐標系形成的空間,這里主要包含模型頂點坐標和表面法向量的信息攻人;


第一次變換
模型變換(Model Transforms):就是指從模型空間轉(zhuǎn)換到世界空間的過程


3. 攝像機空間

攝像機空間

攝像機空間取试,就是黃色區(qū)域所包圍的空間;
攝像機空間在這里就是透視投影怀吻,透視投影用于 3D 圖形顯示瞬浓,反映真實世界的物體狀態(tài);

透視知識擴展 《透視》


第二次變換
視變換(View Transforms):就是指從世界空間轉(zhuǎn)換到攝像機空間的過程


  • 攝像機空間蓬坡,也被稱為眼睛空間猿棉,即可視區(qū)域磅叛;
  • 其中,LookAt(攝像機的位置) 和 Perspective(攝像機的空間) 都是在調(diào)整攝像空間铺根;

4. 裁剪空間

圖形屬于裁剪空間則保留宪躯,圖形在裁剪空間外,則剔除(Culled)

攝像機 帶注解

標號(3)[視景體] 位迂,所指的空間即為裁剪空間,這個空間就由 Left详瑞、Right掂林、Top、Bottom坝橡、Near泻帮、Far 六個面組成的四棱臺,即視景體计寇。


視景體

圖中紫色區(qū)域為視場角


fov & zoom

從而引出锣杂,視場縮放為:


zoom
  • 其次,頂點是用齊次坐標表示{x, y, z, w}, 3D 坐標則為{x/w, y/w, z/w}而 w 就是判斷圖形是否屬于裁剪空間的關(guān)鍵:
錐面 關(guān)系
Near z < -w
Far z > w
Bottom y < -w
Top y > w
Left x < -w
Right x > w

即坐標值番宁,不符合這個范圍的元莫,都會被裁剪掉

坐標 值范圍
x [-w , w]
y [-w, w]
z [-w, w]

第三次變換
投影變換(Projection Transforms): 當然包括正交、透視投影了蝶押,就是指從攝影機空間到視景體空間的變換過程


5. 屏幕空間

它就是顯示設(shè)備的物理屏幕所在的坐標系形成的空間踱蠢,它是 2D 的且以像素為單位,原點在屏幕的幾何中心點

屏幕坐標空間.jpg


第四次變換(最后一次)
視口變換(ViewPort Transforms): 指從裁剪空間到屏幕空間的過程棋电,即從 3D 到 2D


這里主要是關(guān)注像素的分布茎截,即像素縱橫比;因為圖形要從裁剪空間投影映射到屏幕空間中赶盔,需要知道真實的環(huán)境的像素分布情況企锌,不然圖形就會出現(xiàn)變形;

《OpenGL ES 2.0 (iOS)[02]:修復三角形的顯示》這篇文章就是為了修復屏幕像素比例不是 1 : 1 引起的拉伸問題于未,而它也就是視中變換中的一個組成部分撕攒。

  • 像素縱橫比計算公式
像素縮放比

三、OpenGL ES 2 3D 空間

1. 變換發(fā)生的過程

OpenGL ES 2 變換流程圖
  • 這個過程表明的是 GPU 處理過程(渲染管線)沉眶;

  • 變換過程發(fā)生在打却,頂點著色與光柵化之間,即圖元裝配階段谎倔;

  • 編寫程序的時候柳击,變換的操作是放在頂點著色器中進行處理;

  • 右下角寫明了片习,總共就是四個變換過程:模型變換捌肴、視變換蹬叭、投影變換、視口變換状知,經(jīng)過這四個變換后秽五,圖形的點就可以正確并如愿地顯示在用戶屏幕上了;

  • 側(cè)面反應(yīng)饥悴,要正確地渲染圖形坦喘,就要掌握這四種變換;

2. 各個變換流程分解簡述

  • 階段一:追加 w 分量為 1.0 (第一個藍框)

    這個階段不需要程序員操作

    這里的原因是西设,OpenGL 需要利用齊次坐標去進行矩陣的運算瓣铣,核心原因當然就是方便矩陣做乘法咯(R(4x4) 點乘 R(4x1) 嘛)!

  • 階段二:用戶變換 (第二個藍框)

    這個階段需要程序員操作贷揽,在 Vertex Shader Code 中進行操作

    這個階段主要是把模型正確地通過 3D 變換(旋轉(zhuǎn)棠笑、縮放、平移)放置于攝像機的可視區(qū)域(視景體)中禽绪,包括處理攝像機的位置蓖救、攝像機的可視區(qū)域占整個攝像機空間的大小。

    這個階段過后印屁,w 就不在是 1.0 了

  • 階段三:重新把齊次坐標轉(zhuǎn)換成 3D 坐標 (第三個藍框)

    這個階段不需要程序員操作

    要重新轉(zhuǎn)換回來的原因循捺,也很簡單 ---- 齊次坐標只是為了方便做矩陣運算而引入的,而 3D 坐標點才是模型真正需要的點位置信息库车。

    這個階段過后巨柒,所有的點坐標都會標準化(所謂標準化,就是單位為1)柠衍,x 和 y 值范圍均在 [-1.0, 1.0 ]之間洋满,z 就在 [ 0.0, 1.0 ] 之間;

    x 和 y 值范圍均在 [-1.0, 1.0 ]之間珍坊,才能正確顯示牺勾,原因是 OpenGL 的正方體值范圍就是 [ -1.0, 1.0 ] 不存在其它范圍的值;而 z 的值范圍是由攝像機決定的阵漏,攝像機所處的位置就是 z = 0驻民,的位置,所以 0 是指無限近履怯,攝像機可視區(qū)的最遠處就是 z = 1回还, 所以 1 是指無限遠;

  • 階段四:重新把齊次坐標轉(zhuǎn)換成 3D 坐標 (第四個藍框)

    *這個階段需要程序員操作叹洲,在圖形渲染前要進行操作柠硕,即在 gldraw 前 **

    這個階段核心的就是 ViewPort 和 DepthRange 兩個,前者是指視口,后者是深度蝗柔,分別對應(yīng)的 OpenGL ES 2 的 API 是:

函數(shù) 描述
glViewport 調(diào)整視窗位置和尺寸
glDepthRange 調(diào)整視景體的 near 和 far 兩個面的位置 (z)
glViewport
void glViewport(GLint x, GLint y, GLsizei w, GLsizei h)
x, y 以渲染的屏幕坐標系為參考的視口原點坐標值(如:蘋果的移動設(shè)備都是是以左上角為坐標原點)
w, h 要渲染的視口尺寸闻葵,單位是像素
glDepthRange
void glDepthRange(GLclampf n, GLclampf f)
n, f n, f 分別指視景體的 near 和 far ,前者的默認值為 0 癣丧,后者的默認值為 1.0槽畔, 它們的值范圍均為 [ 0.0, 1.0 ], 其實就是 z 值

3. 四次變換與編程應(yīng)用

  • 下面這兩張圖片就是 Vertex Shader Code 中的最終代碼
#version 100

attribute vec4 v_Position;
uniform mat4 v_Projection, v_ModelView;

attribute vec4 v_Color;
varying mediump vec4 f_color;

void main(void) {
    f_color = v_Color;
    gl_Position  = v_Projection * v_ModelView * v_Position;
}
 v_Projection 表示投影變換;v_ModelView 表示模型變換和視變換胁编;
  • 第一次變換:模型變換厢钧,模型空間到世界空間 ( 1 -> 2 )

請看《OpenGL ES 2.0 (iOS)[02]:修復三角形的顯示》 這篇文章,專門講模型變換的掏呼。

  • 余下的幾次變換坏快,都是和攝像機模型在打交道
    攝像機里面的模型
Camera Model
要完成攝像機正確地顯示模型,要設(shè)置攝像機位置憎夷、攝像機的焦距:
  1. 設(shè)置攝像機的位置、方向 --> (視變換) gluLookAt (ES 沒有這個函數(shù))昧旨,使要渲染的模型位于攝像機可視區(qū)域中拾给;【完成圖中 1 和 2】
  2. 選擇攝像機的焦距去適應(yīng)整個可視區(qū)域 --> (投影變換) glFrustum(視景體的六個面)、gluPerspective(透視) 兔沃、glOrtho(正交)( ES 沒有這三個函數(shù)) 【完成圖中 3】
  3. 設(shè)置圖形的視圖區(qū)域蒋得,對于 3D 圖形還可以設(shè)置 depth- range --> glViewport 、glDepthRange
  • 第二次變換:視變換乒疏,世界空間到攝像機空間 ( 2 -> 3 )

上面提到额衙, ES 版本沒有 gluLookAt 這個函數(shù),但是我們知道怕吴,這里做的都是矩陣運算窍侧,所以可以自己寫一個功能一樣的矩陣函數(shù)即可;

// 我不想寫转绷,所以可以用 GLKit 提供給我們的函數(shù)
/*
Equivalent to gluLookAt.
*/
GLK_INLINE GLKMatrix4 GLKMatrix4MakeLookAt(float eyeX, float eyeY, float eyeZ,
                                                 float centerX, float centerY, float centerZ,
                                                 float upX, float upY, float upZ);
Frustum

函數(shù)的 eye x伟件、y、z 就是對應(yīng)圖片中的 Eye at 议经,即攝像機的位置斧账;

函數(shù)的 center x、y煞肾、z 就是對應(yīng)圖片中的 z-axis 可視區(qū)域的中心點咧织;

函數(shù)的 up x、y籍救、z 就是對應(yīng)圖片中的 up 指攝像機上下的位置(就是角度)习绢;

  • 第三次變換:投影變換,攝像機空間到裁剪空間 ( 3 -> 4 )
view frustum

當模型處于視景體外時會被剔除掉钧忽,如果模型有一部分在視景體內(nèi)時毯炮,模型的點信息只會剩下在視景體內(nèi)的逼肯,其它的點信息不渲染;

/*
 Equivalent to glFrustum.
 */
GLK_INLINE GLKMatrix4 GLKMatrix4MakeFrustum(float left, float right,
                                            float bottom, float top,
                                            float nearZ, float farZ);

這個是設(shè)置視景體六個面的大小的桃煎;

  • 透視投影
透視投影

對應(yīng)的投影公式 :

完整的透視投影公式

使用 GLKit 提供的函數(shù):

/*
 Equivalent to gluPerspective.
 */
GLK_INLINE GLKMatrix4 GLKMatrix4MakePerspective(float fovyRadians, // 視場角
                                                    float aspect,  // 屏幕像素縱橫比
                                                    float nearZ, // 近平面距攝像機位置的距離
                                                    float farZ); // 遠平面攝像機位的距離
  • 正交投影
Orthographic projection

對應(yīng)的投影公式 :

完整的正交投影公式
/*
 Equivalent to glOrtho.
 */
GLK_INLINE GLKMatrix4 GLKMatrix4MakeOrtho(float left, float right,
                                          float bottom, float top,
                                          float nearZ, float farZ);
  • 第四次變換:視口變換篮幢,裁剪空間到屏幕空間 ( 4 -> 5 )

這里就是設(shè)置 glViewPort 和 glDepthRange 當然 2D 圖形不用設(shè)置 glDepthRange ;

  • 實際編程過程中的使用過程

  • 第一步为迈,如果是 3D 圖形的渲染三椿,那么要綁定深度渲染緩存(DepthRenderBuffer),若是 2D 可以跳過葫辐,因為它的頂點信息中沒有 z 信息 ( z 就是頂點坐標的深度信息 )搜锰;

    1. Generate ,請求 depth buffer 耿战,生成相應(yīng)的內(nèi)存標識符
    2. Bind蛋叼,綁定申請的內(nèi)存標識符
    3. Configure Storage,配置儲存 depth buffer 的尺寸
    4. Attach剂陡,裝載 depth buffer 到 Frame Buffer 中
      具體的程序代碼:
  • 第二步狈涮,縮寫 Vertex Shader Code
#version 100

attribute vec4 v_Position;
uniform mat4 v_Projection, v_ModelView; // 投影變換、模型視圖變換

attribute vec4 v_Color;
varying mediump vec4 f_color;

void main(void) {
     f_color = v_Color;
     gl_Position = v_Projection * v_ModelView * v_Position;
}

一般是把四次變換寫成這兩個鸭栖,當然也可以寫成一個歌馍;因為它們是一矩陣,等同于一個常量晕鹊,所以使用的是 uniform 變量松却,變量類型就是 mat4 四乘四方陣(齊次矩陣);

  • 第三步溅话,就是外部程序賦值這兩個變量

注意晓锻,要在 glUseProgram 函數(shù)后,再使用 glUniform 函數(shù)來賦值變量公荧,不然是無效的带射;*

依次完成 模型變換、視變換循狰、投影變換窟社,即可;它們兩兩用矩陣乘法進行連接即可绪钥;

如:modelMatrix 點乘 viewMatrix , 它們的結(jié)果再與 projectionMatrix 點乘灿里,即為 ModelViewMatrix ;

GLKit 點乘函數(shù)程腹,
GLK_INLINE GLKMatrix4 GLKMatrix4Multiply(GLKMatrix4 matrixLeft, GLKMatrix4 matrixRight);

  • 第四步匣吊,如果是 3D 圖形,有 depth buffer ,那么要清除深度渲染緩存

使用 glClear(GL_DEPTH_BUFFER_BIT); 進行清除色鸳,當然之后就是要使能深度測試 glEnable(GL_DEPTH_TEST); 不然圖形會變形社痛;

最好,也使能 glEnable(GL_CULL_FACE); 這里的意思就是命雀,把在屏幕后面的點剔除掉蒜哀,就是不渲染;判斷是前還是后吏砂,是利用提供的模型頂點信息中點與點依次連接形成的基本圖元的時鐘方向進行判斷的撵儿,這個 OpenGL 會自行判斷;


ClockWise & Counterclockwise

左為順時針狐血,右為逆時針淀歇;

  • 第五步,設(shè)置 glViewPort 和 glDepthRange

使用 OpenGL ES 提供的 glViewPort 和 glDepthRange 函數(shù)即可匈织;


四浪默、工程例子

Github: 《DrawSquare_3DFix》


五、參考書籍

《OpenGL ES 2.0 Programming Guide》
《OpenGL Programming Guide 8th》
《3D 數(shù)學基礎(chǔ):圖形與游戲開發(fā)》
《OpenGL 超級寶典 第五版》
《Learning OpenGL ES For iOS》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末缀匕,一起剝皮案震驚了整個濱河市浴鸿,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌弦追,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件花竞,死亡現(xiàn)場離奇詭異劲件,居然都是意外死亡,警方通過查閱死者的電腦和手機约急,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門零远,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人厌蔽,你說我怎么就攤上這事牵辣。” “怎么了奴饮?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵纬向,是天一觀的道長。 經(jīng)常有香客問我戴卜,道長逾条,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任投剥,我火速辦了婚禮师脂,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己吃警,他們只是感情好糕篇,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著酌心,像睡著了一般拌消。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上谒府,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天拼坎,我揣著相機與錄音,去河邊找鬼完疫。 笑死泰鸡,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的壳鹤。 我是一名探鬼主播盛龄,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼芳誓!你這毒婦竟也來了余舶?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤锹淌,失蹤者是張志新(化名)和其女友劉穎匿值,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體赂摆,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡挟憔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了烟号。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片绊谭。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖汪拥,靈堂內(nèi)的尸體忽然破棺而出达传,到底是詐尸還是另有隱情,我是刑警寧澤迫筑,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布宪赶,位于F島的核電站,受9級特大地震影響铣焊,放射性物質(zhì)發(fā)生泄漏逊朽。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一曲伊、第九天 我趴在偏房一處隱蔽的房頂上張望叽讳。 院中可真熱鬧追他,春花似錦、人聲如沸岛蚤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽涤妒。三九已至单雾,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間她紫,已是汗流浹背硅堆。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留贿讹,地道東北人渐逃。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像民褂,于是被迫代替她去往敵國和親茄菊。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

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

  • 本文首發(fā)于個人博客:Lam's Blog - 【OpenGL ES】入門及繪制一個三角形赊堪,文章由MarkDown語...
    格子林ll閱讀 7,248評論 2 18
  • 1 前言 一直想沿著圖像處理這條線建立一套完整的理論知識體系面殖,同時積累實際應(yīng)用經(jīng)驗。因此有了從使用AVFounda...
    RichardJieChen閱讀 5,644評論 5 12
  • 一周緊張的工作結(jié)束了哭廉,有點疲憊脊僚,但每天都很開心,感覺團隊的每個小伙伴都特別好遵绰,從心底里喜歡每個人吃挑,雖然累,但還是要...
    L莎莎閱讀 107評論 0 0
  • 盛夏時節(jié),安徽牛商爭霸賽的各位小伙伴又一次齊聚在徽馬科技端辱,進行新一場的線下交流活動梁剔。這次線下交流的主題為:阿里巴巴...
    安徽飾界舞臺桁架閱讀 433評論 0 2
  • 來到寢室,打開門便看到三張帶上下鋪的床架子整整齊齊的擺在兩邊舞蔽,右邊兩張荣病,左邊一張再加一個六個人的柜子,潔白的地板上...
    右手心聲閱讀 223評論 0 0