從零開始學(xué)習(xí)opengl之一基本概念by fengliu_第1頁
從零開始學(xué)習(xí)opengl之一基本概念by fengliu_第2頁
從零開始學(xué)習(xí)opengl之一基本概念by fengliu_第3頁
從零開始學(xué)習(xí)opengl之一基本概念by fengliu_第4頁
從零開始學(xué)習(xí)opengl之一基本概念by fengliu_第5頁
已閱讀5頁,還剩161頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

1、從零開始學(xué)習(xí)OpenGL ES之一 基本概念by fengliuOpenGL ES編程,但大部分我曾寫過一些文章介紹的是已經(jīng)至少懂得一些3D編程知識的人。作為起點(diǎn),請OpenGL Xcode項目模板,而不要使用Apple提供的模板。你可以解壓到下面位置安裝此模板:/Developer/Platforms/ t Templates/Application/OS.platform/Developer/Library/Xcode/Projec已經(jīng)有大量有關(guān)OpenGL的好和書籍。但是,卻沒有多少是關(guān)于OpenGLES,而且沒有(至少在我撰寫此文時)是專門學(xué)習(xí)上3D編程的。因為大部分有關(guān)學(xué)習(xí)OpenG

2、L的材料是從所謂“直接模式(direct mode)”開始的,而OpenGL ES并不支持此模式,對于沒有3D背景知識的開發(fā)者而言,使用現(xiàn)有的書籍和是十分的。為滿足一些開發(fā)者的要求,3D初學(xué)者的博文系列。這是此系列的第一篇文章。我決定撰寫一個OpenGL 數(shù)據(jù)類型首先我們要討論的是OpenGL的數(shù)據(jù)類型。因為OpenGL是一個跨平臺的API, 數(shù)據(jù)類型的大小會隨使用的編程語言以及處理器(64位,32位,16位)等的不同而不同,所以O(shè)penGL定義了的數(shù)據(jù)類型。當(dāng)傳遞數(shù)據(jù)到OpenGL時,你應(yīng)該堅持使用這些OpenGL的數(shù)據(jù)類型,從而保證傳遞數(shù)據(jù)的和精度正確。不這樣做的后果是可能會導(dǎo)致無法預(yù)料的

3、結(jié)果或由于運(yùn)行時的數(shù)據(jù)轉(zhuǎn)換造成效率低下。不論平臺或語言實(shí)現(xiàn)的OpenGL都采用這種方式定義數(shù)據(jù)類型以保證在各平臺上數(shù)據(jù)的更為容易。一致,并使平臺間OpenGL代碼移植下面是OpenGL的各種數(shù)據(jù)類型: GLenum: 用于GL枚舉的無符號整型。通常用于通知OpenGL由指針傳遞于數(shù)組中數(shù)據(jù)的類型(例如,GL_FLOAT用于指示數(shù)組由GLfloat的組成)。 GLboolean: 用于單布爾值。OpenGL ES還定義了其的“真”和“假”值(GL_TRUE和GL_FALSE)以避免平臺和語言的差別。當(dāng)向OpenGL 傳遞布爾值時,請使用這些值而不是使用YES或NO(盡管由于它們的定義實(shí)際沒有區(qū)別

4、,即使你不定義值是一個好的習(xí)慣。)使用了YES或NO。但是,使用GL-GLbitfield: 用于將多個布爾值(最多32個)打包到單個使用位操作變量的四字節(jié)整型。閱 wikipedia在第一次使用位域變量時詳細(xì)介紹,請參GLbyte: 有符號單字節(jié)整型,包含數(shù)值從-128 到 127 GLshort: 有符號雙字節(jié)整型,包含數(shù)值從32,768 到 32,767 GLint: 有符號四字節(jié)整型,包含數(shù)值從2,147,483,648 到2,147,483,647GLsizei: 有符號四字節(jié)整型,用于代表數(shù)據(jù)的的size_tGLubyte: 無符號單字節(jié)整型,包含數(shù)值從0 到(字節(jié)),類似于C中2

5、55。GLushort: 無符號雙字節(jié)整型,包含數(shù)值從0 GLuint: 無符號四字節(jié)整型,包含數(shù)值從0 到GLfloat: 四字節(jié)精度IEEE 754-1985 浮點(diǎn)數(shù)到 65,5354,294,967,295GLclampf: 這也是四字節(jié)精度浮點(diǎn)數(shù),但OpenGL使用GLclampf特別表示數(shù)值為0.0 到 1.0GLvoid:void值用于指示一個函數(shù)沒有返回值,或沒有參數(shù)GLfixed: 定點(diǎn)數(shù) 使用整型數(shù)實(shí)數(shù)。由于大部分計算機(jī)處理器在處理整型數(shù)比處理浮點(diǎn)數(shù)快很多,這通常是對3D系統(tǒng)的優(yōu)化方式。但因為具有用于浮點(diǎn)運(yùn)算的矢量處理器,GLfixed數(shù)據(jù)類型。不討論定點(diǎn)運(yùn)算或GLclamp

6、x: 另一種定點(diǎn)型,用于使用定點(diǎn)運(yùn)算來表示0.0 到 1.0之間的實(shí)數(shù)。正如GLfixed,我們討論或使用它。OpenGL ES (至少目前所使用的版本)不支持8字節(jié)(64位)數(shù)據(jù)類型,如long或double。OpenGL 其實(shí)具有這些大型數(shù)據(jù)類型,但考慮到大部分設(shè)備屏幕以及可能為它們所寫的程序類型而且使用它們有可能對性能造成不利的影響,最后的決定是在OpenGL ES中排除這些數(shù)據(jù)類型。點(diǎn)或頂點(diǎn)3D圖像的最小稱為 點(diǎn)(point) 或者 頂點(diǎn)vertex。它們代表三中的一個點(diǎn)并用來建造更復(fù)雜的物體。多邊形就是由點(diǎn),而物體是由多個多邊形組成。盡管通常OpenGL支持多種多邊形,但OpenGL

7、 ES只支持三邊形(即三角形)。如果你回憶高中學(xué)過的幾何學(xué),你可能會記得所謂笛卡爾坐標(biāo)。 基本概念是在空間中任選一點(diǎn),稱作原點(diǎn)。 然后你可以通過參照原點(diǎn)并使用三維的數(shù)值指定空間中的任意一點(diǎn),坐標(biāo)是由三個通過原點(diǎn)線表示的。從左至右的想象直線叫x-軸。沿著x-軸從左至右數(shù)值變大,向左移動數(shù)值變小。原點(diǎn)左方x為負(fù)值,右邊為正值。另外兩軸同理。沿y軸向上,y值增加,向下y值減小。原點(diǎn)上方y(tǒng)為正,原點(diǎn)下方為負(fù)。對于z軸,當(dāng)物體離開觀察者,數(shù)值變小,向觀察者移動(或超出觀察者),數(shù)值變大。原點(diǎn)前方z值為正,原點(diǎn)之后為負(fù)。下圖幫助說明了這一點(diǎn):Note:上另一種繪圖框架Core Graphics使用了稍微不

8、同的坐標(biāo)系統(tǒng),當(dāng)向屏幕上方移動時y值減小,而向下移動y值增加。沿各軸增加或減小的數(shù)值是以任意刻度進(jìn)行的 它們不代表任何真實(shí),如英尺,英寸或米等。你可以選擇任何對你的程序有意義的刻度。如果你想設(shè)計的以英尺為,你可以那樣做。如果你希望為毫米,同樣可處理,保證它行。OpenGL不管它對最終用戶代表什么,只是將它作為們具有相同的距離。由于任何物體在三中的方位可以由三個數(shù)值表示,物體的位置通常在OpenGL中由使用一個三維數(shù)組的三個GLfloat變量表示,數(shù)組中的第一項(索引0)為x位置,第二項(索引1)為y位置,第三項(索引2)為z位置。下面是一個創(chuàng)建OpenGL ES頂點(diǎn)的簡單例子:GLfloat

9、vertex3; vertex0 = 10.0;vertex1 = 23.75;vertex2 = -12.532;/ x/ y/ z在OpenGL ES中,通常將場景中所有所有或部分物體的提交為頂點(diǎn)數(shù)組。一個頂點(diǎn)數(shù)組是包括場景中部分或所有頂點(diǎn)數(shù)據(jù)的簡單數(shù)組。我將在系列的下一篇中討論,有關(guān)頂點(diǎn)數(shù)組要記住的是它們的大小是基于呈現(xiàn)的頂點(diǎn)數(shù)乘以三(三繪圖)或二(二繪圖)。所以一個包含六個三維空間中的三角形的頂點(diǎn)數(shù)組由54個GLfloat組成,因為每個三角形有三個頂點(diǎn), 而每個頂點(diǎn)有三個坐標(biāo),即6 x 3 x 3 = 54。處理所有這些GLfloat是很痛苦的事情。幸運(yùn)的是,有一個容易的方法。我們可以

10、定義一個數(shù)據(jù)結(jié)構(gòu)了保存多個頂點(diǎn),像這樣:typedef struct GLfloat x; GLfloat y; GLfloat z; Vertex3D;通過這樣做,我們的代碼可讀性更強(qiáng):Vertex3D vertex;vertex.x = 10.0;vertex.y = 23.75;vertex.z = -12.532;現(xiàn)在由于Vertex3D由三個GLfloat組成,向Vertex3D傳遞指針與向數(shù)組傳遞一個包含三個GLfloat的數(shù)組的指針完全一樣。對于電腦而言毫無分別;兩者具和同樣的字節(jié)數(shù)以及OpenGL需要的同樣的順序。將數(shù)據(jù)分組有同樣的到數(shù)據(jù)結(jié)構(gòu)只是讓程序員感到更容易,處理起來更方

11、便。如果你了文章開頭處的Xcode模板,你會發(fā)現(xiàn)此數(shù)據(jù)結(jié)構(gòu)以及我后面將討論的各種函數(shù)都定義在文件OpenGLCommon.h中。還有一個內(nèi)聯(lián)函數(shù)用于創(chuàng)建單個頂點(diǎn): static inline Vertex3D Vertex3DMake(CGFloat inX, CGFloat inY, CGFloat inZ)Vertex3D ret;ret.x = inX;ret.y = inY;ret.z = inZ;return ret; 如果你回憶起幾何學(xué)(如果不記得也不要緊)的內(nèi)容,你會知道空間中兩點(diǎn)間的距離是使用下面公式計算的:我們可以在一個簡單的內(nèi)聯(lián)函數(shù)中實(shí)現(xiàn)這個公式來計算三間的直線距離:中任何

12、兩點(diǎn)static inline GLfloat Vertex3DCalculateDistanceBetweenVertices (Vertex3D first, Vertex3D second)GLfloat deltaX = second.x first.x;GLfloat deltaY = second.y first.y;GLfloat deltaZ = second.z first.z;return sqrtf(deltaX*deltaX + deltaY*deltaY + deltaZ*deltaZ );三角形由于OpenGL ES僅支持三角形,因此我們可以通過創(chuàng)建一個數(shù)據(jù)結(jié)構(gòu)將三

13、個頂點(diǎn)組一個三角形物體。typedef struct Vertex3D v1; Vertex3D v2; Vertex3D v3; Triangle3D;一個 Triangle3D實(shí)際上與一個九個GLfloat的數(shù)組是完全一樣的,因為我們通過頂點(diǎn)和三角形而不是GLfloat數(shù)組來構(gòu)建物體,所以它能幫助我們更容易地處理我們的代碼。的事情。在OpenGL中有一個概念叫卷繞然而關(guān)于三角形你需要知道(winding), 它表示頂點(diǎn)繪制的次序是重要的。不像真實(shí)世界中的物體,有兩面。它們只有一面,被當(dāng)做front faceOpenGL中的多邊形通常都(前面), 三角形只有其front face面對觀察者時

14、才可見??梢栽O(shè)置OpenGL將多邊形作為兩面處理,但默認(rèn)狀態(tài)下,三角形只有一個可見面。通過知道哪一個面是多邊形的前面或可見面,才能使OpenGL只做一半的計算。盡管有時多邊形也可以存在,需要繪制其背面,但通常三角形是一個大物體的一部分,其面對物體內(nèi)部的一面永遠(yuǎn)也不可見。不被繪制的一面稱為backface(背面),OpenGL是通過觀察頂點(diǎn)的繪制次序來確定front face和backface的。以反時針次序繪制頂點(diǎn)的的面是frontface(默認(rèn),可以改變)。由于OpenGL可以很容易確定哪個三角形對用戶可見,所以它使用了一種稱為Backface Culling(隱面消除) 的技術(shù)來避免繪制視

15、窗中多邊形的不可見面。下一篇文章將討論視窗,現(xiàn)在你可將其想象成一個虛擬攝像或觀察OpenGL世界的虛擬窗口。上圖中,左邊青色的三角形是backface,因此將不可見。而右方的三角形是frontface,所以將被繪制。本系列的下一篇文章將設(shè)定一個OpenGL的虛擬世界并使用Vertex3D 和 Triangle3D進(jìn)行一些基本繪圖。再后, 用線性代數(shù)在虛擬世界中移動物體。討論變換,它使從零開始學(xué)習(xí)OpenGL ES之二 述 by fengliu還有許多理論知識需要討論,但與其花許多時間在復(fù)雜的數(shù)學(xué)公式或難以理解的概念上,還不如讓我們開始熟悉OpenGL ES的基本繪圖功能。請OpenGL Xco

16、de項目模板。我們使用此模板而不是Apple提供的模板。你可以解壓到下面目錄來安裝它:簡單繪圖概/Developer/Platforms/OS.platform/Developer/Library/Xcode/Project Templates/Application/此模板用于全屏OpenGL程序,它具有一個OpenGL視圖以及相應(yīng)的視圖器。 大部分時候你不需要動到此視圖。此視圖用于處理一些諸如緩存切換之類的事物,但在兩處調(diào)用了其器類。器的 setupView: 方首先,當(dāng)設(shè)定視圖時,調(diào)用了一次器。調(diào)用視圖法使器有機(jī)會增加所需的設(shè)定工作。這里是你設(shè)定視口,添加光源以及進(jìn)行其他項目相關(guān)設(shè)定的地

17、方?,F(xiàn)在忽略此方法。此方法中已經(jīng)有非?;镜脑O(shè)定以你進(jìn)行簡單地繪圖。器的 drawView: 方法根據(jù)常數(shù)kRenderingFrequency的值定期地被調(diào)用。kRenderingFrequency的初始值為15.0,表示 drawView: 方法每秒鐘被調(diào)用15次。如果你希望改變渲染的頻率,你可以在ConstantsAndMacros.h中找到此常數(shù)的定義。首先加入下列代碼到GLViewController.m的drawView: 方法中:- (void)drawView:(GLView*)view;Vertex3D Vertex3D Vertex3Dvertex1 = Vertex3DM

18、ake(0.0, 1.0, -3.0);vertex2 = Vertex3DMake(1.0, 0.0, -3.0);vertex3 = Vertex3DMake(-1.0, 0.0, -3.0);Triangle3D triangle = Triangle3DMake(vertex1, vertex2, vertex3);glLoadIdentity(); glClearColor(0.7, 0.7, 0.7, 1.0);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glEnableClientState(GL_VERTEX_ARRAY

19、); glColor4f(1.0, 0.0, 0.0, 1.0);glVertexPointer(3, GL_FLOAT, 0, >triangle); glDrawArrays(GL_TRIANGLES, 0, 9); glDisableClientState(GL_VERTEX_ARRAY);在討論我們到底做了什么之前,先運(yùn)行一下,你應(yīng)該看到以下畫面:這是個簡單的方法;如果你試過了,你可能已經(jīng)知道我們到底做了什么,但這里我們還是一起過一遍。因為我們的任務(wù)是畫三角形,所以需要三個頂點(diǎn), 因此我們創(chuàng)建三個上一篇文章中討論過的Vertex3D對象:Vertex3D Vertex3D Ver

20、tex3Dvertex1 = Vertex3DMake(0.0, 1.0, -3.0);vertex2 = Vertex3DMake(1.0, 0.0, -3.0);vertex3 = Vertex3DMake(-1.0, 0.0, -3.0);你應(yīng)該注意到了三個頂點(diǎn)的z值是一樣的,其值(-3.0)是處于原點(diǎn) “之后”的。因為我們還沒有做任何改變,所以我們是站在原點(diǎn)上觀察虛擬世界的,這是默認(rèn)的起點(diǎn)位置。將三角形放置在z值為-3處,可以保證我們可以在屏幕上看到它。隨后,我們創(chuàng)建一個由這三個頂點(diǎn)的三角形。Triangle3D triangle = Triangle3DMake(vertex1, v

21、ertex2, vertex3);這些代碼很容易理解,對嗎?但是,在幕后,電腦是將其視為一個包含9 個 GLfloat 的數(shù)組。如下:GLfloat triangle = 0.0, 1.0, -3.0, 1.0, 0.0, -3.0, -1.0, 0.0,-3.0;并不是完全相同 這里有一個很小但很重要的區(qū)別。在我們的示例中,我們傳遞給OpenGL的是 Triangle3D 對象的地址(即 &triangle ),但在第二個使用數(shù)組的示例中,由于C數(shù)組是指針,我們傳遞的是數(shù)組。現(xiàn)在不需要考慮太多,因為這將是最后一次我用這種方式(第二種方法)定義一個 Triangle3D對象。等一下我將

22、解釋,但現(xiàn)在讓我們先過一遍代碼。下一步我們做的是加載矩陣。我將花至少一整篇文章討論變換矩陣。我們暫且將其視為OpenGL的“復(fù)位開關(guān)”。它將清除虛擬世界中的一切旋轉(zhuǎn),移動或其他變化并將觀察者置于原點(diǎn)。glLoadIdentity();之后,我們告訴OpenGL所有的繪制工作是在一個灰色背景上進(jìn)行的。OpenGL通常需要用四個鉗位值來定義顏色。上一篇文章中有提過,鉗位浮點(diǎn)數(shù)是0.0 到 1.0之間的浮點(diǎn)數(shù)。我們通過定義紅,綠,藍(lán)以及alpha元素來定義顏色, alpha值定義了顏色之后物體的將其設(shè)為1.0,代表完全不透明。程度?,F(xiàn)在暫時不用管它,glClearColor(0.7, 0.7, 0.

23、7, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);在OpenGL中要定義白色,我們需要將四個元素全部設(shè)為1.0。要定義不透明的黑色,則定義紅,綠,藍(lán)為0.0,alpha為1.0。上例代碼的第二行是通知OpenGL清除以前的一切圖形并將其設(shè)為clear顏色。你可能想知道 glClear()的兩個參數(shù)是什么意思。簡單地說,它們是與位域中的常量。OpenGL 保存了一系列 緩存(buffers),即用于繪圖各方面的內(nèi)存塊。將這兩個值進(jìn)行邏輯或是通知OpenGL清除兩個不同的緩存 顏色緩存(color buffer) 和 深度緩存(

24、depth buffer)。 顏色緩存保存當(dāng)前幀各像素的顏色?;旧暇褪悄阍谄聊簧峡吹降摹I疃染彺妫ㄓ袝r也稱為“z-buffer”)保存每個潛在像素離觀察者距離的信息。使用此信息可以確定一個像素是否需要被繪制出來。這兩個緩存是OpenGL中最常見的緩存。還有其他一些緩存,如模板緩存(stencil buffer)和累積緩存(accumulation buffer),但現(xiàn)在我們暫時不討論這些。我們現(xiàn)在只需記住在繪制一幀之前,必須清除這兩個緩存以保證和以前的內(nèi)容混雜。然后,我們要啟動OpenGL的一項稱為vertex arrays(頂點(diǎn)數(shù)組)的特性。此特性可能只需要setupView:方法中啟動一

25、次,但作為基本準(zhǔn)則,我喜歡啟動和我使用的功能。你永遠(yuǎn)也知道是否另一段代碼會做不同處理。如果你打開你需要的功能然后關(guān)閉它,產(chǎn)生問題的幾率將大為減小。就本例來說,如果另一個類不使用頂點(diǎn)數(shù)組而使用頂點(diǎn)緩存的話,任何一段代碼遺留了啟動了的特性或沒有顯性啟動其需要的特性,這一段或兩段代碼都會導(dǎo)致不可預(yù)知的結(jié)果。glEnableClientState(GL_VERTEX_ARRAY);接下來我們設(shè)置了繪圖時所需的顏色。此行代碼將繪圖顏色設(shè)為鮮艷的紅色。glColor4f(1.0, 0.0, 0.0, 1.0);現(xiàn)在,直到下次調(diào)用 glColor4f()前所有的圖形都是以紅色繪制。有一些例外的情況,例如繪制

26、紋理形狀時,但基本上,這樣設(shè)定顏色可以使顏色保持。由于我們使用頂點(diǎn)數(shù)組,我們必須通知OpenGL頂點(diǎn)的數(shù)組在什么地方。記住,頂點(diǎn)數(shù)組只是一個GLfloat的C數(shù)組,每三個值代表一個頂點(diǎn)。我們創(chuàng)建了Triangle3D 對象,但在內(nèi)存中,它完全等同于9個連續(xù)的GLfloat, 所以我們可以傳遞此三角形對象的地址。glVertexPointer(3, GL_FLOAT, 0, &triangle);glVertexPointer() 的第一個參數(shù)指示了多少個GLfloat代表一個頂點(diǎn)。根據(jù)你是在進(jìn)行二維或三維繪圖,你可以傳遞2或者3。盡管我們的物體是存在于一個平面的,我們?nèi)匀粚⑵淅L制在三維

27、虛擬世界中,因此每個頂點(diǎn)用三個數(shù)值表示,所以我們傳遞3給函數(shù)。然后,我們傳遞一個枚舉值告訴OpenGL頂點(diǎn)是由GLfloat。OpenGL ES你在當(dāng)?shù)財?shù)組中使用大部分的數(shù)據(jù)類型,但除GL_FLOAT外,其他都很少見。下一個參數(shù) 現(xiàn)在不需要考慮下一個參數(shù)。那是以后討論的主題?,F(xiàn)在,它始終為0。在以后的文章中,我將討論怎樣使用此參數(shù)將同一對象以不同的數(shù)據(jù)類型混雜在一個數(shù)據(jù)結(jié)構(gòu)中。隨后,我們通知OpenGL通過剛才提交的頂點(diǎn)數(shù)組來繪制三角形。glDrawArrays(GL_TRIANGLES, 0, 9);你可能已經(jīng)可以猜到,第一個枚舉值是告訴OpenGL繪制什么。盡管OpenGL ES不支持繪制

28、三角形之外的四邊形或其他多邊形,但它仍然支持一些其他繪圖模式,如繪制點(diǎn),線,線回路,三角形條和三角形扇。稍后些繪圖模式。討論這最后,我們要先前啟動了的特性以保證被其他地方的代碼弄混。本例中沒有其他的代碼了,但通常你可以使用OpenGL繪制多個物體。glDisableClientState(GL_VERTEX_ARRAY);好了,我們的代碼可以工作了盡管它不是那么引人入勝而且不是十分高效, 但它確確實(shí)實(shí)可以工作。每秒鐘我們的代碼被調(diào)用數(shù)次。不相信?加入下列黑體代碼再次運(yùn)行:1.- (void)drawView:(GLView*)view;2.3.4.5.6.7.8.9.10.11.12.13.1

29、4.15.16.17.18.19.20.21.static GLfloat rotation = 0.0;Vertex3D Vertex3D Vertex3Dvertex1 = Vertex3DMake(0.0, 1.0, -3.0);vertex2 = Vertex3DMake(1.0, 0.0, -3.0);vertex3 = Vertex3DMake(-1.0, 0.0, -3.0);Triangle3D triangle = Triangle3DMake(vertex1, vertex2, vertex3);glLoadIdentity(); glRotatef(rotation, 0

30、.0, 0.0, 1.0);glClearColor(0.7, 0.7, 0.7, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glEnableClientState(GL_VERTEX_ARRAY); glColor4f(1.0, 0.0, 0.0, 1.0);glVertexPointer(3, GL_FLOAT, 0, >triangle); glDrawArrays(GL_TRIANGLES, 0, 9); glDisableClientState(GL_VERTEX_ARRAY);rotation+= 0.5

31、;當(dāng)你再次運(yùn)行時,三角形將沿著原點(diǎn)緩緩轉(zhuǎn)動。先不需要關(guān)注太多旋轉(zhuǎn)的邏輯。想告訴你我們的代碼每秒鐘被調(diào)用了多次。如果你想畫正方形怎么辦?OpenGL ES并不支持正方形,所以我們只能通過三角形來定義正方形。這很簡單 一個正方形可以通過兩個三角形。我們要怎樣調(diào)整上敘代碼來繪制兩個三角形?是不是可以創(chuàng)建兩個Triangle3D? 是的,你可以這樣做,但那沒有效率。我們最好將兩個三角形置入同一個頂 點(diǎn)數(shù)組中。我們可以通過定義一個包含兩個Triangle3D對象的數(shù)組,或分配 大小等于兩個Triangle3D對象或18個GLfloat的內(nèi)存.法:這是1.- (void)drawView:(GLView*

32、)view;2.3.4.Triangle3D triangle2;triangle0.v1 = Vertex3DMake(0.0, 1.0, -3.0);5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.triangle0.v2 = Vertex3DMake(1.0, 0.0, -3.0);triangle0.v3 = Vertex3DMake(-1.0, 0.0, -3.0);triangle1.v1 = Vertex3DMake(-1.0, 0.0, -3.0);triangle1.v2 = Vertex3DMake(1.0, 0.0, -3.0);trian

33、gle1.v3 = Vertex3DMake(0.0, -1.0, -3.0);glLoadIdentity(); glClearColor(0.7, 0.7, 0.7, 1.0);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glEnableClientState(GL_VERTEX_ARRAY); glColor4f(1.0, 0.0, 0.0, 1.0);glVertexPointer(3, GL_FLOAT, 0, >triangle); glDrawArrays(GL_TRIANGLES, 0, 18); glDisabl

34、eClientState(GL_VERTEX_ARRAY);運(yùn)行,你將看到如下屏幕:由于Vertex3DMake()方法在堆中創(chuàng)建新的Vertex3D然后而造成額外的內(nèi)存被占用,因此上述代碼并不理想。其值到數(shù)組中對于這樣簡單的情況是沒有什么問題的,但是在一個更為復(fù)雜的情況下,如果定義的3D物體很大時,那么你希望將其分配在堆中而且你希望對一個頂點(diǎn)不止一次地進(jìn)行內(nèi)存分配,所以最好是養(yǎng)成習(xí)慣通過我們的老朋友 malloc() (我更喜歡用 calloc() ,因為它會將所有值設(shè)為0,比較易于查找錯誤)將頂點(diǎn)分配在棧中。 首先我們需要一個函數(shù)設(shè)定現(xiàn)存頂點(diǎn)的值而不是像Vertex3DMake()一樣創(chuàng)建

35、一個新對象。如下:1.static inline void Vertex3DSet(Vertex3D *vertex, CGFloat inX, CGFloat in Y, CGFloat inZ)2.3.vertex->x = inX;4. vertex->y = inY;5. vertex->z = inZ; 6.現(xiàn)在,我們使用新方法將兩個三角形分配在棧中,重寫代碼:1.- (void)drawView:(GLView*)view;2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.Triangle3D *t

36、riangles = malloc(sizeof(Triangle3D) * 2);Vertex3DSet(>triangles0.v1, 0.0, 1.0, -3.0);Vertex3DSet(>triangles0.v2, 1.0, 0.0, -3.0);Vertex3DSet(>triangles0.v3, -1.0, 0.0, -3.0);Vertex3DSet(>triangles1.v1, -1.0, 0.0, -3.0);Vertex3DSet(>triangles1.v2, 1.0, 0.0, -3.0);Vertex3DSet(>trian

37、gles1.v3, 0.0, -1.0, -3.0);glLoadIdentity(); glClearColor(0.7, 0.7, 0.7, 1.0);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glEnableClientState(GL_VERTEX_ARRAY); glColor4f(1.0, 0.0, 0.0, 1.0);glVertexPointer(3, GL_FLOAT, 0, triangles); glDrawArrays(GL_TRIANGLES, 0, 18); glDisableClientState(GL_

38、VERTEX_ARRAY);if (triangles != NULL) free(triangles);好了,我們已經(jīng)討論了許多基礎(chǔ)知識,我們現(xiàn)在更深入一點(diǎn)。記住我說過OpenGL ES不止一種繪圖方式嗎?現(xiàn)在正方形需要6個頂點(diǎn)(18個 GLfloat), 實(shí)際上我們可以使用 triangle strips (GL_TRIANGLE_STRIP)方法通過四個頂點(diǎn)(12個 GLfloat)來繪制正方形。(索引0, 1,這里是三角形條的基本概念:第一個三角形條是由前三個頂點(diǎn)2)。第二個三角形條是由前一個三角形的兩個頂點(diǎn)加上數(shù)組中的下一個頂點(diǎn),繼續(xù)直到整個數(shù)組結(jié)束??聪聢D更清楚 第一個三角形由頂點(diǎn)

39、 1, 2, 3,下一個三角形由頂點(diǎn) 2, 3, 4,等等:所以,我們的正方形是這樣的:代碼如下:1.- (void)drawView:(GLView*)view;2.3.4.5.6.7.8.9.10.11.Vertex3D *vertices = malloc(sizeof(Vertex3D) * 4);Vertex3DSet(>vertices0, 0.0, 1.0, -3.0);Vertex3DSet(>vertices1, 1.0, 0.0, -3.0);Vertex3DSet(>vertices2, -1.0, 0.0, -3.0);Vertex3DSet(>

40、vertices3, 0.0, -1.0, -3.0);glLoadIdentity();12.13.14.15.16.17.18.19.20.21.22.glClearColor(0.7, 0.7, 0.7, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glEnableClientState(GL_VERTEX_ARRAY); glColor4f(1.0, 0.0, 0.0, 1.0);glVertexPointer(3, GL_FLOAT, 0, vertices); glDrawArrays(GL_TRIANGLE_S

41、TRIP, 0, 12); glDisableClientState(GL_VERTEX_ARRAY);if (vertices != NULL) free(vertices);我們再返回到第一段代碼看看。記住我們是怎樣繪制第一個三角形嗎?我們使用glColor4f()設(shè)置顏色并且說設(shè)置的顏色一直適用于隨后的代碼。那意味著定義于頂點(diǎn)數(shù)組中的物體必須用同一種顏色繪制。很有局限性,對嗎?并非如此。正如 OpenGL ES你將所有頂點(diǎn)置于一個數(shù)組中,它還你將每個頂點(diǎn)使用的顏色置于一個顏色數(shù)組(color array)中。如果你選擇使用顏色數(shù)組,那么你需要為每個頂點(diǎn)設(shè)置顏色(四個GLfloat值) 。

42、 通過下面方法啟動顏色數(shù)組:glEnableClientState(GL_COLOR_ARRAY);我們可以象頂點(diǎn)數(shù)組一樣定義一個包含四個GLfloat成員的 Color3D結(jié)構(gòu)。下面是怎樣為原始三角形分配不同顏色的示例:1.- (void)drawView:(GLView*)view;2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.Vertex3D Vertex3D Vertex3Dvertex1 = Vertex3DMake(0.0, 1.0, -3.0);vertex2 = Vertex3DMake(1.0, 0.0, -3.0);vertex3 =

43、 Vertex3DMake(-1.0, 0.0, -3.0);Triangle3D triangle = Triangle3DMake(vertex1, vertex2, vertex3);Color3D*colors = malloc(sizeof(Color3D) * 3);Color3DSet(>colors0, 1.0, 0.0, 0.0, 1.0);Color3DSet(>colors1, 0.0, 1.0, 0.0, 1.0);Color3DSet(>colors2, 0.0, 0.0, 1.0, 1.0);glLoadIdentity(); glClearCol

44、or(0.7, 0.7, 0.7, 1.0);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glColor4f(1.0, 0.0, 0.0, 1.0);19.20.21.22.23.24.25.26.27.glVertexPointer(3, GL_FLOAT, 0, >triangle); glColorPointer(4, GL_FLOAT, 0, colors); glDrawA

45、rrays(GL_TRIANGLES, 0, 9); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY);if (colors != NULL) free(colors);運(yùn)行,屏幕如下:今天我們還要討論一個話題。如果我們不止一次使用一個頂點(diǎn)(三角形條或三角形扇的相鄰頂點(diǎn)除外),我們至今使用的方法存在一個問題,我們必須多次向OpenGL傳遞同一頂點(diǎn)。那不是什么大問題,但通常我們需要盡量減少向OpenGL傳遞的數(shù)據(jù)量,所以一次又一次地傳遞同一個4字節(jié)浮點(diǎn)數(shù)是非常地不理想。在一些物體中,某個頂點(diǎn)會用

46、在七個甚至因此你的頂點(diǎn)數(shù)組可能會增大許多倍。的不同三角形中,當(dāng)處理這類復(fù)雜的幾何體時,有法可以避免多次傳遞同一個頂點(diǎn),就是使用通過頂點(diǎn)對應(yīng)于頂點(diǎn)數(shù)組中的索引的方法,此方法稱之為元素(elements)。其原理是創(chuàng)建一個每個頂點(diǎn)只使用一次的數(shù)組。然后使用另一個使用最小的無符號整型數(shù)的數(shù)組來保存所需的唯一頂點(diǎn)號。換句話說, 如果頂點(diǎn)數(shù)組具有小于256個頂點(diǎn),那么你應(yīng)創(chuàng)建一個GLubyte數(shù)組,如果大于 256,但小于 65,536,應(yīng)使用 GLushort。你可以通過頂點(diǎn)在第一個數(shù)組中的索引值來創(chuàng)建三角形(或其他形狀)。所以,如果你創(chuàng)建了一個具有12個頂點(diǎn)的數(shù)組,那么數(shù)組中的第一個頂點(diǎn)為0。你可以

47、按以前一樣的方法繪制圖形,只不過不是調(diào)用glDrawArrays(),而是調(diào)用不同的函數(shù) glDrawElements()并傳遞整數(shù)數(shù)組。讓我們以一個真實(shí)的,如假包換的3D形狀來結(jié)束我們的:一個二十面體。每個人都使用正方體,但我們要更怪異一點(diǎn),我們要畫一個二十面體。替換drawView:1.- (void)drawView:(GLView*)view;2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.static GLfloat rot = 0.0;/ This is the same result as using Verte

48、x3D, just faster to type and/ can be made const this way static const Vertex3D vertices= 0, -0.525731, 0.850651,0.850651, 0, 0.525731,0.850651, 0, -0.525731,-0.850651, 0, -0.525731,-0.850651, 0, 0.525731,-0.525731, 0.850651, 0,0.525731, 0.850651, 0,0.525731, -0.850651, 0,-0.525731, -0.850651, 0,0, -

49、0.525731, -0.850651,0, 0.525731, -0.850651,0, 0.525731, 0.850651;/ vertices0/ vertices1/ vertices2/ vertices3/ vertices4/ vertices5/ vertices6/ vertices7/ vertices8/ vertices9/ vertices10/ vertices11static const Color3D colors = 24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47

50、.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.66.1.0, 0.0, 0.0, 1.0,1.0, 0.5, 0.0, 1.0,1.0, 1.0, 0.0, 1.0,0.5, 1.0, 0.0, 1.0,0.0, 1.0, 0.0, 1.0,0.0, 1.0, 0.5, 1.0,0.0, 1.0, 1.0, 1.0,0.0, 0.5, 1.0, 1.0,0.0, 0.0, 1.0, 1.0,0.5, 0.0, 1.0, 1.0,1.0, 0.0, 1.0, 1.0,1.0, 0.0, 0.5, 1.0;static const G

51、Lubyte icosahedronFaces = 1, 2, 6,1, 7, 2,3, 4, 5,4, 3, 8,6, 5, 11,5, 6, 10,9, 10, 2,10, 9, 3,7, 8, 9,8, 7, 0,11, 0, 1,0, 11, 4,6, 2, 10,1, 6, 11,3, 5, 10,5, 4, 11,2, 7, 9,7, 1, 0,3, 9, 8,4, 8, 0,;glLoadIdentity(); glTranslatef(0.0f,0.0f,-3.0f); glRotatef(rot,1.0f,1.0f,1.0f); glClearColor(0.7, 0.7,

52、0.7, 1.0);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glEnableClientState(GL_VERTEX_ARRAY);67.68.69.70.71.glEnableClientState(GL_COLOR_ARRAY); glVertexPointer(3, GL_FLOAT, 0, vertices); glColorPointer(4, GL_FLOAT, 0, colors);glDrawElements(GL_TRIANGLES, 60, GL_UNSIGNED_BYTE, ic osahedronFaces

53、);72.73.74.75.76.77.78.glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); static NSTimeInterval lastDrawTime;if (lastDrawTime)NSTimeInterval timeSinceLastDraw = NSDate timeIntervalSinc eReferenceDate - lastDrawTime;rot+=50 * timeSinceLastDraw;lastDrawTime = NSDate timeIntervalSinceReferenceDate;79.80.81.82.運(yùn)行,屏幕上將看到一個漂亮的旋轉(zhuǎn)物體:因為我們沒有使用光源而且即使使用了光源我們也沒有告訴OpenGL怎樣進(jìn)行光源反射,所以它看上去還不是一個完美的3D物體。有關(guān)光線的部分將在后續(xù)文章中討論。這里我們做了什么?首先,我們建立了一個靜態(tài)變量來跟蹤物體的旋轉(zhuǎn)。static GLfloat rot = 0.0;然后我們定義頂點(diǎn)數(shù)組。我們使用了一個與前不同的方法,但結(jié)果是一樣的。其定義為const,這樣就不需要由于我們的幾何體根本每一幀都

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論