OpenGL ES
-
OpenGL ES是OpenGL的子集 - 是針對(duì)嵌入式設(shè)備及移動(dòng)終端設(shè)備的高級(jí)3D圖形應(yīng)用程序,例如iOS、Android、Windows等
-
OpenGL ES是跨平臺(tái)的,不會(huì)提供窗口相關(guān)方法,需要系統(tǒng)各自提供載體
OpenGL ES渲染流程

OpenGL ES的渲染主要分為兩部分:CPU和GPU
CPU部分
- app代碼通過OpenGL ES API,會(huì)調(diào)度OpenGL ES Framework
- 通過OpenGL ES client 調(diào)度 OpenGL ES server,將頂點(diǎn)數(shù)據(jù)等傳遞到GPU
GPU部分
- 做一些圖形硬件的處理,例如光柵化、顯示等
OpenGL ES 圖形管道

- API獲得頂點(diǎn)數(shù)據(jù),將頂點(diǎn)數(shù)據(jù)從內(nèi)存中拷貝至頂點(diǎn)緩沖區(qū)(顯存)
- 拿到數(shù)據(jù)之后,通過attribute通道傳遞至頂點(diǎn)著色器,同時(shí),紋理坐標(biāo)通過Texture通道傳遞到頂點(diǎn)著色器和片元著色器
- 然后,圖元裝配,即圖元的連接方式,一共有9種,常用的有6種,此步驟將頂點(diǎn)變換為圖形
- 光柵化:確定圖形與屏幕對(duì)應(yīng)的位置
- 片元/片段/像素著色器:處理對(duì)應(yīng)像素點(diǎn)的顏色值
- 在將處理好的每個(gè)像素點(diǎn)的顏色值存儲(chǔ)到幀緩存區(qū),然后在顯示器中顯示
- API:可以通過API操作頂點(diǎn)緩沖區(qū)、頂點(diǎn)著色器、紋理坐標(biāo)、片段著色器
下面附上蘋果官方文檔圖示,原理都是一致的,只是描述方式不同。

- App:提供圖元裝配頂點(diǎn)信息,圖片信息
- Vertex(頂點(diǎn)著色器):處理頂點(diǎn) -- 圖形變換(旋轉(zhuǎn)、縮放、平移)
- Geometry(圖元裝配):圖元裝配 + 裁剪(超出屏幕部分被裁剪)
- Fragment(片元著色器):紋理處理 + 霧化處理
- Framebuffer Operation(幀緩沖區(qū)):透明度混合、模板、深度測(cè)試;最后在混合,這些操作都是在即將顯示時(shí),在幀緩沖區(qū)中完成的動(dòng)作
頂點(diǎn)著色器 (vertex shader)

- 輸入,有3種方式
- 通過
attribute通道輸入頂點(diǎn)數(shù)據(jù),提供每個(gè)頂點(diǎn)的數(shù)據(jù) - 通過
uniform通道輸入統(tǒng)一變量,即頂點(diǎn)/片元著色器中使用的不變的數(shù)據(jù) - 采樣器:表示頂點(diǎn)著色器使用紋理的特殊統(tǒng)一變量類型
- 通過
- 輸出:經(jīng)過處理的最終頂點(diǎn)數(shù)據(jù),有2種
-
gl_Position,是GLSL 的內(nèi)建變量,是將處理后的最終頂點(diǎn)數(shù)據(jù)賦值給它 -
gl_PointSize,是指點(diǎn)的尺寸,即可以在頂點(diǎn)著色器中修改每個(gè)點(diǎn)的大小,使用率較低
-
頂點(diǎn)著色器的業(yè)務(wù)內(nèi)容:
1.矩陣變換位置
2.計(jì)算光照公式?成逐頂點(diǎn)顏?
3.?成/變換紋理坐標(biāo)
總結(jié): 它可以?于執(zhí)行?自定義計(jì)算,實(shí)施新的變換,照明或者傳統(tǒng)的固定功能所不允許 的基于頂點(diǎn)的效果。
頂點(diǎn)著色器GLSL代碼示例:
attribute、uniform 表示client與server之間的通道
其中的vec4、vec2都是向量類型,表示四維向量和二維向量
mat4:4*4矩陣
varying是修飾符:通過varying將紋理坐標(biāo)傳入到片元著色器
lowp:低精讀
main中的操作
實(shí)現(xiàn)了紋理坐標(biāo)的橋接
實(shí)現(xiàn)了頂點(diǎn)旋轉(zhuǎn)矩陣的相乘:列向量 與 列矩陣 相乘,得到旋轉(zhuǎn)后的頂點(diǎn)坐標(biāo)
將上述得到的頂點(diǎn)坐標(biāo),賦值給gl_Position
*********************************************************
attribute vec4 position;
attribute vec2 textCoordinate;
uniform mat4 rotateMatrix;
varying lowp vec2 varyTextCoord;
void main()
{
varyTextCoord = textCoordinate;
vec4 vPos = position;
vPos = vPos * rotateMatrix;
gl_Position = vPos;
}
圖元裝配
頂點(diǎn)著?器之后,下?個(gè)階段就是圖元裝配.
圖元(Primitive): 點(diǎn),線,三?角形等.
圖元裝配: 將頂點(diǎn)數(shù)據(jù)計(jì)算成?個(gè)個(gè)圖元.在這個(gè)階段會(huì)執(zhí)?裁剪、透視分割和 Viewport變換操作。
圖元類型和頂點(diǎn)索確定將被渲染的單獨(dú)圖元。對(duì)于每個(gè)單獨(dú)圖元及其對(duì)應(yīng)的頂點(diǎn),圖元裝配階段執(zhí)行的操作包括:將頂點(diǎn)著?器的輸出值執(zhí)?裁剪、透視分割、視?變換后進(jìn)?入光柵化階段。
光柵化
將圖元轉(zhuǎn)化為一組二維片段的過程,主要是由于屏幕是2D的,所以轉(zhuǎn)換的像素點(diǎn)也是二維的

片源著色器(fragment shader)

- 輸入同頂點(diǎn)著色器一樣,有3種方式
- 由頂點(diǎn)著色器橋接傳遞過來的紋理坐標(biāo)等
- 通過
uniform通道輸入統(tǒng)一變量,即頂點(diǎn)/片元著色器中使用的不變的數(shù)據(jù) - 采樣器:表示頂點(diǎn)著色器使用紋理的特殊統(tǒng)一變量類型,例如紋理就是通過采樣器傳遞
- 輸出:某個(gè)像素點(diǎn)經(jīng)過片元著色器處理后的結(jié)果。
片元著色器的業(yè)務(wù)內(nèi)容:
1.計(jì)算顏色
2.獲取紋理值
3.往像素點(diǎn)中填充顏色值(紋理值/顏色值)
總結(jié): 它可以?于圖片/視頻/圖形中每個(gè)像素的顏?填充(?如給視頻添加濾鏡,實(shí)際上就是將視頻中每個(gè)圖?的像素點(diǎn)顏?填充進(jìn)行修改.)
片元著色器GLSL代碼示例
varying:必須和頂點(diǎn)著色器中一模一樣,這樣才能傳遞紋理坐標(biāo)
sampler2D 采樣器類型
texture2D(紋理采樣器,紋理坐標(biāo)):獲取對(duì)應(yīng)位置/坐標(biāo)的顏色值,簡稱獲得紋素
gl_FragColor(內(nèi)建變量):將最終的顏色值賦值給它
*********************************************************
varying lowp vec2 varyTextCoord;
uniform sampler2D colorMap;
void main() {
gl_FragColor = texture2D(colorMap, varyTextCoord); }
逐片段操作
這個(gè)過程都是GPU內(nèi)部處理的,開發(fā)者并不需要關(guān)心,將處理好的數(shù)據(jù)存儲(chǔ)到幀緩存區(qū),最后讀取幀緩存區(qū)將圖形顯示到屏幕上

- 像素歸屬測(cè)試: 確定幀緩存區(qū)中位置(Xw,Yw)的像素?前是不是歸屬于OpenGL ES所 有. 例如,如果一個(gè)顯示OpenGL ES幀緩存區(qū)View被另外一個(gè)View 所遮蔽.則窗口系統(tǒng)可以確定被遮蔽的像素不屬于OpenGL ES上下文.從而不全顯示這些像素.而像素歸屬測(cè)試是OpenGL ES 的?部分,它不由開發(fā)者開人為控制,?是由OpenGL ES內(nèi)部進(jìn)?.
- 裁剪測(cè)試: 裁剪測(cè)試確定(Xw,Yw)是否位于作為OpenGL ES狀態(tài)的?部分裁剪矩形范圍內(nèi).如果該?段位于裁剪區(qū)域之外,則被拋棄.
- 深度測(cè)試: 輸?片段的深度值進(jìn)步?較,確定?段是否拒絕測(cè)試
- 混合: 混合將新生成的?段顏色與保存在幀緩存的位置的顏色值組合起來.
- 抖動(dòng): 抖動(dòng)可?于最?化因?yàn)槭?有限精度在幀緩存區(qū)中保存顏?值?產(chǎn)生的偽像.
OpenGL ES的應(yīng)用
圖片濾鏡
- 獲取圖片中的每一個(gè)像素點(diǎn)
- 像素點(diǎn)做飽和度處理
- 得到新的顏色
- 將新的顏色翻入幀緩存區(qū)
- 最后進(jìn)行顯示
視頻濾鏡
原理以及處理方式是一樣的(GLSL代碼),視頻也是一幀一幀處理的,而一幀就是一張圖片
- 獲得視頻MP4文件
- 拿到h264(視頻壓縮文件) -
- 將視頻解碼(解壓),還原成一幀一幀的圖片
- 針對(duì)一幀一幀的圖片進(jìn)行處理
EGL(Embedded Graphics Library)
-
OpenGL ES命令需要渲染上下?和繪制表面才能完成圖形圖像的繪制
渲染上下?: 存儲(chǔ)相關(guān)OpenGL ES狀態(tài),是一個(gè)狀態(tài)機(jī) - 繪制表面:?于繪制圖元的表面,需要指定渲染的緩存區(qū),例如顏?緩、深度和模板
-
OpenGL ES API并沒有提供如何創(chuàng)建渲染上下文或者上下文如何連接到原生窗口系 統(tǒng).EGL是Khronos渲染API(如OpenGL ES) 和原?窗?系統(tǒng)之間的接?. 唯?支持OpenGL ES卻不支持EGL的平臺(tái)是iOS.Apple提供?己的EGL API的iOS實(shí)現(xiàn),稱為EAGL - 因?yàn)槊總€(gè)窗?系統(tǒng)都有不同的定義,所以
EGL提供基本的不透明類型—EGLDisplay, 這 個(gè)類型封裝了所有系統(tǒng)相關(guān)性,用于和原生窗?系統(tǒng)接?
GLKit
了解GLKit框架前,有必要先看下GLKit的蘋果官方文檔GLKitAPI
GLKit框架的設(shè)計(jì)目標(biāo)是為了簡化基于OpenGL / OpenGL ES的應(yīng)用開發(fā)。它的出現(xiàn)加快OpenGL ES或OpenGL應(yīng)用程序開發(fā)。 使用數(shù)學(xué)庫,背景紋理加載,預(yù)先創(chuàng)建的著色器效果,以及標(biāo)準(zhǔn)視圖和視圖控制器來實(shí)現(xiàn)渲染循環(huán)。
GLKit框架提供了功能和類,可以減少創(chuàng)建新的基于著?器的應(yīng)用程序所需的?作量,或者?持依賴早期版本的OpenGL ES或OpenGL提供的固定函數(shù)頂點(diǎn)或?段處理的現(xiàn)有應(yīng)用程序。
GLKit功能
提供高性能的數(shù)學(xué)運(yùn)算(
Math libraries):提供常用的向量,四元數(shù)和矩陣運(yùn)算。加載紋理(
Texture loading):允許加載各種紋理,且可以后臺(tái)加載,通過GLKTextureLoader類來加載-
提供常見的著色器(effect):包含以下3種著色器
GLKBaseEffectGLKReflectionMapEffectGLKSkyboxEffect
-
提供視圖視圖以及視圖控制器:
GLKView和GLKViewController-
GLKView:提供繪制場(chǎng)所,繼承自UIView -
GLKViewController:?于繪制視圖內(nèi)容的管理與呈現(xiàn),繼承自UIViewController)
-
使用GLKit視圖呈現(xiàn)OpenGL ES 內(nèi)容
下圖來自Apple官方文檔Drawing with OpenGL ES and GLKit

通過GLKit展示圖片,主要有以下三個(gè)步驟
- GLKView的創(chuàng)建和配置
- 使用GLKView對(duì)象繪制圖形,并存儲(chǔ)到幀緩存區(qū)
- 從幀緩存區(qū)中讀取數(shù)據(jù),顯示到屏幕上
GLKit 常用API
GLKit文理加載
1.GLKTextureInfo 創(chuàng)建OpenGL紋理信息
@interface GLKTextureInfo : NSObject <NSCopying>
{
@private
GLuint name;
GLenum target;
GLuint width;
GLuint height;
GLuint depth;
GLKTextureInfoAlphaState alphaState;
GLKTextureInfoOrigin textureOrigin;
BOOL containsMipmaps;
GLuint mimapLevelCount;
GLuint arrayLength;
}
@property (readonly) GLuint name;
@property (readonly) GLenum target;
@property (readonly) GLuint width;
@property (readonly) GLuint height;
@property (readonly) GLuint depth;
@property (readonly) GLKTextureInfoAlphaState alphaState;
@property (readonly) GLKTextureInfoOrigin textureOrigin;
@property (readonly) BOOL containsMipmaps;
@property (readonly) GLuint mimapLevelCount;
@property (readonly) GLuint arrayLength;
@end
GLKTextureInfo對(duì)象里面有很多屬性,常用的如下:
name: OpenGL 上下文中紋理名稱
target: 紋理綁定的目標(biāo)
height: 加載的紋理?度
width: 加載紋理的寬度
textureOrigin: 加載紋理中的原點(diǎn)位置
alphaState: 加載紋理中alpha分量狀態(tài)
containsMipmaps: 布爾值,加載的紋理是否包含mip貼圖
2.GLTextureLoader簡化從各種資源文件中加載紋理
GLTextureLoader初始化方式:
- initWithSharegroup:初始化一個(gè)新的紋理加載到對(duì)象中
- initWithShareContext:初始化一個(gè)新的紋理加載對(duì)象
常見的加載方式如下:
- 從?件中加載紋理
+ textureWithContentsOfFile:options:errer:從?件加載2D紋理圖像并從數(shù)據(jù)中
創(chuàng)建新的紋理
- textureWithContentsOfFile:options:queue:completionHandler:從?件中異步
加載2D紋理圖像,并根據(jù)數(shù)據(jù)創(chuàng)建新紋理
- 從URL加載紋理
- textureWithContentsOfURL:options:error:從URL加載2D紋理圖像并從數(shù)據(jù)創(chuàng)
建新紋理
- textureWithContentsOfURL:options:queue:completionHandler:從URL異步
加載2D紋理圖像,并根據(jù)數(shù)據(jù)創(chuàng)建新紋理.
- 從內(nèi)存中表示創(chuàng)建紋理
+ textureWithContentsOfData:options:errer:從內(nèi)存空間加載2D紋理圖像,并根據(jù)數(shù)據(jù)創(chuàng)建新紋理
- textureWithContentsOfData:options:queue:completionHandler:從內(nèi)存空間異步加載2D紋理圖像,并從數(shù)據(jù)中創(chuàng)建新紋理
- 從CGImages創(chuàng)建紋理
- textureWithCGImage:options:error:從Quartz圖像加載2D紋理圖像并從數(shù)據(jù)創(chuàng)建新紋理
- textureWithCGImage:options:queue:completionHandler:從Quartz圖像異步加載2D紋理理圖像,并根據(jù)數(shù)據(jù)創(chuàng)建新紋理
- 從URL加載多維創(chuàng)建紋理
+ cabeMapWithContentsOfURL:options:errer:從單個(gè)URL加載?方體貼圖紋理圖像,并根據(jù)數(shù)據(jù)創(chuàng)建新紋理
- cabeMapWithContentsOfURL:options:queue:completionHandler:從單個(gè)
URL異步加載?方體貼圖紋理圖像,并根據(jù)數(shù)據(jù)創(chuàng)建新紋理
- 從?件加載多維數(shù)據(jù)創(chuàng)建紋理
+ cubeMapWithContentsOfFile:options:errer:從單個(gè)文件加載?方體貼圖紋理對(duì)象,并從數(shù)據(jù)中創(chuàng)建新紋理理
- cubeMapWithContentsOfFile:options:queue:completionHandler:從單個(gè)?件異步加載?方體貼圖紋理對(duì)象,并從數(shù)據(jù)中創(chuàng)建新紋理
+ cubeMapWithContentsOfFiles:options:errer:從?系列文件中加載?方體貼圖紋理圖像,并從數(shù)據(jù)總創(chuàng)建新紋理
- cubeMapWithContentsOfFiles:options:options:queue:completionHandler:
從一系列文件異步加載?方體貼圖紋理圖像,并從數(shù)據(jù)中創(chuàng)建新紋理
GLKit OpenGL ES視圖渲染
GLKView使用OpenGL ES繪制內(nèi)容的視圖默認(rèn)實(shí)現(xiàn)
- 初始化視圖
- initWithFrame:context:初始化新視圖
delegate視圖的代理- 配置幀緩存區(qū)對(duì)象
drawableColorFormat顏?渲染緩存區(qū)格式
drawableDepthFormat深度渲染緩存區(qū)格式
drawableStencilFormat模板渲染緩存區(qū)的格式
drawableMultisample多重采樣緩存區(qū)的格式- 幀緩存區(qū)屬性
drawableHeight底層緩存區(qū)對(duì)象的?度(以像素為單位)
drawableWidth底層緩存區(qū)對(duì)象的寬度(以像素為單位)- 繪制視圖的內(nèi)容
context繪制視圖內(nèi)容時(shí)使?用的OpenGL ES上下文
- bindDrawable將底層FrameBuffer對(duì)象綁定到OpenGL ES
enableSetNeedsDisplay布爾值,指定視圖是否響應(yīng)使得視圖內(nèi)容?效的消息
- display ?即重繪視圖內(nèi)容
snapshot繪制視圖內(nèi)容并將其作為新圖像對(duì)象返回
- 刪除視圖
FrameBuffer對(duì)象
- deleteDrawable刪除與視圖關(guān)聯(lián)的可繪制對(duì)象
GLKViewDelegate?于GLKView對(duì)象回調(diào)方法
繪制視圖的內(nèi)容
- glkView:drawInRect:繪制視圖內(nèi)容 (必須實(shí)現(xiàn)代理)
** GLKViewController管理OpenGL ES渲染循環(huán)的視圖控制器**
- 更新
- (void) glkViewControllerUpdate:- 配置幀速率
preferredFramesPerSecond視圖控制器調(diào)?視圖以及更新視圖內(nèi)容的速率
framesPerSencond視圖控制器器調(diào)用視圖以及更新其內(nèi)容的實(shí)際速率- 配置GLKViewController代理
delegate視圖控制器的代理- 控制幀更新
paused布爾值,渲染循環(huán)是否已暫停
pausedOnWillResignActive布爾值,當(dāng)前程序重新激活動(dòng)狀態(tài)時(shí)視圖控制器是
否?動(dòng)暫停渲染循環(huán)
resumeOnDidBecomeActive布爾值,當(dāng)前程序變?yōu)榛顒?dòng)狀態(tài)時(shí)視圖控制是否?動(dòng)恢復(fù)呈現(xiàn)循環(huán)- 獲取有關(guān)View 更更新信息
frameDisplayed視圖控制器?創(chuàng)建以來發(fā)送的幀更新數(shù)
timeSinceFirstResume自視圖控制器第一次恢復(fù)發(fā)送更新事件以來經(jīng)過的時(shí)間量
timeSinceLastResume自上次視圖控制器恢復(fù)發(fā)送更新事件以來更新的時(shí)間量
timeSinceLastUpdate?上次視圖控制器調(diào)?委托?法以及經(jīng)過的時(shí)間量
glkViewControllerUpdate:timeSinceLastDraw自上次視圖控制器調(diào)用視圖display方法以來經(jīng)過的時(shí)間量
GLKViewControllerDelegate渲染循環(huán)回調(diào)?法
處理更新事件
- glkViewControllerUpdate:在顯示每個(gè)幀之前調(diào)用
暫停/恢復(fù)通知
- glkViewController : willPause:在渲染循環(huán)暫停或恢復(fù)之前調(diào)?
GLKBaseEffect 一種簡單光照/著?系統(tǒng),?于基于著?器OpenGL渲染
- 命名Effect
label給Effect(效果)命名- 配置模型視圖轉(zhuǎn)換
transform綁定效果時(shí)應(yīng)?于頂點(diǎn)數(shù)據(jù)的模型視圖,投影和紋理變換- 配置光照效果
lightingType?于計(jì)算每個(gè)?段的光照策略,GLKLightingTypeGLKLightingType
GLKLightingTypePerVertex表示在三?形中每個(gè)頂點(diǎn)執(zhí)行光照計(jì)算,然后在三?形進(jìn)?插值
GLKLightingTypePerPixel表示光照計(jì)算的輸?入在三?形內(nèi)插?,并且在每個(gè)片段執(zhí)行光照計(jì)算- 配置光照
lightModelTwoSided布爾值,表示為基元的兩側(cè)計(jì)算光照
material計(jì)算渲染圖元光照使用的材質(zhì)屬性
lightModelAmbientColor環(huán)境顏?色應(yīng)用效果渲染的所有圖元.
light0場(chǎng)景中第一個(gè)光照屬性light1場(chǎng)景中第二個(gè)光照屬性light2場(chǎng)景中第三個(gè)光照屬性- 配置紋理
texture2d0第?個(gè)紋理屬性texture2d1第二個(gè)紋理屬性
textureOrder紋理應(yīng)用于渲染圖元的順序- 配置霧化
fog應(yīng)?于場(chǎng)景的霧屬性- 配置顏?信息
colorMaterialEnable布爾值,表示計(jì)算光照與材質(zhì)交互時(shí)是否使?顏色頂點(diǎn)屬性
useConstantColor布爾值,指示是否使用常量顏色
constantColor不提供每個(gè)頂點(diǎn)顏?數(shù)據(jù)時(shí)使?常量顏?- 準(zhǔn)備繪制效果
- prepareToDraw準(zhǔn)備渲染效果
注意
1、GLKit中最多只有3個(gè)光照,2個(gè)紋理
2、常量顏色:黑色
GLKit加載圖片案例
首先實(shí)現(xiàn)一個(gè)修改view的backgroundColor
創(chuàng)建一個(gè)iOS項(xiàng)目,并將系統(tǒng)創(chuàng)建的ViewController的父類由UIViewController修改為GLKViewController,其中的view的父類由UIView修改為GLKView
在ViewController.h文件中導(dǎo)入GLKit框架的頭文件#import <GLKit/GLKit.h>
在ViewController.h文件中導(dǎo)入OpenGL ES相關(guān)頭文件#import <OpenGLES/ES3/gl.h>、#import <OpenGLES/ES3/glext.h>
- 定義一個(gè)
EAGLContext成員變量
#import <OpenGLES/ES3/gl.h>
#import <OpenGLES/ES3/glext.h>
@interface ViewController ()
{
EAGLContext *context;
@end
-
viewDidLoad方法:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//1.初始化上下文&設(shè)置當(dāng)前上下文
/*
EAGLContext 是蘋果iOS平臺(tái)下實(shí)現(xiàn)OpenGLES 渲染層.
kEAGLRenderingAPIOpenGLES1 = 1, 固定管線
kEAGLRenderingAPIOpenGLES2 = 2,
kEAGLRenderingAPIOpenGLES3 = 3,
*/
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.設(shè)置背景顏色
glClearColor(0, 0, 1, 1.0);
}
- 實(shí)現(xiàn)
GLView代理方法
//繪制視圖的內(nèi)容
/*
GLKView對(duì)象使其OpenGL ES上下文成為當(dāng)前上下文,并將其framebuffer綁定為OpenGL ES呈現(xiàn)命令的目標(biāo)。然后,委托方法應(yīng)該繪制視圖的內(nèi)容。
*/
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
glClear(GL_COLOR_BUFFER_BIT);
}
運(yùn)行看下結(jié)果,如下圖:

使用GLKit加載圖片紋理并顯示到view上
在上面的基礎(chǔ)上添加一個(gè)GLKBaseEffect成員變量*
@interface ViewController ()
{
EAGLContext *context;
GLKBaseEffect *cEffect;
}
@end
- 初始化
OpenGL ES
-(void)setUpConfig
{
//1.初始化上下文&設(shè)置當(dāng)前上下文
/*
EAGLContext 是蘋果iOS平臺(tái)下實(shí)現(xiàn)OpenGLES 渲染層.
kEAGLRenderingAPIOpenGLES1 = 1, 固定管線
kEAGLRenderingAPIOpenGLES2 = 2,
kEAGLRenderingAPIOpenGLES3 = 3,
*/
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ū).
(1). drawableColorFormat: 顏色緩存區(qū)格式.
簡介: OpenGL ES 有一個(gè)緩存區(qū),它用以存儲(chǔ)將在屏幕中顯示的顏色。你可以使用其屬性來設(shè)置緩沖區(qū)中的每個(gè)像素的顏色格式。
GLKViewDrawableColorFormatRGBA8888 = 0,
默認(rèn).緩存區(qū)的每個(gè)像素的最小組成部分(RGBA)使用8個(gè)bit,(所以每個(gè)像素4個(gè)字節(jié),4*8個(gè)bit)。
GLKViewDrawableColorFormatRGB565,
如果你的APP允許更小范圍的顏色,即可設(shè)置這個(gè)。會(huì)讓你的APP消耗更小的資源(內(nèi)存和處理時(shí)間)
(2). drawableDepthFormat: 深度緩存區(qū)格式
GLKViewDrawableDepthFormatNone = 0,意味著完全沒有深度緩沖區(qū)
GLKViewDrawableDepthFormat16,
GLKViewDrawableDepthFormat24,
如果你要使用這個(gè)屬性(一般用于3D游戲),你應(yīng)該選擇GLKViewDrawableDepthFormat16
或GLKViewDrawableDepthFormat24。這里的差別是使用GLKViewDrawableDepthFormat16
將消耗更少的資源
*/
//3.配置視圖創(chuàng)建的渲染緩存區(qū).
view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
view.drawableDepthFormat = GLKViewDrawableDepthFormat16;
//4.設(shè)置背景顏色
glClearColor(0, 0, 1, 1.0);
}
- 創(chuàng)建頂點(diǎn)數(shù)據(jù)
-(void)setUpVertexData
{
//1.設(shè)置頂點(diǎn)數(shù)組(頂點(diǎn)坐標(biāo),紋理坐標(biāo))
/*
紋理坐標(biāo)系取值范圍[0,1];原點(diǎn)是左下角(0,0);
故而(0,0)是紋理圖像的左下角, 點(diǎn)(1,1)是右上角.
*/
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, //左下
};
/*
頂點(diǎn)數(shù)組: 開發(fā)者可以選擇設(shè)定函數(shù)指針,在調(diào)用繪制方法的時(shí)候,直接由內(nèi)存?zhèn)魅腠旤c(diǎn)數(shù)據(jù),也就是說這部分?jǐn)?shù)據(jù)之前是存儲(chǔ)在內(nèi)存當(dāng)中的,被稱為頂點(diǎn)數(shù)組
頂點(diǎn)緩存區(qū): 性能更高的做法是,提前分配一塊顯存,將頂點(diǎn)數(shù)據(jù)預(yù)先傳入到顯存當(dāng)中。這部分的顯存,就被稱為頂點(diǎn)緩沖區(qū)
*/
//2.開辟頂點(diǎn)緩存區(qū)
//(1).創(chuàng)建頂點(diǎn)緩存區(qū)標(biāo)識(shí)符ID
GLuint bufferID;
glGenBuffers(1, &bufferID);
//(2).綁定頂點(diǎn)緩存區(qū).(明確作用)
glBindBuffer(GL_ARRAY_BUFFER, bufferID);
//(3).將頂點(diǎn)數(shù)組的數(shù)據(jù)copy到頂點(diǎn)緩存區(qū)中(GPU顯存中)
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);
//3.打開讀取通道.
/*
(1)在iOS中, 默認(rèn)情況下,出于性能考慮,所有頂點(diǎn)著色器的屬性(Attribute)變量都是關(guān)閉的.
意味著,頂點(diǎn)數(shù)據(jù)在著色器端(服務(wù)端)是不可用的. 即使你已經(jīng)使用glBufferData方法,將頂點(diǎn)數(shù)據(jù)從內(nèi)存拷貝到頂點(diǎn)緩存區(qū)中(GPU顯存中).
所以, 必須由glEnableVertexAttribArray 方法打開通道.指定訪問屬性.才能讓頂點(diǎn)著色器能夠訪問到從CPU復(fù)制到GPU的數(shù)據(jù).
注意: 數(shù)據(jù)在GPU端是否可見,即,著色器能否讀取到數(shù)據(jù),由是否啟用了對(duì)應(yīng)的屬性決定,這就是glEnableVertexAttribArray的功能,允許頂點(diǎn)著色器讀取GPU(服務(wù)器端)數(shù)據(jù)。
(2)方法簡介
glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr)
功能: 上傳頂點(diǎn)數(shù)據(jù)到顯存的方法(設(shè)置合適的方式從buffer里面讀取數(shù)據(jù))
參數(shù)列表:
index,指定要修改的頂點(diǎn)屬性的索引值,例如
size, 每次讀取數(shù)量。(如position是由3個(gè)(x,y,z)組成,而顏色是4個(gè)(r,g,b,a),紋理則是2個(gè).)
type,指定數(shù)組中每個(gè)組件的數(shù)據(jù)類型。可用的符號(hào)常量有GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT,GL_UNSIGNED_SHORT, GL_FIXED, 和 GL_FLOAT,初始值為GL_FLOAT。
normalized,指定當(dāng)被訪問時(shí),固定點(diǎn)數(shù)據(jù)值是否應(yīng)該被歸一化(GL_TRUE)或者直接轉(zhuǎn)換為固定點(diǎn)值(GL_FALSE)
stride,指定連續(xù)頂點(diǎn)屬性之間的偏移量。如果為0,那么頂點(diǎn)屬性會(huì)被理解為:它們是緊密排列在一起的。初始值為0
ptr指定一個(gè)指針,指向數(shù)組中第一個(gè)頂點(diǎn)屬性的第一個(gè)組件。初始值為0
*/
//頂點(diǎn)坐標(biāo)數(shù)據(jù)
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (GLfloat *)NULL + 0);
//紋理坐標(biāo)數(shù)據(jù)
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (GLfloat *)NULL + 3);
}
- 為了創(chuàng)建顯示圖片的頂點(diǎn)數(shù)據(jù),確定圖片顯示到view的那個(gè)位置。
圖片是正方形,我們由兩個(gè)三角形拼起來,所以需要6個(gè)頂點(diǎn)- 我們定義頂點(diǎn)坐標(biāo)使用的是一維數(shù)組,我們?cè)谇懊婢椭v過,在OpenGL中習(xí)慣使用一維數(shù)組,所以O(shè)penGL ES也是一樣的。
- 加載圖片紋理并顯示
-(void)setUpTexture
{
//1.獲取紋理圖片路徑
NSString *filePath = [[NSBundle mainBundle]pathForResource:@"tutu" ofType:@"jpg"]
//2.設(shè)置紋理參數(shù)
//紋理坐標(biāo)原點(diǎn)是左下角,但是圖片顯示原點(diǎn)應(yīng)該是左上角.
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:@(1),GLKTextureLoaderOriginBottomLeft, nil];
GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithContentsOfFile:filePath options:options error:nil];
//3.使用蘋果GLKit 提供GLKBaseEffect 完成著色器工作(頂點(diǎn)/片元)
cEffect = [[GLKBaseEffect alloc]init];
cEffect.texture2d0.enabled = GL_TRUE;
cEffect.texture2d0.name = textureInfo.name;
}
- 實(shí)現(xiàn)
GLKViewDelegate代理方法
//繪制視圖的內(nèi)容
/*
GLKView對(duì)象使其OpenGL ES上下文成為當(dāng)前上下文,并將其framebuffer綁定為OpenGL ES呈現(xiàn)命令的目標(biāo)。然后,委托方法應(yīng)該繪制視圖的內(nèi)容。
*/
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
//1.
glClear(GL_COLOR_BUFFER_BIT);
//2.準(zhǔn)備繪制
[cEffect prepareToDraw];
//3.開始繪制
glDrawArrays(GL_TRIANGLES, 0, 6);
}
-
viewDidLoad調(diào)用
- (void)viewDidLoad {
[super viewDidLoad];
//1.OpenGL ES 相關(guān)初始化
[self setUpConfig];
//2.加載頂點(diǎn)/紋理坐標(biāo)數(shù)據(jù)
[self setUpVertexData];
//3.加載紋理數(shù)據(jù)(使用GLBaseEffect)
[self setUpTexture];
}
最后運(yùn)行看下效果,如下圖:
