OpenGL ES 入門 — 1.HelloWorld 繪制圖片

> 作為入門的小Demo,先帶大家學習怎樣在屏幕上渲染一張圖片。

其實很簡單:

先定義兩個屬性。

```

EAGLContext *context; //EAGLContent是蘋果在ios平臺下實現(xiàn)的opengles渲染層,用于渲染結(jié)果在目標surface上的更新。

GLKBaseEffect *mEffect;//著色器或者光照

```

在viewDidLoad中調(diào)用自定義方法。

```

- (void)viewDidLoad {

? ? [super viewDidLoad];

? ? //1.設置OpenGL ES 配置

? ? [self setUpConfig];

? ? //2.加載頂點數(shù)據(jù)

? ? [self uploadVertexArray];

? ? //3.加載紋理

? ? [self uploadTexture];

}

```

# 1. 設置OpenGL ES 配置

由于OpenGL ES 沒有提供窗口層,托管系統(tǒng)(iOS、安卓)必須提供函數(shù)來創(chuàng)建一個能夠接受OpenGL ES命令的渲染上下文,以及寫入任何繪制命令結(jié)果的緩沖區(qū)。

```

//新建OpenGL ES上下文

? ? context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];//這里用的是opengles3.

? ? if (!context) {

? ? ? ? NSLog(@"創(chuàng)建上下文失敗!");

? ? ? ? return;

? ? }

```

`EAGLContent`就是接受OpenGL ES命令的渲染上下文,是蘋果在ios平臺下實現(xiàn)的OpenGL ES渲染層,用于渲染結(jié)果在目標surface上的更新。

其中初始化參數(shù)API有以下幾種:

- kEAGLRenderingAPIOpenGLES1 ->OpenGL ES 1.0,固定管線。

- kEAGLRenderingAPIOpenGLES2 ->OpenGL ES 2.0,非固定管線。

- kEAGLRenderingAPIOpenGLES3 ->OpenGL ES 3.0,也是非固定管線,比2.0多了一些API而已。

接下來將context綁定到view上,這里需要在storyBoard中把控制器的view改為GLKView,當然如果你要用storyBoard的話。

![修改viewController中的view](https://upload-images.jianshu.io/upload_images/1477238-83f2f57f0c16dcb9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

```

//創(chuàng)建一個OpenGL ES上下文并將其分配給從storyboard加載的視圖

GLKView * view? = (GLKView *)self.view;

view.context = context;

```

同時,配置視圖創(chuàng)建所需要的渲染緩沖區(qū),有四個緩沖區(qū)可以設置:

- 顏色緩沖區(qū),它用以存儲將在屏幕中顯示的顏色。你可以使用GLKView的`drawableColorFormat`屬性來設置緩沖區(qū)中的每個像素的顏色格式。

```

view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;

```

GLKViewDrawableColorFormatRGBA8888:即緩存區(qū)的每個像素的最小組成部分(RGBA)使用8個bit,所以每個像素4個字節(jié),4*8個bit,默認格式。

GLKViewDrawableColorFormatRGB565:如果你的APP允許更小范圍的顏色,即可設置這個。會讓你的APP消耗更小的資源(內(nèi)存和處理時間)。

- 深度緩沖區(qū),保存深度值,OpenGL在深度測試時會把接近觀察者的對象的所有像素存儲到深度緩沖區(qū),當開始繪制一個像素時,OpenGL首先檢查深度緩沖區(qū),看是否已經(jīng)繪制了更接近觀察者的什么東西,如果是則忽略它,不用繪制它了,否則把它增加到深度緩沖區(qū)和顏色緩沖區(qū)進行繪制處理。

通過`drawableDepthFormat`屬性設置深度緩沖區(qū)。

```

view.drawableDepthFormat = GLKViewDrawableDepthFormat24;

```

GLKViewDrawableDepthFormatNone:完全沒有深度緩沖區(qū)。

GLKViewDrawableDepthFormat16:用于一般簡單的2D場景中,將消耗更少的資源,但是當對象非常接近彼此時,你可能存在渲染問題。

GLKViewDrawableDepthFormat24: 用于3D游戲。

- stencil(模板)緩沖區(qū),它幫助你把繪制區(qū)域限定到屏幕的一個特定部分。它還用于像影子一類的事物,比如你可以使用stencil緩沖區(qū)確保影子投射到地板。

```

view.drawableStencilFormat = GLKViewDrawableStencilFormat8;

```

GLKViewDrawableStencilFormatNone:沒有stencil緩沖區(qū)。

GLKViewDrawableStencilFormat8。

- 多重采樣緩沖區(qū),用于抗鋸齒,它將一個像素分成更小的單元, 并在更細微的層面上多次調(diào)用fragment shader,之后它將返回的顏色合并,生成更光滑的幾何邊緣效果,但是該屬性比較占用內(nèi)存,耗時。

```

view.drawableMultisample = GLKViewDrawableMultisample4X;

```

GLKViewDrawableMultisampleNone:沒有多重采樣緩沖區(qū)。

GLKViewDrawableMultisample4X。

```

[EAGLContext setCurrentContext:context]; //設置當前緩沖區(qū)。

glEnable(GL_DEPTH_TEST); //開啟深度測試,就是讓離你近的物體可以遮擋離你遠的物體。

glClearColor(0.1, 0.2, 0.3, 1); //設置surface的清除顏色,也就是渲染到屏幕上的背景色。

```

# 2. 加載頂點數(shù)據(jù)

```

//頂點數(shù)據(jù),前三個是頂點坐標(x、y、z軸),后面兩個是紋理坐標(x,y)

GLfloat vertexData[] = {

? ? ? ? 0.5, -0.5, 0.0f,? ? 1.0f, 0.0f, //右下

? ? ? ? 0.5, 0.5, -0.0f,? ? 1.0f, 1.0f, //右上

? ? ? ? -0.5, 0.5, 0.0f,? ? 0.0f, 1.0f, //左上

? ? ? ? 0.5, -0.5, 0.0f,? ? 1.0f, 0.0f, //右下

? ? ? ? -0.5, 0.5, 0.0f,? ? 0.0f, 1.0f, //左上

? ? ? ? -0.5, -0.5, 0.0f,? 0.0f, 0.0f, //左下

? ? };

```

頂點坐標,OpenGLES的世界坐標系是[-1, 1],故而點(0, 0)是在屏幕的正中間。

紋理坐標系的取值范圍是[0, 1],原點是在左下角。故而點(0, 0)在左下角,點(1, 1)在右上角。

開啟頂點緩沖區(qū):

```

//頂點緩存區(qū)

? ? GLuint buffer;

? ? //申請一個緩存區(qū)標識符

? ? glGenBuffers(1, &buffer);

? ? //glBindBuffer把標識符綁定到GL_ARRAY_BUFFER上

? ? glBindBuffer(GL_ARRAY_BUFFER, buffer);

? ? //glBufferData把頂點數(shù)據(jù)從CPU內(nèi)存復制到GPU內(nèi)存

? ? glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);

```

開啟對應的頂點屬性:

```

glEnableVertexAttribArray(GLKVertexAttribPosition);

```

默認情況下,出于性能考慮,所有頂點著色器的屬性(Attribute)變量都是disable的,意味著哪怕數(shù)據(jù)已經(jīng)上傳到GPU,頂點著色器也不能讀取到數(shù)據(jù)。由`glEnableVertexAttribArray`啟用指定屬性,才可在頂點著色器中訪問頂點的屬性數(shù)據(jù)。

設置合適的格式從buffer里面讀取數(shù)據(jù):

```

glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (GLfloat *)NULL + 0);

```

glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr)

是用來上傳頂點數(shù)據(jù)到顯卡的方法。

參數(shù)解釋:

- indx: 指定要修改的頂點屬性的索引值

- size : 指定每個頂點屬性的組件數(shù)量。必須為1、2、3或者4。初始值為4。(如position是由3個(x,y,z)組成,而顏色是4個(r,g,b,a))

- type : 指定數(shù)組中每個組件的數(shù)據(jù)類型。可用的符號常量有GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT,GL_UNSIGNED_SHORT, GL_FIXED, 和 GL_FLOAT,初始值為GL_FLOAT。

- normalized : 指定當被訪問時,固定點數(shù)據(jù)值是否應該被歸一化(GL_TRUE)或者直接轉(zhuǎn)換為固定點值(GL_FALSE)

- stride : 指定連續(xù)頂點屬性之間的偏移量。如果為0,那么頂點屬性會被理解為:它們是緊密排列在一起的。初始值為0

- ptr? ? : 就是一個指針,指向的是需要上傳到頂點數(shù)據(jù)指針,通常是數(shù)組名的偏移量,指向數(shù)組中第一個頂點屬性的第一個組件,上面(GLfloat *)NULL + 0 指針,指向數(shù)組首地址。

開啟紋理的頂點屬性:

```

glEnableVertexAttribArray(GLKVertexAttribTexCoord0);

```

通過(GLfloat *)NULL + 3,指到紋理數(shù)據(jù):

```

glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (GLfloat * )NULL + 3);

```

# 3. 加載紋理

```

-(void)uploadTexture

{

? ? //獲取紋理圖片保存路徑

? ? NSString *filePath = [[NSBundle mainBundle]pathForResource:@"sf" ofType:@"jpg"];

? ? //GLKTextureLoaderOriginBottomLeft,紋理坐標是相反的

? ? NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:@(1), GLKTextureLoaderOriginBottomLeft,NULL];

? ? GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithContentsOfFile:filePath options:options error:NULL];

? ? //著色器

? ? mEffect = [[GLKBaseEffect alloc]init];

? ? //第一個紋理屬性

? ? mEffect.texture2d0.enabled = GL_TRUE;

? ? //紋理的名字

? ? mEffect.texture2d0.name = textureInfo.name;

}

```

# 4. 在GLKViewDelegate的代理方法中啟動著色器

```

-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect

{

? ? glClearColor(0.3f, 0.6f, 1.0f, 1.0f);

? ? //清除surface內(nèi)容,恢復至初始狀態(tài)

? ? glClear(GL_DEPTH_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

? ? //啟動著色器

? ? [mEffect prepareToDraw];

? ? glDrawArrays(GL_TRIANGLES, 0, 6);

}

```

最后完成效果:

![那年夕陽下的奔跑,那是我逝去的青春](https://upload-images.jianshu.io/upload_images/1477238-7ca98d62ab688930.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

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