圖片渲染
- 新建一個ViewController繼承自GLKViewController
- 把這個控制器設(shè)置為根視圖,view改成基礎(chǔ)GLKView
- 導(dǎo)入相應(yīng)頭文件
#import <OpenGLES/ES3/gl.h>
#import <OpenGLES/ES3/glext.h>
setUpConfig
初始化上下文&設(shè)置當(dāng)前上下文
- 使用
OpenGL
做任何事前,你都需要先創(chuàng)建一個EAGLContext
返十。 -
iOS
使用OpenG
L進行繪制時需要一些信息奋刽,這些信息都由EAGLContext
管理旱函。這和你使用一個Core Graphics
上下文差不多应结。 - 當(dāng)你創(chuàng)建一個上下文時图毕,你需要定義要使用的
API
版本推励。
EAGLContext
是蘋果iOS
平臺下實現(xiàn)OpenGLES
渲染層.
1. `kEAGLRenderingAPIOpenGLES1` = 1, 固定管線
2. `kEAGLRenderingAPIOpenGLES2` = 2,
3. `kEAGLRenderingAPIOpenGLES3` = 3,
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
設(shè)置當(dāng)前上下文
[EAGLContext setCurrentContext:context];
獲取GLKView
& 設(shè)置context
- 這創(chuàng)建了一個新的
GLKView
的實例曲梗,并使它和整個window
一樣大。 - 當(dāng)你創(chuàng)建一個
GLKView
的時候弄跌,你需要告訴它要使用的OpenGL
上下文甲喝,所以配置成我們剛剛創(chuàng)建的context
。
GLKView *view = (GLKView *)self.view; view.context = context;
配置視圖創(chuàng)建的渲染緩存區(qū)
- drawableColorFormat: 顏色緩存區(qū)格式
- 簡介:
OpenGL ES
有一個緩存區(qū)铛只,它用以存儲將在屏幕中顯示的顏色埠胖。你可以使用其屬性來設(shè)置緩沖區(qū)中的每個像素的顏色格式。 -
GLKViewDrawableColorFormatRGBA8888
:此值為默認值淳玩,緩存區(qū)的每個像素的最小組成部分(RGBA)使用8個bit直撤,(所以每個像素4個字節(jié),4*8個bit)蜕着。 -
GLKViewDrawableColorFormatRGB565
:如果你的APP允許更小范圍的顏色谋竖,即可設(shè)置這個红柱。會讓你的APP
消耗更小的資源(內(nèi)存和處理時間)
-
drawableDepthFormat
(深度緩存區(qū)格式):如果你要使用這個屬性(一般用于3D
游戲),你應(yīng)該選擇GLKViewDrawableDepthFormat16
或GLKViewDrawableDepthFormat24
蓖乘。這里的差別是使用GLKViewDrawableDepthFormat16
將消耗更少的資源锤悄。
-
GLKViewDrawableDepthFormatNone
= 0:意味著完全沒有深度緩沖區(qū) GLKViewDrawableDepthFormat16
GLKViewDrawableDepthFormat24
view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
view.drawableDepthFormat = GLKViewDrawableDepthFormat16;
設(shè)置背景顏色
定義用來清理屏幕的RGB顏色
和alpha
(透明度)值。這里我們設(shè)置紅色
嘉抒。
glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
setUpVertexData
準(zhǔn)備數(shù)據(jù)
四邊形是有兩個三角形組成.
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, //左下
};
綁定數(shù)據(jù)
創(chuàng)建頂點緩存區(qū)標(biāo)識符ID
函數(shù)原型:
void glGenBuffers(GLsizei n,GLuint * buffers)
;
第一個參數(shù)
:要生成的緩沖對象的數(shù)量
第二個參數(shù)
:要輸入用來存儲緩沖對象名稱的數(shù)組
如果使用數(shù)組保存
GLuint bufferID[3];
glGenBuffers(3,bufferID);
- 單個
GLuint
數(shù)據(jù)
GLuint bufferID;
glGenTextures(1, &bufferID);
綁定頂點緩存區(qū)(明確作用)
函數(shù)原型:
void glBindBuffer(GLenum target,GLuint buffer)
;
第一個參數(shù)
:緩沖對象的類型
第二個參數(shù)
:要綁定的緩沖對象的名稱
- 使用該函數(shù)將緩沖對象綁定到
OpenGL
上下文環(huán)境中以便使用零聚。 - 如果把
target
綁定到一個已經(jīng)創(chuàng)建好的緩沖對象,那么這個緩沖對象將為當(dāng)前target
的激活對象些侍。 - 但是如果綁定的
buffer
值為0
隶症,那么OpenGL
將不再對當(dāng)前target
使用任何緩存對象。
glBindTexture(GL_ARRAY_BUFFER, bufferID);
OpenGL
允許我們同時綁定多個緩沖類型岗宣,只要這些緩沖類型是不同的蚂会,換句話說,同一時間耗式,不能綁定兩個相同類型的緩沖對象颂龙。也可以理解為對于一個類型來說,同一時間只能“激活”一個類型纽什,否則就會發(fā)生“矛盾”
措嵌。
第二個參數(shù)雖然是GLuint
類型的,但是你萬萬不能直接指定個常量比如說0
芦缰,否則會出現(xiàn)GL_INVALID_VALUE
的錯誤企巢,具體如下:
GL_INVALID_VALUE is generated if buffer is not a name previously returned form a call to glGenBuffers
將頂點數(shù)組的數(shù)據(jù)copy
到頂點緩存區(qū)中(GPU
顯存中)
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);
插槽重識(打開讀取通道)
GLKit
目標(biāo)就是簡化, 里面有很多對OpenGLES
的封裝, 我們也可以不用進行shader
的編輯, 不用在寫glsl
就能完成shader
的繪制
GLKVertexAttribPosition
就是position
位置插槽,
GLKVertexAttribColor
就是color
位置插槽,
GLKVertexAttribTexCoord0
就是texcoord0
位置插槽,
-
glEnableVertexAttribArray
:在iOS
中, 默認情況下,出于性能考慮让蕾,所有頂點著色器的屬性(Attribute
)變量都是關(guān)閉的浪规。
意味著,頂點數(shù)據(jù)在著色器端(服務(wù)端)是不可用的。即使你已經(jīng)使用
glBufferData
方法探孝,將頂點數(shù)據(jù)從內(nèi)存拷貝到頂點緩存區(qū)中(GPU
顯存中)笋婿。
所以, 必須由
glEnableVertexAttribArray
方法打開通道。指定訪問屬性顿颅,才能讓頂點著色器能夠訪問到從CPU
復(fù)制到GPU
的數(shù)據(jù)缸濒。
注意: 數(shù)據(jù)在
GPU
端是否可見,即粱腻,著色器能否讀取到數(shù)據(jù)庇配,由是否啟用了對應(yīng)的屬性決定,這就是glEnableVertexAttribArray
的功能绍些,允許頂點著色器讀取GPU
(服務(wù)器端)數(shù)據(jù)捞慌。
- glVertexAttribPointer
函數(shù)原型:
glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr)
功能:上傳頂點數(shù)據(jù)到顯存的方法(設(shè)置合適的方式從buffer里面讀取數(shù)據(jù))
參數(shù)列表:
-
index
:指定要修改的頂點屬性的索引值 -
size
:每次讀取數(shù)量。(如position
是由3個(x,y,z
)組成柬批,而顏色是4個(r,g,b,a
),紋理則是2個.) -
type
:指定數(shù)組中每個組件的數(shù)據(jù)類型啸澡⌒涠可用的符號常量有GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT,GL_UNSIGNED_SHORT, GL_FIXED, 和GL_FLOAT,初始值為GL_FLOAT
嗅虏。
4.normalized
:指定當(dāng)被訪問時著角,固定點數(shù)據(jù)值是否應(yīng)該被歸一化(GL_TRUE
)或者直接轉(zhuǎn)換為固定點值(GL_FALSE
) -
stride
:指定連續(xù)頂點屬性之間的偏移量。如果為0
旋恼,那么頂點屬性會被理解為:它們是緊密排列在一起的。初始值為0
-
ptr
:指定一個指針奄容,指向數(shù)組中第一個頂點屬性的第一個組件冰更。初始值為0
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (GLfloat *)NULL + 0);
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (GLfloat *)NULL + 3);
- (GLfloat *)NULL null值包裝為0
- (GLfloat *)NULL + 3 起始位置
- 乘以5直接間隔
setUpTexture
紋理矩陣
- 獲取紋理圖片路徑
NSString *filePath = [[NSBundle mainBundle]pathForResource:@"test" ofType:@"jpg"];
- 設(shè)置紋理參數(shù)
由于紋理坐標(biāo)系是跟手機顯示的Quartz 2D坐標(biāo)系的y軸正好相反,紋理坐標(biāo)系使用左下角為原點昂勒,往
上為y軸的正值
蜀细,往右是x軸的正值
,所以需要設(shè)置一下GLKTextureLoaderOriginBottomLeft
戈盈。
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:@(1),GLKTextureLoaderOriginBottomLeft, nil];
GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithContentsOfFile:filePath options:options error:nil];
- 使用蘋果
GLKit
提供GLKBaseEffect
完成著色器工作(頂點/片元)
eEffect = [[GLKBaseEffect alloc] init];
eEffect.texture2d0.enabled = GL_TRUE;
eEffect.texture2d0.name = textureInfo.name;
- 繪制
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect{
glClear(GL_COLOR_BUFFER_BIT);
[eEffect prepareToDraw];
glDrawArrays(GL_TRIANGLES, 0, 6);
}
效果圖
下來做一個立方體的貼圖,并旋轉(zhuǎn).
準(zhǔn)備工作
立方體和單個四邊形區(qū)別,多了
5
個面,定點數(shù)也有原來的6
個變成36個.
- 首先創(chuàng)建需要的類已經(jīng)一個
OPVertex
來存放頂點和紋理頂點.
ypedef struct OPVertex{
GLKVector3 positionCoord;//頂點坐標(biāo)
GLKMatrix2 texturecoord; //紋理
}OPVertex;
//總共頂點數(shù)
static int const kCoordCount = 36;
EAGLContext *context; //上下文
GLKBaseEffect *cEffect;// 著色器
NSInteger angle; //記錄旋轉(zhuǎn)的角度
GLKView *glkView; //glkView
@property(nonatomic, assign) OPVertex *vertices;
繪制
- 初始化上下文&設(shè)置當(dāng)前上下文,設(shè)置渲染區(qū)和背景顏色
這一步和之前繪制沒有變化
-(void)setUpConfig
{
context = [[EAGLContext alloc]initWithAPI:kEAGLRenderingAPIOpenGLES3];
//判斷context是否創(chuàng)建成功
if (!context) {
NSLog(@"Create ES context Failed");
}
//設(shè)置當(dāng)前上下文
[EAGLContext setCurrentContext:context];
//2.獲取GLKView & 設(shè)置context
GLKView *view =(GLKView *) self.view;
view.context = context;
//3.配置視圖創(chuàng)建的渲染緩存區(qū).
view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
view.drawableDepthFormat = GLKViewDrawableDepthFormat16;
glkView = view;
//4.設(shè)置背景顏色
glClearColor(1, 0, 0, 1.0);
}
- 加載頂點/紋理坐標(biāo)數(shù)據(jù)
- 使用
malloc
分配內(nèi)存
self.vertices = malloc(sizeof(OPVertex) * kCoordCount);
- 6個面對應(yīng)的頂點和紋理坐標(biāo)
// 前面
self.vertices[0] = (OPVertex){{-0.5, 0.5, 0.5}, {0, 1}};
self.vertices[1] = (OPVertex){{-0.5, -0.5, 0.5}, {0, 0}};
self.vertices[2] = (OPVertex){{0.5, 0.5, 0.5}, {1, 1}};
self.vertices[3] = (OPVertex){{-0.5, -0.5, 0.5}, {0, 0}};
self.vertices[4] = (OPVertex){{0.5, 0.5, 0.5}, {1, 1}};
self.vertices[5] = (OPVertex){{0.5, -0.5, 0.5}, {1, 0}};
// 上面
self.vertices[6] = (OPVertex){{0.5, 0.5, 0.5}, {1, 1}};
self.vertices[7] = (OPVertex){{-0.5, 0.5, 0.5}, {0, 1}};
self.vertices[8] = (OPVertex){{0.5, 0.5, -0.5}, {1, 0}};
self.vertices[9] = (OPVertex){{-0.5, 0.5, 0.5}, {0, 1}};
self.vertices[10] = (OPVertex){{0.5, 0.5, -0.5}, {1, 0}};
self.vertices[11] = (OPVertex){{-0.5, 0.5, -0.5}, {0, 0}};
// 下面
self.vertices[12] = (OPVertex){{0.5, -0.5, 0.5}, {1, 1}};
self.vertices[13] = (OPVertex){{-0.5, -0.5, 0.5}, {0, 1}};
self.vertices[14] = (OPVertex){{0.5, -0.5, -0.5}, {1, 0}};
self.vertices[15] = (OPVertex){{-0.5, -0.5, 0.5}, {0, 1}};
self.vertices[16] = (OPVertex){{0.5, -0.5, -0.5}, {1, 0}};
self.vertices[17] = (OPVertex){{-0.5, -0.5, -0.5}, {0, 0}};
// 左面
self.vertices[18] = (OPVertex){{-0.5, 0.5, 0.5}, {1, 1}};
self.vertices[19] = (OPVertex){{-0.5, -0.5, 0.5}, {0, 1}};
self.vertices[20] = (OPVertex){{-0.5, 0.5, -0.5}, {1, 0}};
self.vertices[21] = (OPVertex){{-0.5, -0.5, 0.5}, {0, 1}};
self.vertices[22] = (OPVertex){{-0.5, 0.5, -0.5}, {1, 0}};
self.vertices[23] = (OPVertex){{-0.5, -0.5, -0.5}, {0, 0}};
// 右面
self.vertices[24] = (OPVertex){{0.5, 0.5, 0.5}, {1, 1}};
self.vertices[25] = (OPVertex){{0.5, -0.5, 0.5}, {0, 1}};
self.vertices[26] = (OPVertex){{0.5, 0.5, -0.5}, {1, 0}};
self.vertices[27] = (OPVertex){{0.5, -0.5, 0.5}, {0, 1}};
self.vertices[28] = (OPVertex){{0.5, 0.5, -0.5}, {1, 0}};
self.vertices[29] = (OPVertex){{0.5, -0.5, -0.5}, {0, 0}};
// 后面
self.vertices[30] = (OPVertex){{-0.5, 0.5, -0.5}, {0, 1}};
self.vertices[31] = (OPVertex){{-0.5, -0.5, -0.5}, {0, 0}};
self.vertices[32] = (OPVertex){{0.5, 0.5, -0.5}, {1, 1}};
self.vertices[33] = (OPVertex){{-0.5, -0.5, -0.5}, {0, 0}};
self.vertices[34] = (OPVertex){{0.5, 0.5, -0.5}, {1, 1}};
self.vertices[35] = (OPVertex){{0.5, -0.5, -0.5}, {1, 0}};
- 開辟頂點緩存區(qū)
GLuint bufferID;
glGenBuffers(1, &bufferID);
//(2).綁定頂點緩存區(qū).(明確作用)
glBindBuffer(GL_ARRAY_BUFFER, bufferID);
//(3).將頂點數(shù)組的數(shù)據(jù)copy到頂點緩存區(qū)中(GPU顯存中)
glBufferData(GL_ARRAY_BUFFER, sizeof(OPVertex) * kCoordCount, self.vertices, GL_STATIC_DRAW);
// 頂點坐標(biāo)數(shù)據(jù)
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(OPVertex) , offsetof(OPVertex, positionCoord) + NULL);
//紋理坐標(biāo)數(shù)據(jù)
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(OPVertex), offsetof(OPVertex, texturecoord) + NULL);
sizeof(OPVertex) * kCoordCount
傳入內(nèi)容的大小
offsetof(OPVertex, positionCoord) + NULL
,對應(yīng)頂點或者紋理起始點的內(nèi)存偏移值
- 加載紋理數(shù)據(jù)
{
//1.獲取紋理圖片路徑
NSString *filePath = [[NSBundle mainBundle]pathForResource:@"test" ofType:@"jpg"];
//2.設(shè)置紋理參數(shù)
//紋理坐標(biāo)原點是左下角,但是圖片顯示原點應(yīng)該是左上角.
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:@(1),GLKTextureLoaderOriginBottomLeft, nil];
GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithContentsOfFile:filePath options:options error:nil];
//3.使用蘋果GLKit 提供GLKBaseEffect 完成著色器工作(頂點/片元)
cEffect = [[GLKBaseEffect alloc]init];
cEffect.texture2d0.enabled = GL_TRUE;
cEffect.texture2d0.name = textureInfo.name;
cEffect.texture2d0.target = textureInfo.target;
[self setTimer];
}
cEffect.texture2d0.target = textureInfo.target;
將目標(biāo)對象交給cEffect
;
[self setTimer];
開啟一個定時器
- 開始定時器
- (void)setTimer{
NSTimer* timer = [NSTimer timerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
[self transforms];
}];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
}
- (void)transforms{
angle = (angle + 10) % 360;
//使用模型矩陣
cEffect.transform.modelviewMatrix = GLKMatrix4MakeRotation(GLKMathDegreesToRadians(angle), 0.3, 1, -1.7);
//重新繪制
[glkView display];
}
- 繪制
#pragma mark -- GLKViewDelegate
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
//1.清屏
glClear(GL_COLOR_BUFFER_BIT);
//2.準(zhǔn)備繪制
[cEffect prepareToDraw];
//3.開始繪制
glDrawArrays(GL_TRIANGLES, 0, 36);
}
這里
36
繪制的定點數(shù).
效果圖
:
總結(jié)
-
OpenGL ES 相關(guān)初始化
- 初始化上下文&設(shè)置當(dāng)前上下文
- 獲取GLKView & 設(shè)置context
- 配置視圖創(chuàng)建的渲染緩存區(qū)
- 設(shè)置背景顏色
-
加載頂點/紋理坐標(biāo)數(shù)據(jù)
- 設(shè)置頂點數(shù)組(頂點坐標(biāo),紋理坐標(biāo))
- 開辟頂點緩存區(qū)
- 創(chuàng)建頂點緩存區(qū)標(biāo)識符ID
- 綁定頂點緩存區(qū).(明確作用)
- 將頂點數(shù)組的數(shù)據(jù)copy到頂點緩存區(qū)中(GPU顯存中)
- 打開讀取通道.
- 上傳頂點數(shù)據(jù)到顯存的方法
-
加載紋理數(shù)據(jù)(使用GLBaseEffect)
- 獲取紋理圖片路徑
- 設(shè)置紋理參數(shù)
- 使用蘋果GLKit 提供GLKBaseEffect 完成著色器工作(頂點/片元)
-
繪制視圖的內(nèi)容(GLKViewDelegate)
- 清屏
- 準(zhǔn)備繪制
- 開始繪制
GLKBaseEffect使用小結(jié):
- 創(chuàng)建一個
GLKBaseEffect
奠衔。通常當(dāng)你創(chuàng)建OpenGL
上下文的時候,你都會創(chuàng)建一個塘娶。對于不同的幾何圖形归斤,你可以(或者說應(yīng)該)重用相同的GLKBaseEffect
,只是要重新設(shè)置其屬性刁岸。在后臺脏里,GLKBaseEffect
只會向它的著色器傳播剛剛變化的屬性。 - 設(shè)置
GLKBaseEffect
的屬性虹曙。這里你可以配置光迫横,轉(zhuǎn)化,和其他GLKBaseEffect
的著色器用來渲染幾何圖形的屬性酝碳。 - 調(diào)用G
LKBaseEffect
的prepareToDraw
方法矾踱。任何時候如果你改變了GLKBaseEffect
的一個屬性,你都要先調(diào)用prepareToDraw
方法讓著色器得到正確的配置疏哗。這也讓GLKBaseEffect
的著色器作為“當(dāng)前”的著色器程序(就是讓GLKBaseEffect
的著色器起作用)呛讲。 - 使能預(yù)定義屬性。通常當(dāng)你使用自定義著色器時返奉,他們會使用稱為屬性的參數(shù)圣蝎,你要寫代碼獲得它們的
ID
。對于GLKBaseEffect
的內(nèi)建著色器衡瓶,這些屬性已經(jīng)用常量值預(yù)先定義好了徘公,比如GLKVertexAttribPosition
或者GLKVertexAttribColor
。所以你要使能所有需要傳給著色器的參數(shù)哮针,并保證他們指向了數(shù)據(jù)关面。 - 繪制你的幾何圖形坦袍。一旦你東西要配置,你都可以使用普通的
OpenGL
繪圖指令等太,比如glDrawArrays
或者glDrawElements
捂齐,它會使用你剛剛配置好的效果進行渲染!
GLKBaseEffect
的好處是如果你使用它們缩抡,你根本就不需要去寫任何的著色器,