1. 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)各自提供載體
在本文中逗物,主要講述的是iOS中的OpenGL ES,OpenGL ES API吕嘀、OpenGL ES Programming Guide
OpenGL ES渲染流程
下圖出自蘋(píng)果官方文檔OpenGL ES as a Client-Server Architecture
OpebGL ES的渲染主要分為兩部分:CPU和GPU
- CPU部分
- app代碼通過(guò)OpenGL ES API违寞,會(huì)調(diào)度OpenGL ES Framework
- 通過(guò)OpenGL ES client 調(diào)度 OpenGL ES server,將頂點(diǎn)數(shù)據(jù)等傳遞到GPU
- GPU部分:做一些圖形硬件的處理偶房,例如光柵化趁曼、顯示等
OpenGL ES 圖形管道
OpenGL ES 圖形管道有以下兩種圖示,其中原理都是一致的蝴悉,只是描述方式不同
圖示一
- API獲得頂點(diǎn)數(shù)據(jù)彰阴,將頂點(diǎn)數(shù)據(jù)從內(nèi)存中拷貝至頂點(diǎn)緩沖區(qū)(顯存)
- 拿到數(shù)據(jù)之后瘾敢,通過(guò)attribute通道傳遞至頂點(diǎn)著色器拍冠,同時(shí),紋理坐標(biāo)通過(guò)Texture通道傳遞到頂點(diǎn)著色器和片元著色器
- 然后簇抵,圖元裝配庆杜,即圖元的連接方式,一共有9種碟摆,常用的有6種晃财,此步驟將頂點(diǎn)變換為圖形
- 光柵化:確定圖形與屏幕對(duì)應(yīng)的位置
- 片元/片段/像素著色器:處理對(duì)應(yīng)像素點(diǎn)的顏色值
- 在將處理好的每個(gè)像素點(diǎn)的顏色值存儲(chǔ)到幀緩存區(qū),然后在顯示器中顯示
- API:可以通過(guò)API操作頂點(diǎn)緩沖區(qū)、頂點(diǎn)著色器断盛、紋理坐標(biāo)罗洗、片段著色器
Apple官方圖示
來(lái)自蘋(píng)果官方文檔OpenGL ES as a Graphics Pipeline
- App:提供圖元裝配頂點(diǎn)信息,圖片信息
- Vertex(頂點(diǎn)著色器):處理頂點(diǎn) -- 圖形變換(旋轉(zhuǎn)钢猛、縮放伙菜、平移)
- Geometry(圖元裝配):圖元裝配 + 裁剪(超出屏幕部分被裁剪)
- Fragment(片元著色器):紋理處理 + 霧化處理
- Framebuffer Operation(幀緩沖區(qū)):透明度混合、模板命迈、深度測(cè)試贩绕;最后在混合,這些操作都是在即將顯示時(shí)壶愤,在幀緩沖區(qū)中完成的動(dòng)作
頂點(diǎn)著色器
簡(jiǎn)單來(lái)說(shuō)就是處理頂點(diǎn)的著色器程序淑倾,如圖所示
- 輸入,有3種方式
- 通過(guò)attribute通道輸入頂點(diǎn)數(shù)據(jù)征椒,提供每個(gè)頂點(diǎn)的數(shù)據(jù)
- 通過(guò)uniform通道輸入統(tǒng)一變量娇哆,即頂點(diǎn)/片元著色器中使用的不變的數(shù)據(jù)
- 采樣器:表示頂點(diǎn)著色器使用紋理的特殊統(tǒng)一變量類(lèi)型
- 輸出:經(jīng)過(guò)處理的最終頂點(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ù)
- 矩陣變換位置
- 計(jì)算光照公式生成逐頂點(diǎn)顏色(也可以片元著色器)
- 生成/變換紋理坐標(biāo):片元著色器是沒(méi)有辦法傳入屬性即attribute的,可以通過(guò)頂點(diǎn)著色器橋接税肪,間接將紋理坐標(biāo)屬性傳遞到片元著色器
頂點(diǎn)著色器GLSL代碼示例
- attribute溉躲、uniform 表示client與server之間的通道
- 其中的vec4、vec2都是向量類(lèi)型益兄,表示四維向量和二維向量
- mat4:4*4矩陣
- varying是修飾符:通過(guò)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)數(shù)據(jù)計(jì)算成一個(gè)個(gè)圖元
- 光柵化:將圖元轉(zhuǎn)化為一組二維片段的過(guò)程疑枯,主要是由于屏幕是2D的,所以轉(zhuǎn)換的像素點(diǎn)也是二維的
片元著色器
下圖表示片元著色器中有哪些輸入和輸出
- 輸入同頂點(diǎn)著色器一樣蛔六,有3種方式
- 由頂點(diǎn)著色器橋接傳遞過(guò)來(lái)的紋理坐標(biāo)等
- 通過(guò)uniform通道輸入統(tǒng)一變量荆永,即頂點(diǎn)/片元著色器中使用的不變的數(shù)據(jù)
- 采樣器:表示頂點(diǎn)著色器使用紋理的特殊統(tǒng)一變量類(lèi)型,例如紋理就是通過(guò)采樣器傳遞
- 輸出:某個(gè)像素點(diǎn)經(jīng)過(guò)片元著色器處理后的結(jié)果
片元著色器業(yè)務(wù)
- 計(jì)算顏色
- 獲取紋理值
- 往像素點(diǎn)中填充顏色值(紋理值/顏色值)
片元著色器GLSL代碼示例
- varying:必須和頂點(diǎn)著色器中一模一樣国章,這樣才能傳遞紋理坐標(biāo)
- sampler2D 采樣器類(lèi)型
- texture2D(紋理采樣器具钥,紋理坐標(biāo)):獲取對(duì)應(yīng)位置/坐標(biāo)的顏色值,簡(jiǎn)稱獲得紋素
- gl_FragColor(內(nèi)建變量):將最終的顏色值賦值給它
varying lowp vec2 varyTextCoord;
uniform sampler2D colorMap;
void main() {
gl_FragColor = texture2D(colorMap, varyTextCoord); }
總結(jié)
- 頂點(diǎn)著色器液兽、片元著色器都是代碼段骂删,類(lèi)似于iOS中的函數(shù)/方法,有返回值
- 頂點(diǎn)著色器的返回值會(huì)被復(fù)制給
gl_Position
- 片元著色器的結(jié)果會(huì)賦值給
gl_fragColor
- 頂點(diǎn)著色器的返回值會(huì)被復(fù)制給
- 這兩個(gè)返回值都屬于GLSL中的內(nèi)建變量,是封裝好的宁玫,直接將數(shù)據(jù)賦值給它即可
- gl_Position:頂點(diǎn)著色器中某一個(gè)頂點(diǎn)經(jīng)過(guò)一系列處理后得到的結(jié)果
- gl_fragColor:經(jīng)過(guò)片元著色器對(duì)某一個(gè)像素點(diǎn)來(lái)進(jìn)行處理之后的結(jié)果
逐片段操作
這個(gè)過(guò)程都是GPU內(nèi)部處理的粗恢,開(kāi)發(fā)者并不需要關(guān)心,將處理好的數(shù)據(jù)存儲(chǔ)到幀緩存區(qū)欧瘪,最后讀取幀緩存區(qū)將圖形顯示到屏幕上
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 并沒(méi)有提供如何創(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提供基本的不透明類(lèi)型—EGLDisplay, 這 個(gè)類(lèi)型封裝了所有系統(tǒng)相關(guān)性,用于和原生窗?系統(tǒng)接?
2. GLKit 簡(jiǎn)述
先了解GLKit框架前苦囱,先附上GLKit的蘋(píng)果官方文檔GLKitAPI
GLKit框架的設(shè)計(jì)目的是為了簡(jiǎn)化基于OpenGL/OpenGL ES的應(yīng)用開(kāi)發(fā)嗅绸,加快了OpenGL/OpenGL ES應(yīng)用程序開(kāi)發(fā)
GLKit功能
- 提供高性能的數(shù)學(xué)運(yùn)算(Math libraries):提供常用的向量,四元數(shù)和矩陣運(yùn)算撕彤。
- 加載紋理(Texture loading):允許加載各種紋理鱼鸠,且可以后臺(tái)加載,通過(guò)
GLKTextureLoader
類(lèi)來(lái)加載 - 提供常見(jiàn)的著色器(effect):包含以下3種著色器
- GLKBaseEffect
- GLKReflectionMapEffect
- GLKSkyboxEffect
- 提供視圖視圖以及視圖控制器:GLKView和GLKViewController
- GLKView:提供繪制場(chǎng)所羹铅,繼承自UIView
- GLKViewController:?于繪制視圖內(nèi)容的管理與呈現(xiàn)蚀狰,繼承自UIViewController)
使用GLKit視圖呈現(xiàn)OpenGL ES 內(nèi)容
下圖來(lái)自Apple官方文檔Drawing with OpenGL ES and GLKit
通過(guò)GLKit展示圖片,主要有以下三個(gè)步驟
- GLKView的創(chuàng)建和配置
- 使用GLKView對(duì)象繪制圖形职员,并存儲(chǔ)到幀緩存區(qū)
- 從幀緩存區(qū)中讀取數(shù)據(jù)麻蹋,顯示到屏幕上
GLKit 常用API
GLKit 紋理加載
GLKTextureInfo 創(chuàng)建OpenGL 紋理信息
常見(jiàn)的屬性如表所示
屬性 | 說(shuō)明 |
---|---|
name | OpenGL 上下?文中紋理名稱 |
target | 紋理綁定的目標(biāo) |
height | 加載的紋理高度 |
width | 加載紋理的寬度 |
textureOrigin | 加載紋理中的原點(diǎn)位置 |
alphaState | 加載紋理中alpha分量狀態(tài) |
containsMipmaps | 布爾值,加載的紋理是否包含mip貼圖 |
GLTextureLoader 簡(jiǎn)化從各種資源?件中加載紋理
- 初始化
初始化方法 | 說(shuō)明 |
---|---|
- initWithSharegroup: | 初始化?個(gè)新的紋理加載到對(duì)象中 |
- initWithShareContext: | 初始化一個(gè)新的紋理加載對(duì)象 |
- 從文件中加載處理
從文件中加載處理方法 | 說(shuō)明 |
---|---|
+ textureWithContentsOfFile:options:errer: | 從?件加載2D紋理圖像并從數(shù)據(jù)中創(chuàng)建新的紋理 |
- textureWithContentsOfFile:options:queue:completionHandler: | 從?件中異步加載2D紋理圖像,并根據(jù)數(shù)據(jù)創(chuàng)建新紋理 |
- 從URL加載處理
從URL加載紋理方法 | 說(shuō)明 |
---|---|
- textureWithContentsOfURL:options:error: | 從URL加載2D紋理圖像并從數(shù)據(jù)創(chuàng)建新紋理 |
- textureWithContentsOfURL:options:queue:completionHandler: | 從URL異步加載2D紋理圖像,并根據(jù)數(shù)據(jù)創(chuàng)建新紋理 |
- 從內(nèi)存中表示創(chuàng)建紋理
從內(nèi)存中表示創(chuàng)建紋理方法 | 說(shuō)明 |
---|---|
+ 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)建紋理
從CGImages創(chuàng)建紋理方法 | 說(shuō)明 |
---|---|
- textureWithCGImage:options:error: | 從Quartz圖像 加載2D紋理圖像并從數(shù)據(jù)創(chuàng)建新紋理 |
- textureWithCGImage:options:queue:completionHandler: | 從Quartz圖像異步加載2D紋理圖像,并根據(jù)數(shù)據(jù)創(chuàng)建新紋理 |
- 從URL加載多維創(chuàng)建紋理
從URL加載多維創(chuàng)建紋理方法 | 說(shuō)明 |
---|---|
+ 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)建紋理
文件加載多維數(shù)據(jù)創(chuàng)建紋理方法 | 說(shuō)明 |
---|---|
+ 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視圖渲染 API
GLKView
使?OpenGL ES 繪制內(nèi)容的視圖默認(rèn)實(shí)現(xiàn),常用API及屬性如下所示
- 初始化視圖
屬性 | 說(shuō)明 |
---|---|
- initWithFrame:context: | 初始化新視圖 |
- 設(shè)置代理
屬性 | 說(shuō)明 |
---|---|
delegate | 視圖的代理 |
- 配置幀緩存區(qū)對(duì)象
屬性 | 說(shuō)明 | |
---|---|---|
配置幀緩存區(qū)對(duì)象 | drawableColorFormat | 顏?渲染緩存區(qū)格式 |
drawableDepthFormat | 深度渲染緩存區(qū)格式 | |
drawableStencilFormat | 模板渲染緩存區(qū)的格式 | |
drawableMultisample | 多重采樣緩存區(qū)的格式 |
-幀緩存區(qū)屬性
屬性 | 說(shuō)明 |
---|---|
drawableHeight | 底層緩存區(qū)對(duì)象的?度(以像素為單位) |
drawableWidth | 底層緩存區(qū)對(duì)象的寬度(以像素為單位) |
- 繪制視圖的內(nèi)容
屬性 | 說(shuō)明 |
---|---|
context | 繪制視圖內(nèi)容時(shí)使?用的OpenGL ES 上下?文 |
drawableStencilFormat | 將底層FrameBuffer 對(duì)象綁定到OpenGL ES |
enableSetNeedsDisplay | 布爾值,指定視圖是否響應(yīng)使得視圖內(nèi)容?效的消息 |
snapshot | 繪制視圖內(nèi)容并將其作為新圖像對(duì)象返回 |
方法 | 說(shuō)明 |
---|---|
- bindDrawable | 深度渲染緩存區(qū)格式 |
- display | ?即重繪視圖內(nèi)容 |
- 刪除視圖FrameBuffer對(duì)象
方法 | 說(shuō)明 |
---|---|
- deleteDrawable | 刪除與視圖關(guān)聯(lián)的可繪制對(duì)象 |
GLKViewDelegate ?于GLKView 對(duì)象回調(diào)方法
- 繪制視圖的內(nèi)容(必須實(shí)現(xiàn)代理:盖小0缡凇!Wǚ尽)
屬性 | 說(shuō)明 |
---|---|
- glkView:drawInRect: | 繪制視圖內(nèi)容 (必須實(shí)現(xiàn)代理) |
GLKViewController
管理OpenGL ES 渲染循環(huán)的視圖控制器刹勃,常用的API如下
- 更新
方法 | 說(shuō)明 |
---|---|
- (void) update | 更新視圖內(nèi)容 |
- (void) glkViewControllerUpdate: | 更新視圖控制器顯示 |
- 配置幀速率
屬性 | 說(shuō)明 |
---|---|
preferredFramesPerSecond | 視圖控制器調(diào)?視圖以及更新視圖內(nèi)容的速率 |
framesPerSencond | 視圖控制器調(diào)?視圖以及更新其內(nèi)容的實(shí)際速率 |
- 配置GLKViewDelegate代理
屬性 | 說(shuō)明 |
---|---|
delegate | 視圖控制器的代理 |
- 控制幀更新
resumeOnDidBecomeActive 布爾值,當(dāng)前程序變?yōu)榛顒?dòng)狀態(tài)時(shí)視圖控制是否?自動(dòng)恢復(fù)呈現(xiàn)循環(huán)
屬性 | 說(shuō)明 |
---|---|
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 更新信息
屬性 | 說(shuō)明 |
---|---|
frameDisplayed | 視圖控制器自創(chuàng)建以來(lái)發(fā)送的幀更新數(shù) |
timeSinceFirstResume | 自視圖控制器第?次恢復(fù)發(fā)送更新事件以來(lái)經(jīng)過(guò)的時(shí)間量 |
timeSinceLastResume | 自上次視圖控制器恢復(fù)發(fā)送更新事件以來(lái)更新的時(shí)間量 |
timeSinceLastUpdate | 自上次視圖控制器調(diào)?委托?法以及經(jīng)過(guò)的時(shí)間量 |
timeSinceLastDraw | ?上次視圖控制器調(diào)?委托?法以及經(jīng)過(guò)的時(shí)間量 |
**GLKViewControllerDelegate **
渲染循環(huán)回調(diào)?方法
- 處理理更更新事件
回調(diào)方法 | 說(shuō)明 |
---|---|
- glkViewControllerUpdate: | 在顯示每個(gè)幀之前調(diào)?,類(lèi)似OpenGL中RenderScene函數(shù) |
- 暫停/恢復(fù)通知
回調(diào)方法 | 說(shuō)明 |
---|---|
- glkViewController : willPause: | 在渲染循環(huán)暫秃坑龋或恢復(fù)之前調(diào)? |
GLKBaseEffect
一種簡(jiǎn)單光照/著色系統(tǒng),?于基于著?器的OpenGL渲染
- 命名Effect
屬性 | 說(shuō)明 |
---|---|
label | 給Effect(效果)命名 |
- 配置模型視圖轉(zhuǎn)換
屬性 | 說(shuō)明 |
---|---|
transform | 綁定效果時(shí)應(yīng)?于頂點(diǎn)數(shù)據(jù)的模型視圖,投影和紋理變換 |
- 配置光照效果
屬性 | 說(shuō)明 |
---|---|
lightingType | 用于計(jì)算每個(gè)片段的光照策略,GLKLightingType |
GLKLightingType枚舉 | 說(shuō)明 |
---|---|
GLKLightingTypePerVertex | 表示在三角形中每個(gè)頂點(diǎn)執(zhí)?光照計(jì)算,然后在三角形進(jìn)?插值 |
GLKLightingTypePerPixel | 表示光照計(jì)算的輸?在三角形內(nèi)插入,并且在每個(gè)片段執(zhí)行光照計(jì)算 |
- 配置光照
屬性 | 說(shuō)明 |
---|---|
lightModelTwoSided | 布爾值,表示為基元的兩側(cè)計(jì)算光照 |
material | 計(jì)算渲染圖元光照使?的材質(zhì)屬性 |
lightModelAmbientColor | 環(huán)境顏?,應(yīng)?效果渲染的所有圖元. |
light0 | 場(chǎng)景中第?個(gè)光照屬性 |
light1 | 場(chǎng)景中第?個(gè)光照屬性 |
light2 | 場(chǎng)景中第三個(gè)光照屬性 |
- 配置紋理
屬性 | 說(shuō)明 |
---|---|
texture2d0 | 第一個(gè)紋理屬性 |
texture2d1 | 第?個(gè)紋理屬性 |
textureOrder | 紋理應(yīng)用于渲染圖元的順序 |
- 配置霧化
屬性 | 說(shuō)明 |
---|---|
fog | 應(yīng)?于場(chǎng)景的霧屬性 |
- 配置顏色信息
屬性 | 說(shuō)明 |
---|---|
colorMaterialEnable | 布爾值,表示計(jì)算光照與材質(zhì)交互時(shí)是否使?顏?頂點(diǎn)屬性 |
useConstantColor | 布爾值,指示是否使用常量顏? |
constantColor | 不提供每個(gè)頂點(diǎn)顏色數(shù)據(jù)時(shí)使?常量顏? |
- 準(zhǔn)備繪制效果
方法 | 說(shuō)明 |
---|---|
- prepareToDraw | 準(zhǔn)備渲染效果 |
注意
1荔仁、GLKit中最多只有3個(gè)光照,2個(gè)紋理
2芽死、常量顏色:黑色