各平臺(tái)渲染標(biāo)準(zhǔn):
win32 : OpenGL?,DirectX
android: Skia/Canvas ?(安卓SDK滑黔,2d) ,?OpenGL ES +NDK
mac/ios :Quartz2D,OpenGL ES?
Linux: OpenGL
wp7:DirectX
win8/wp8 : DirectX
游戲引擎基于的渲染標(biāo)準(zhǔn):
HTML5: Canvas/WebGL?
Unity3D:OpenGL
Cocos2d-x:OpenGL ES/DirectX/Canvas(Html5版本)
一、OpenGL初識(shí)
1朗儒、什么是OpenGL??一般認(rèn)為OpenGL是?一個(gè)圖形渲染庫(kù)摇肌,然?而并不不是烟零,OpenGL只是?包含了一系列操作圖形、圖像的函數(shù)的規(guī)范暴备。嚴(yán)格規(guī)定了每個(gè)函數(shù)如何執(zhí)行悠瞬,以及它 們的輸出值,而具體每個(gè)函數(shù)是如何實(shí)現(xiàn)的涯捻,是由顯卡開(kāi)發(fā)商自行決定的浅妆。 作為用戶不會(huì)感受到功能上的差異。
2障癌、代碼風(fēng)格OpenGL自身是一個(gè)巨大的狀態(tài)機(jī)凌外,OpenGL定義了很多狀態(tài)設(shè)置函
數(shù),通過(guò)設(shè)置函數(shù)參數(shù)的不同選項(xiàng)涛浙,達(dá)到不同的渲染效果康辑。
// 創(chuàng)建對(duì)象
unsigned int objectId = 0;
glGenObject(1, &objectId);
// 綁定對(duì)象至上下文
glBindObject(GL_WINDOW_TARGET, objectId);
// 設(shè)置當(dāng)前綁定到 GL_WINDOW_TARGET 的對(duì)象的一些選項(xiàng)
glSetObjectOption(GL_WINDOW_TARGET,GL_OPTION_WINDOW_WIDTH, 800);
glSetObjectOption(GL_WINDOW_TARGET,GL_OPTION_WINDOW_HEIGHT, 600);
//?將上下文對(duì)象設(shè)回默認(rèn)
glBindObject(GL_WINDOW_TARGET, 0);
3摄欲、GLFW庫(kù)
?? ? 跟系統(tǒng)相關(guān)的操作,如創(chuàng)建顯示窗口疮薇、處理用戶輸入胸墙、創(chuàng)建OpengGL上下文,不同的操作系統(tǒng)是不一樣的按咒,所以O(shè)penGL讓開(kāi)發(fā)者根據(jù)不同的平臺(tái)自己去處理迟隅。這些都有人會(huì)寫(xiě)好了, GLUT励七、SDL智袭、SFML、GLFM這些庫(kù)剛好提供了一個(gè)窗口和上下文用來(lái)渲染掠抬。
?? ? GLFW是一個(gè)專門(mén)針對(duì)OpenGL的C語(yǔ)言庫(kù)吼野,允許用戶創(chuàng)建上下文、定義窗口參數(shù)以及用戶輸入剿另。
4箫锤、GLAD
? ? ? OpenGL的函數(shù)的具體實(shí)現(xiàn)是由驅(qū)動(dòng)開(kāi)發(fā)商針對(duì)特定顯卡實(shí)現(xiàn)的。開(kāi)發(fā)者在調(diào)用每一個(gè)函數(shù)時(shí)需要運(yùn)行時(shí)獲取函數(shù)地址將其保存在一個(gè)函數(shù)指針中供以后使用雨女,如下:?
//?定義函數(shù)原型
typedef?void?(*GL_GENBUFFERS) (GLsizei, GLuint*);
//?找到正確的函數(shù)并賦值給函數(shù)指針
GL_GENBUFFERS glGenBuffers=(GL_GENBUFFERS)wglGetProcAddress(“glGenBuffers”);
//?現(xiàn)在函數(shù)可以被正常調(diào)用了
GLuint buffer;
glGenBuffers(1, &buffer);
這個(gè)操作使代碼復(fù)雜而且繁瑣谚攒。 GLAD是一個(gè)開(kāi)源的庫(kù),幫我們實(shí)現(xiàn)了運(yùn)行時(shí)查詢OpenGL函數(shù)實(shí)現(xiàn)的這個(gè)動(dòng)作氛堕。GLAD使用了一個(gè)在線服務(wù)(https://glad.dav1d.de/)馏臭,我們?cè)O(shè)置不同OpenGL版本的會(huì)得到相對(duì)應(yīng)的庫(kù)。加載這個(gè)庫(kù)讼稚, 我們就是可以直接使用如上glGenBuffers函數(shù)括儒,而無(wú)需寫(xiě)動(dòng)態(tài)查詢地址的代碼。
二锐想、OpenGL基礎(chǔ)概念
? ? 1帮寻、圖形渲染管線
?? ? ? ? 圖像渲染管線指的是一堆原始圖形數(shù)據(jù)途經(jīng)一個(gè)輸送管道,期間經(jīng)過(guò)各種變化處理最終出現(xiàn)在屏幕的過(guò)程赠摇。下圖是圖形渲染管線的每個(gè)階段的抽象展示固逗。藍(lán)色部分我們可以注入自定義的著色器。
2藕帜、頂點(diǎn)輸入
?? 頂點(diǎn)數(shù)組對(duì)象:Vertex Array Object烫罩,VAO
? 頂點(diǎn)緩沖對(duì)象:Vertex Buffer Object,VBO
GPU內(nèi)存中存儲(chǔ)大量頂點(diǎn)的對(duì)象洽故。使用這些對(duì)象可以一性發(fā)送大批數(shù)據(jù)到顯卡上供點(diǎn)著色器訪問(wèn)贝攒。
float vertices[] = {
? ? -0.5f, -0.5f, 0.0f,
? ? 0.5f, -0.5f, 0.0f,
? ? 0.0f,? 0.5f, 0.0f
};
//獲取一個(gè)頂點(diǎn)緩沖對(duì)象
unsigned int VBO,VAO;
glGenBuffers(1, &VBO);
glGenVertexArrays(1, &VAO);
//綁定緩沖對(duì)象
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);?
//將頂點(diǎn)數(shù)據(jù)復(fù)制到緩沖內(nèi)存中
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
//設(shè)置著色器獲取頂點(diǎn)數(shù)據(jù)的指針
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
OpenGL的坐標(biāo)x、y时甚、z軸的坐標(biāo)范圍是(-1.0隘弊,1.0)
3哈踱、頂點(diǎn)著色器
?? ? ? 渲染管線的每一個(gè)階段運(yùn)行著自己的小程序,快速處理圖像數(shù)據(jù)长捧,這些小程序就叫做著色器嚣鄙。
?? ? ? GLSL: OpenGl著色器是用OpenGL著色器語(yǔ)言(OpenGL Shading Language)寫(xiě)成的吻贿。
? ? ? 頂點(diǎn)著色器:主要目的是將一種3D坐標(biāo)轉(zhuǎn)換為另外一種3D坐標(biāo)串结。同時(shí)允許我們對(duì)頂點(diǎn)屬性進(jìn)行一些基本處理。下面為一個(gè)簡(jiǎn)單GLSL頂點(diǎn)著色器的源代碼:?
#version 330 core
layout (location = 0) in vec3 aPos;
void main()
{
? ?gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
}
3舅列、片段著色器
?? ? 片段著色器所做的事計(jì)算像素最后的顏色輸出肌割。輸出由RGBA4個(gè)分量組成,每個(gè)值的范圍是0.0-1.0之間帐要。?
#version 330 core
out vec4 FragColor;
void main()
{
? ? FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
}
4把敞、著色器程序
? ? ? 我們需要對(duì)著色器源碼進(jìn)行編譯,并鏈接到一個(gè)著色器程序上榨惠,然后就可以使用著色器進(jìn)行渲染了奋早。?
//編譯頂點(diǎn)著色器
? ? unsigned int vertexShader;
? ? vertexShader = glCreateShader(GL_VERTEX_SHADER);
? ? glShaderSource(vertexShader,1,&vertexShaderSource,NULL);
? ? glCompileShader(vertexShader);
? ? ? //編譯片段著色器
? ? unsigned int fragmentShader1;
? ? fragmentShader1 =? glCreateShader(GL_FRAGMENT_SHADER);
? ? glShaderSource(fragmentShader1,1,&fragmentShaderSource1,NULL);
? ? glCompileShader(fragmentShader1);
上面的vertexShaderSource,fragmentShaderSource1可以定義為著色器代碼的字符串格式赠橙。
鏈接著色器程序耽装,獲取一個(gè)著色器程序?qū)ο?
//著色器程序
? ? unsigned int shaderProgram1;
? ? shaderProgram1? = glCreateProgram();
? ? glAttachShader(shaderProgram1,vertexShader);
? ? glAttachShader(shaderProgram1,fragmentShader1);
? ? glLinkProgram(shaderProgram1);
?設(shè)置渲染參數(shù),進(jìn)行渲染?
//設(shè)置好需要輸入的頂點(diǎn)
glBindVertexArray(VAO);
//設(shè)置好著色器程序
glUseProgram(shaderProgram1);
//畫(huà)三角形
glDrawArrays(GL_TRIANGLES, 0, 3);
5期揪、GLM庫(kù)
? ? ? GLM是OpenGL?Mathematics的縮寫(xiě)掉奄,它是一個(gè)只有頭文件的庫(kù)。 是一個(gè)數(shù)學(xué)庫(kù)凤薛,能夠滿足變換所需要的矩陣運(yùn)算姓建。
6、 紋理(Texture)
?? 紋理通常是一個(gè)2D圖片(也有3D的),用來(lái)豐富物體的細(xì)節(jié)缤苫。 紋理中包含了大量的數(shù)據(jù)速兔,并通過(guò)一定的方式給到著色器。通過(guò)測(cè)試活玲、混合等后期處理涣狗,可以渲染出炫酷的效果。