一、認(rèn)識OpenGL相關(guān)概念
OpenGL:用于創(chuàng)建3d圖像的編程接口,用于PC端,是一個跨編程語言、跨平臺的圖形編程程序接口校读,只操作GPU芯片來保證跨平臺性
OpenGL ES:是OpenGL的子集雅潭,主要針對手機椿浓、PAD和游戲主機等嵌入式設(shè)備使用,用于移動端笋敞,使用的語言是GLSL碱蒙,是著色器語言赛惩,iOS框架是GLKit
DirectX:僅用于Windows平臺的多媒體處理框架
Metal:是Apple在2014年推出的3D渲染框架勉抓,性能優(yōu)于OpenGL ES,使用的語言是Metal shading language边翁,iOS框架是Metal kit3D圖形:有3個維度的圖形翎承,屏幕上的3D效果是2D+透視呈現(xiàn)出來的
三維物體:高度、寬度、深度(在坐標(biāo)軸上用z軸表)甸各;二維物體:高度垛贤、寬度3D術(shù)語:
- 光柵化:圖形是由像素點構(gòu)成,將像素點顯示到屏幕上的過程稱為光柵化趣倾;
- 著色:渲染圖形的時候給像素點添加顏色聘惦;
- 紋理貼圖:將紋理圖片附著到需要繪制的圖像上;
- 混合:顏色混合效果儒恋;
- 坐標(biāo)系:
2D笛卡爾坐標(biāo)系
- x軸與y軸垂直定義一個xy面善绎,繪制平面圖形
3D笛卡爾坐標(biāo)系
- x軸、y軸诫尽、z軸禀酱,z軸是垂直于xy面,z軸表示深度牧嫉,繪制3D圖形
渲染:圖形圖像數(shù)據(jù)轉(zhuǎn)換成3D空間圖像的操作剂跟,如圖形繪制、圖片顯示到屏幕等數(shù)據(jù)可視化操作
線框渲染:平面通過線條形成酣藻;
純色渲染:通過顏色形成形狀浩聋;
紋理渲染:添加紋理到形狀上;
OpenGL里只有點臊恋、線、三角形墓捻,通過這三者來拼成各種形狀著色器:
- 圖元:組成圖像的基本單元
- OpenGL渲染管線:一系列有序的處理階段的序列抖仅,用于把我們應(yīng)用中的數(shù)據(jù)轉(zhuǎn)化到OpenGL,生成一個最終圖像的過程
- GLSL:專門為圖形開發(fā)設(shè)計的編程語言
著色器分類:
- 頂點著色器(必要)
- 細(xì)分著色器(可選)
- 幾何著色器(可選)
- 片元著色器(必選)砖第,Metal里稱為片元函數(shù)
著色器渲染流程:
頂點數(shù)據(jù)->頂點著色器(必要撤卢,接收頂點數(shù)據(jù),單獨處理每個頂點)
->細(xì)分著色器(可選梧兼,描述物體的形狀放吩,在管線中生成新的幾何體處理(平順)模型,生成最終狀態(tài)羽杰;對所有的圖像進行修改幾何圖元類型或放棄所有凸緣)
->幾何著色器
->圖元設(shè)置(圖形的形狀)
->剪切(剪切視口之外的繪制)
->光柵化(輸入圖元的數(shù)學(xué)描述渡紫,轉(zhuǎn)化為與屏幕對應(yīng)的位置像素片元)
->片元著色器(必選,給像素點添加顏色)
->顯示效果
CPU與GPU的通信過程
CPU將數(shù)據(jù)交給GPU處理需要通過OpenGL考赛,OpenGL的buffers緩存區(qū)域(顏色緩存區(qū)惕澎、頂點緩存區(qū)、深度緩存區(qū))解決數(shù)據(jù)饑餓問題颜骤,CPU和GPU的數(shù)據(jù)處理能力高于內(nèi)存唧喉,CPU和GPU控制的內(nèi)存是分開的,不能從一塊內(nèi)存復(fù)制到另一塊內(nèi)存執(zhí)行,因為復(fù)制數(shù)據(jù)速度很慢八孝,CPU和GPU都不能操作數(shù)據(jù)董朝,也避免引起錯誤。OpenGL使用客戶端--服務(wù)端的形式實現(xiàn)干跛,客戶端是我們編寫的代碼子姜,服務(wù)端是計算機圖形硬件廠商所提供的OpenGL實現(xiàn),OpenGL ES框架相當(dāng)于Client去發(fā)起圖像處理請求驯鳖,GPU相當(dāng)于Server負(fù)責(zé)處理圖形操作闲询。
二、了解OpenGL
- OpenGL簡介:OpenGL是跨平臺計算機圖形應(yīng)用程序接口規(guī)范浅辙,用于可視化領(lǐng)域扭弧,是一種圖形應(yīng)用程序編程接口,圖形API本質(zhì)是利用GPU芯片來高效渲染圖形圖像
tips:CPU是串行運算记舆,時間片快速切換調(diào)度任務(wù)鸽捻,處理復(fù)雜的邏輯判斷,C語言泽腮、C++代碼是編譯運行在CPU上的御蒲;GPU是并發(fā)運算,通過很多的計算單元執(zhí)行任務(wù)诊赊,處理數(shù)據(jù)更高效厚满,OpenGL語言GLSL,著色器語言碧磅,編譯運行在GPU上
- OpenGL用處:實現(xiàn)圖形的底層渲染
- 視頻碘箍、圖形、圖片處理:音視頻開發(fā)中視頻解碼后的數(shù)據(jù)渲染和濾鏡處理鲸郊、核心動畫的繪制丰榴、地圖引擎中地圖上數(shù)據(jù)的渲染
- 2D/3D游戲引擎開發(fā):游戲開發(fā)中游戲場景和人物的渲染
- 科學(xué)可視化
- 醫(yī)學(xué)軟件開發(fā)
- CAD(計算機輔助技術(shù))
- 虛擬實境(AR、VR)
- AI人工智能
- OpenGL專業(yè)名詞
OpenGL上下文(context)
- OpenGL上下文(context):是一個非常龐大的狀態(tài)機秆撮,保存了OpenGL中的各種狀態(tài)
- OpenGL函數(shù):類似C語言是面向過程的函數(shù)四濒,本質(zhì)是操作context中的某個狀態(tài)或?qū)ο?/li>
- 高效處理方案:由于OpenGL特性,切換上下文會產(chǎn)生較大開銷职辨,但是不同的繪制模塊可能需要使用完全獨立的狀態(tài)管理盗蟆,所以在應(yīng)用程序中分別創(chuàng)建不同的上下文,在不同線程中使用不同的上下文舒裤,上下文之間共享紋理姆涩、緩沖區(qū)等資源
OpenGL狀態(tài)機
- OpenGL狀態(tài)機:狀態(tài)機描述了一個對象在其生命周期內(nèi)所經(jīng)歷的各種狀態(tài)以及狀態(tài)間的轉(zhuǎn)變、轉(zhuǎn)變的動因惭每、條件及轉(zhuǎn)變中所執(zhí)行的活動
- 特點:有記憶功能骨饿,記住當(dāng)前的狀態(tài)亏栈;接收輸入并結(jié)合輸入內(nèi)容和原先狀態(tài)修改當(dāng)前狀態(tài)后輸出;進入特殊狀態(tài)如停機時宏赘,不再接收輸入绒北,直接停止工作
- OpenGL可以記錄自己的狀態(tài),如當(dāng)前所使用的顏色察署、是否開啟混合等
- OpenGL可以接收輸入闷游,調(diào)用OpenGL函數(shù)時相當(dāng)于OpenGL接收輸入,如調(diào)用glColor3f贴汪,OpenGL會修改當(dāng)前顏色的狀態(tài)
- OpenGL停止工作脐往,程序退出前OpenGL會先停止工作
頂點數(shù)組(VertexArray)和頂點緩沖區(qū)(VertexBuffer)
- 頂點數(shù)據(jù)由GPU處理
- 頂點數(shù)組:OpenGL中圖像都是由圖元組成的,在OpenGL ES中扳埂,有3種類型的圖元:點业簿、線、三角形阳懂,頂點數(shù)組用來存儲他們的頂點數(shù)據(jù)梅尤,頂點數(shù)組存儲在內(nèi)存中
- 頂點緩沖區(qū):高性能的做法是提前分配一塊顯存,將頂點數(shù)據(jù)預(yù)先傳入到顯存當(dāng) 中岩调,這部分的顯存巷燥,就被稱為頂點緩沖區(qū),頂點緩沖區(qū)存儲在顯卡的顯存中
管線
- 顯卡在處理數(shù)據(jù)的時候是按照一個固定的順序來執(zhí)行的号枕,而且嚴(yán)格按照這個順序缰揪,像流水線一樣,所以稱之為管線葱淳,這個順序就是渲染流程邀跃。
- 固定管線/存儲著色器:OpenGL封裝了很多種著色器程序塊,內(nèi)置一段包含了光 照蛙紫、坐標(biāo)變換、裁剪等等諸多功能的固定shader程序途戒,來幫助開發(fā)者來完成圖形的渲染
著色器程序shader
- shader:自定義可編程管線坑傅,操作GPU芯片計算數(shù)據(jù)。
OpenGL ES3.0只支持頂點著色器和片元著色器這兩個最基礎(chǔ)的著色器喷斋。 - OpenGL處理shader的流程
OpenGL在處理shader時唁毒,通過編譯、鏈接等步驟星爪,?成了著色器程序(glProgram)浆西,著色器程序同時包含了頂點著?器和?元著?器的運算邏輯。在OpenGL進行繪制的時候顽腾,首先由頂點著?器對傳?的頂點數(shù)據(jù)進?運算近零,再通過圖元裝配诺核,將頂點轉(zhuǎn)換為圖元,然后進?光柵化久信,將圖元這種?量圖形轉(zhuǎn)換為柵格化數(shù)據(jù)窖杀,最后將柵格化數(shù)據(jù)傳入?元著?器中進?運算。?元著?器會對柵格化數(shù)據(jù)中的每一個像素進行運算裙士,并決定像素的顏?入客,從而形成一個圖形圖像。
- 頂點著色器VertexShader:計算頂點屬性腿椎,用來處理圖形每個頂點的變化桌硫,如旋轉(zhuǎn)、平移啃炸、投影等
- 片元著色器FragmentShader:計算像素顏色铆隘,用來處理圖形中每個像素點顏色的計算和填充
GLSL語言
- OpenGL的著色語言,在GPU上執(zhí)行
- GLSL的著色器代碼分兩個部分:頂點著色器VertexShader和片元著色器FragmentShader
光柵化Rasterization
- 把頂點數(shù)據(jù)轉(zhuǎn)換為片元的過程肮帐,將圖轉(zhuǎn)化為一個個柵格組成的圖像咖驮,把物體的數(shù)學(xué)描述以及顏色信息轉(zhuǎn)換為屏幕上對應(yīng)位置的像素及填充像素的顏色
紋理
- 實際是位圖,可以理解為圖片训枢,渲染圖形時填充圖片使場景更加逼真
混合Blending
- 兩種顏色重合時的顏色計算托修,使用顏色混合方程式
變換矩陣Transformation
- 圖形發(fā)生平移、縮放恒界、旋轉(zhuǎn)等會使用變換矩陣
投影矩陣Projection
- 將3D坐標(biāo)轉(zhuǎn)換為二維屏幕坐標(biāo)睦刃,實際線條也在二維坐標(biāo)下進行繪制
渲染緩沖區(qū)
- 將圖像直接渲染到窗口對應(yīng)的渲染緩沖區(qū),圖像就可以顯示到屏幕上
但是每個窗口只有一個緩沖區(qū)十酣,如果在繪制過程中屏幕進行了刷新涩拙,窗?可能顯示出不完整的圖像,所以常規(guī)的OpenGL程序至少都會有兩個緩沖區(qū)耸采,顯示在屏幕上的稱為屏幕緩沖區(qū)兴泥,沒有顯示的稱為離屏緩沖區(qū),在一個緩沖區(qū)渲染完成之后虾宇,通過將屏幕緩沖區(qū)和離屏緩沖區(qū)交換搓彻,實現(xiàn)圖像在屏幕上的顯示。由于顯示器的刷新一般是逐?進?的嘱朽,因此為了防?交換緩沖區(qū)的時候屏幕上下區(qū)域的圖像分屬于兩個不同的幀旭贬,因此交換一般會等待顯示器刷新完成的信號,在顯示器兩次刷新的間隔中進?交換搪泳,這個信號就被稱為垂直同步信號稀轨,這個技術(shù)被稱為垂直同步。使?了雙緩沖區(qū)和垂直同步技術(shù)之后岸军,由于總是要等待緩沖區(qū)交換之后再進?下一幀的渲染奋刽,使得幀率無法完全達到硬件允許的最高水平瓦侮。為了解決這個問題,引?了三緩沖區(qū)技術(shù)杨名,在等待垂直同步時蓉冈,來回交替渲染兩個離屏的緩沖區(qū)福铅,而垂直同步發(fā)生時吃度,屏幕緩沖區(qū)和最近渲染完成的離屏緩沖區(qū)交換匹涮,實現(xiàn)充分利用硬件性能的?的。
- 坐標(biāo)系相關(guān)
視口
- glviewPort()設(shè)置視口趁蕊,映射需要顯示的窗口區(qū)域坞生,一般視口與窗口等大
投影
透視投影:觀察者距離的遠(yuǎn)近也就是視角的大小會影響物體的大小,遠(yuǎn)小近大掷伙,立體圖形一般使用透視投影
GLFrustum::SetPerspective(float fFov, float fAspect, float fNear, float fFar); // fFov:垂直方向上的視場角度是己;fAspect:窗口的寬度與高度的縱橫比;fNear:近裁剪面距離任柜;fFar:遠(yuǎn)裁剪面距離卒废;縱橫比=寬(w)/高(h)
正投影:遠(yuǎn)近不影響物體大小,平面圖形一般使用正投影
GLFrustum::SetOrthographic(GLfloat xMin, GLfloat xMax, GLfloat yMin, GLfloat yMax, GLfloat zMin, GLfloat zMax,); // 正投影設(shè)置獲取投影矩陣宙地,設(shè)置x摔认、y、z軸上的最小和最大值宅粥,是一個區(qū)間参袱,一般設(shè)置的區(qū)間沒有太大調(diào)整
攝像機坐標(biāo)系
- 觀察者的位置,一般在原點(0,0,0)秽梅,
標(biāo)準(zhǔn)化設(shè)備坐標(biāo)系NDC范圍是[-1, 1]
世界坐標(biāo)系:描述世界空間抹蚀,在大的環(huán)境里的位置,表示系統(tǒng)絕對坐標(biāo)系
物體坐標(biāo)系:局部空間坐標(biāo)系企垦、物體空間坐標(biāo)系环壤,描述局部空間、物體本身钞诡,物體所在的位置坐標(biāo)系
攝像機坐標(biāo)系:觀察空間郑现,描述觀察坐標(biāo)系的空間,觀察者角度的坐標(biāo)系
慣性坐標(biāo)系:物體坐標(biāo)系的旋轉(zhuǎn)臭增,是世界坐標(biāo)系平移后的坐標(biāo)系
裁剪空間:超過范圍后需要裁剪
屏幕空間:描述屏幕顯示坐標(biāo)系
MVP矩陣:描述物體發(fā)生的變化,model竹习、view誊抛、projection(投影)
圖形從坐標(biāo)頂點到渲染到屏幕需要經(jīng)歷的坐標(biāo)系轉(zhuǎn)換:
物體坐標(biāo)(object space)->模型變換(modeling transformation)->世界坐標(biāo)(world space)
->視變換(viewing transformation)(觀察者)->觀察者坐標(biāo)(eye space)
->投影變換(projection transformation)->裁剪坐標(biāo)(clip space)
->透視除法(perspective divide)->規(guī)范化設(shè)備坐標(biāo)(NDC space)
->視口變換(ViewPort mapping)->屏幕坐標(biāo)(screen space)
三、OpenGL環(huán)境搭建與測試
-
準(zhǔn)備資料
OpenGL環(huán)境搭建資料 -
創(chuàng)建MacOS工程整陌,工程名字自己起拗窃,使用Objective-C
創(chuàng)建MacOS工程 -
在General最底部Linked Frameworks and Libraries添加兩個系統(tǒng)庫OpenGL.framework 和 GLUT.framework
兩個系統(tǒng)庫 -
添加準(zhǔn)備好的資料include和libGLTools.a到工程中
在Bulid Settings找到Header Search Paths瞎领,拖入GLTools.h 和 glew.h
拖入GLTool.h 和 glew.h -
將libGLTools.a 直接拖到工程的==Frameworks== 文件夾里面,在Linked Frameworks and Libraries里將libGLTools.a刪除然后重新拖過來添加上随夸,另外刪除文件:AppDelegate.h 九默、 AppDelegate.m 、ViewController.h 宾毒、 ViewController.m 驼修、 main.m ; 創(chuàng)建 main.cpp文件
選擇C++ File
- 添加代碼到main.cpp
#include "GLShaderManager.h"
#include "GLTools.h"
#include <glut/glut.h>
GLBatch triangleBatch;
GLShaderManager shaderManager;
//窗口大小改變時接受新的寬度和高度,其中0,0代表窗口中視口的左下角坐標(biāo)诈铛,w乙各,h代表像素
void ChangeSize(int w,int h)
{
glViewport(0,0, w, h);
}
//為程序作一次性的設(shè)置
void SetupRC()
{
//設(shè)置背影顏色
glClearColor(0.1f,0.1f,0.1f,1.0f);
//初始化著色管理器
shaderManager.InitializeStockShaders();
//設(shè)置三角形,其中數(shù)組vVert包含所有3個頂點的x,y,笛卡爾坐標(biāo)對幢竹。
GLfloat vVerts[] = {
-0.5f,0.0f,0.0f,
0.5f,0.0f,0.0f,
0.0f,0.5f,0.0f,
};
//批次處理
triangleBatch.Begin(GL_TRIANGLES,3);
triangleBatch.CopyVertexData3f(vVerts);
triangleBatch.End();
}
//開始渲染
void RenderScene(void)
{
//清除一個或一組特定的緩沖區(qū)glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
//設(shè)置一組浮點數(shù)來表示紅色
GLfloat vRed[] = {1.0f,0.0f,0.0f,1.0f};
//傳遞到存儲著色器耳峦,即GLT_SHADER_IDENTITY著色器,這個著色器只是使用指定顏色以默認(rèn)笛卡爾坐標(biāo)第在屏幕上渲染幾何圖形
shaderManager.UseStockShader(GLT_SHADER_IDENTITY,vRed);
//提交著色器
triangleBatch.Draw();
//將在后臺緩沖區(qū)進行渲染焕毫,然后在結(jié)束時交換到前臺
glutSwapBuffers();
}
int main(int argc,char* argv[])
{
//設(shè)置當(dāng)前工作目錄蹲坷,針對MAC OS X
gltSetWorkingDirectory(argv[0]);
//初始化GLUT庫
glutInit(&argc, argv);
/*初始化雙緩沖窗口,其中標(biāo)志GLUT_DOUBLE邑飒、GLUT_RGBA循签、GLUT_DEPTH、GLUT_STENCIL分別指
雙緩沖窗口幸乒、RGBA顏色模式懦底、深度測試、模板緩沖區(qū)*/
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
//GLUT窗口大小罕扎,標(biāo)題窗口
glutInitWindowSize(800,600);
glutCreateWindow("Triangle");
//注冊回調(diào)函數(shù)
glutReshapeFunc(ChangeSize);
glutDisplayFunc(RenderScene);
//驅(qū)動程序的初始化中沒有出現(xiàn)任何問題聚唐。
GLenum err = glewInit();
if(GLEW_OK != err) {
fprintf(stderr,"glew error:%s\n",glewGetErrorString(err));
return 1;
}
//調(diào)用SetupRC
SetupRC();
glutMainLoop();
return 0;
}
- 將GLBatch.h、GLShaderManager.h腔召、GLTools.h杆查、GLTriangleBatch.h中報錯的頭文件引入由<>改為"",編譯時由<>系統(tǒng)引入臀蛛,改為""普通引入亲桦,點擊運行窗口出現(xiàn)一個三角形