OpenGL ES 3.0 入門

一银舱、OpenGL ES簡介

OpenGL(Open Graphics Library)是指定義了一個跨編程語言、跨平臺的編程接口規(guī)格的專業(yè)的圖形程序接口判耕。它用于三維圖像(二維的亦可)透绩,是一個功能強(qiáng)大,調(diào)用方便的底層圖形庫壁熄。
OpenGL ES (OpenGL for Embedded Systems) 是 OpenGL 三維圖形 API 的子集帚豪,針對手機(jī)、PDA和游戲主機(jī)等嵌入式設(shè)備而設(shè)計草丧。(OpenGL ES可以在iOS上實(shí)現(xiàn)2D和3D圖形編程狸臣。)

** OpenGL ES 1.0、2.0昌执、3.0的區(qū)別: **

OpenGL ES1.0:
針對固定管線硬件(fixed pipeline)烛亦,通過它內(nèi)建的functions來設(shè)置諸如燈光、vertexes(圖形的頂點(diǎn)數(shù))懂拾、顏色煤禽、camera等等的東西。

OpenGL ES2.0:
針對可編程管線硬件(programmable pipeline)岖赋,需要自己動手編寫任何功能檬果。與此同時,2.0相比于1.0更具靈活性唐断,功能也更強(qiáng)大选脊。可以自定義頂點(diǎn)和像素計算脸甘,可以讓表現(xiàn)方式更加準(zhǔn)確恳啥。

OpenGL ES3.0:
OpenGL ES3.0擴(kuò)展了OpenGL ES2.0,支持許多新的渲染技術(shù)斤程、優(yōu)化和顯示質(zhì)量改進(jìn)角寸,包括——引入了許多和紋理相關(guān)的新功能菩混,對著色語言進(jìn)行了重大更新和支持著色器新功能的API特性忿墅,引入了多種與幾何形狀規(guī)范和圖元渲染控制相關(guān)的新功能扁藕,引入了新的緩沖區(qū)對象,增添了許多與屏幕外渲染到幀緩沖區(qū)對象相關(guān)的新功能疚脐。具體功能在后邊的文章詳細(xì)說明亿柑。(可能:))

** OpenGL ES 3.0的向后兼容新 **

OpenGL ES 3.0向后兼容OpenGL ES 2.0,但由于3.0/2.0不支持1.x支持的固定功能管線棍弄,3.0/2.0不能向后兼容1.x望薄。

** EGL/EAGL **

EGL是Khronos渲染API(如OpenGL ES)和原生窗口系統(tǒng)之間的接口(在iOS上則是EAGL),任何OpenGL ES應(yīng)用程序都必須在開始渲染之前使用EGL執(zhí)行如下任務(wù):

  • 查詢并初始化設(shè)備商可用的顯示器
  • 創(chuàng)建渲染表面
  • 創(chuàng)建渲染上下文

** OpenGL ES 3.0圖形管線的各個階段 **

OpenGL ES 3.0圖形管線的各個階段

二呼畸、Hello痕支,Triangle:第一個OpenGL ES 3.0程序

** 代碼地址如下 Hello_Triangle **

在此解釋一下** Hello_Triangle.c **的代碼

#include "esUtil.h"

typedef struct
{
   // Handle to a program object
   GLuint programObject;

} UserData;

///
// Create a shader object, load the shader source, and
// compile the shader.
//
GLuint LoadShader ( GLenum type, const char *shaderSrc )
{
   GLuint shader;
   GLint compiled;

   // Create the shader object
   shader = glCreateShader ( type );

   if ( shader == 0 )
   {
      return 0;
   }

   // Load the shader source
   glShaderSource ( shader, 1, &shaderSrc, NULL );

   // Compile the shader
   glCompileShader ( shader );

   // Check the compile status
   glGetShaderiv ( shader, GL_COMPILE_STATUS, &compiled );

   if ( !compiled )
   {
      GLint infoLen = 0;

      glGetShaderiv ( shader, GL_INFO_LOG_LENGTH, &infoLen );

      if ( infoLen > 1 )
      {
         char *infoLog = malloc ( sizeof ( char ) * infoLen );

         glGetShaderInfoLog ( shader, infoLen, NULL, infoLog );
         esLogMessage ( "Error compiling shader:\n%s\n", infoLog );

         free ( infoLog );
      }

      glDeleteShader ( shader );
      return 0;
   }

   return shader;

}

///
// Initialize the shader and program object
//
int Init ( ESContext *esContext )
{
   UserData *userData = esContext->userData;
   char vShaderStr[] =
      "#version 300 es                          \n"
      "layout(location = 0) in vec4 vPosition;  \n"
      "void main()                              \n"
      "{                                        \n"
      "   gl_Position = vPosition;              \n"
      "}                                        \n";

   char fShaderStr[] =
      "#version 300 es                              \n"
      "precision mediump float;                     \n"
      "out vec4 fragColor;                          \n"
      "void main()                                  \n"
      "{                                            \n"
      "   fragColor = vec4 ( 1.0, 0.0, 0.0, 1.0 );  \n"
      "}                                            \n";

   GLuint vertexShader;
   GLuint fragmentShader;
   GLuint programObject;
   GLint linked;

   // Load the vertex/fragment shaders
   vertexShader = LoadShader ( GL_VERTEX_SHADER, vShaderStr );
   fragmentShader = LoadShader ( GL_FRAGMENT_SHADER, fShaderStr );

   // Create the program object
   programObject = glCreateProgram ( );

   if ( programObject == 0 )
   {
      return 0;
   }

   glAttachShader ( programObject, vertexShader );
   glAttachShader ( programObject, fragmentShader );

   // Link the program
   glLinkProgram ( programObject );

   // Check the link status
   glGetProgramiv ( programObject, GL_LINK_STATUS, &linked );

   if ( !linked )
   {
      GLint infoLen = 0;

      glGetProgramiv ( programObject, GL_INFO_LOG_LENGTH, &infoLen );

      if ( infoLen > 1 )
      {
         char *infoLog = malloc ( sizeof ( char ) * infoLen );

         glGetProgramInfoLog ( programObject, infoLen, NULL, infoLog );
         esLogMessage ( "Error linking program:\n%s\n", infoLog );

         free ( infoLog );
      }

      glDeleteProgram ( programObject );
      return FALSE;
   }

   // Store the program object
   userData->programObject = programObject;

   glClearColor ( 1.0f, 1.0f, 1.0f, 0.0f );
   return TRUE;
}

///
// Draw a triangle using the shader pair created in Init()
//
void Draw ( ESContext *esContext )
{
   UserData *userData = esContext->userData;
   GLfloat vVertices[] = {  0.0f,  0.5f, 0.3f,
                            -0.5f, -0.5f, 0.5f,
                            0.5f, -0.5f, -0.4f
                         };

   // Set the viewport
   glViewport ( 0, 0, esContext->width, esContext->height );

   // Clear the color buffer
   glClear ( GL_COLOR_BUFFER_BIT );

   // Use the program object
   glUseProgram ( userData->programObject );

   // Load the vertex data
   glVertexAttribPointer ( 0, 3, GL_FLOAT, GL_FALSE, 0, vVertices );
   glEnableVertexAttribArray ( 0 );

   glDrawArrays ( GL_TRIANGLES, 0, 3 );
}

void Shutdown ( ESContext *esContext )
{
   UserData *userData = esContext->userData;

   glDeleteProgram ( userData->programObject );
}

int esMain ( ESContext *esContext )
{
   esContext->userData = malloc ( sizeof ( UserData ) );

   esCreateWindow ( esContext, "Hello Triangle", 375, 667, ES_WINDOW_RGB );

   if ( !Init ( esContext ) )
   {
      return GL_FALSE;
   }

   esRegisterShutdownFunc ( esContext, Shutdown );
   esRegisterDrawFunc ( esContext, Draw );

   return GL_TRUE;
}

** 1.使用OpenGL ES 3.0 框架 **

** int esMain ( ESContext esContext ) **
esMain函數(shù)為應(yīng)用程序的主入口,參數(shù)是ESContext蛮原。ESContext有一個名為userData卧须、類型為void
的成員變量,應(yīng)用程序所需的所有數(shù)據(jù)保存在userData中儒陨。ESContext結(jié)構(gòu)中的其他元素在頭文件中描述花嘶,供用戶的用用程序讀取。ESContext結(jié)構(gòu)中的其他數(shù)據(jù)包括窗口寬度和高度蹦漠、EGL上下文和回調(diào)函數(shù)指針等信息椭员。
在本程序的esMain中分配了userData、創(chuàng)建了窗口并初始化繪圖回調(diào)函數(shù)笛园。

** 2.創(chuàng)建頂點(diǎn)著色器和片斷著色器 **

** int Init ( ESContext *esContext ) **
要進(jìn)行任何渲染隘击,OpenGL ES 3.0程序必須至少有一個頂點(diǎn)著色器和一個片斷著色器。本程序中的Init函數(shù)最主要的任務(wù)是建在一個頂點(diǎn)著色器和一個片斷著色器研铆。

以頂點(diǎn)著色器為例說明:

   char vShaderStr[] =
      "#version 300 es                          \n"
      "layout(location = 0) in vec4 vPosition;  \n"
      "void main()                              \n"
      "{                                        \n"
      "   gl_Position = vPosition;              \n"
      "}

第一行聲明著色器版本闸度;
第二行聲明一個名為vPosition的4分量向量輸入屬性,layout(location=0)限定符表示這個變量的位置是頂點(diǎn)屬性0蚜印;
第三行開始聲明一個main函數(shù)莺禁,表示著色器執(zhí)行的開始,{}中是著色器主體窄赋,將vPosition輸入屬性拷貝到名為gl_Position的特殊輸出變量哟冬。每個頂點(diǎn)著色器必須在gl_Position變量中輸出一個位置,這個變量定義傳遞到管線下一個階段的位置忆绰。

** 3.編譯和加載著色器 **

** GLuint LoadShader ( GLenum type, const char *shaderSrc ) **
定義完著色器源代碼后浩峡,可以將著色器加載到OpenGL ES。LoadShader函數(shù)負(fù)責(zé)加載著色器源代碼错敢、編譯并檢查錯誤翰灾,它返回一個著色器對象缕粹,這是一個OpenGL ES 3.0對象,以后可用于連接到程序?qū)ο螅ê筮厱v到)纸淮。
以本程序的LoadShader為例:

GLuint shader;
GLint compiled;
// Create the shader object
shader = glCreateShader ( type );

if ( shader == 0 )
{
  return 0;
}

glCreateShader創(chuàng)建指定類型的新著色器對象平斩。

// Load the shader source
glShaderSource ( shader, 1, &shaderSrc, NULL );

// Compile the shader
glCompileShader ( shader );

著色器源代碼本身用glShaderSource加載到著色器對象,著色器用glCompileShader函數(shù)編譯咽块。

// Check the compile status
glGetShaderiv ( shader, GL_COMPILE_STATUS, &compiled );

if ( !compiled )
{
  GLint infoLen = 0;

  glGetShaderiv ( shader, GL_INFO_LOG_LENGTH, &infoLen );

  if ( infoLen > 1 )
  {
     char *infoLog = malloc ( sizeof ( char ) * infoLen );

     glGetShaderInfoLog ( shader, infoLen, NULL, infoLog );
     esLogMessage ( "Error compiling shader:\n%s\n", infoLog );

     free ( infoLog );
  }

  glDeleteShader ( shader );
  return 0;
}

return shader;

編譯著色器之后绘面,確定編譯的狀態(tài),打印輸出生成的錯誤侈沪。

如果著色器編譯成功揭璃,則返回一個新的著色器對象。

** 4.創(chuàng)建一個程序?qū)ο蟛⑦B接著色器 **

頂點(diǎn)和片段著色器需要連接到一個程序?qū)ο蟛拍芾L制圖形亭罪,可以說程序?qū)ο笫亲罱K連接的程序瘦馍。

// Create the program object
programObject = glCreateProgram ( );

if ( programObject == 0 )
{
return 0;
}

glAttachShader ( programObject, vertexShader );
glAttachShader ( programObject, fragmentShader );

用glCreateProgram創(chuàng)建程序?qū)ο螅⒂胓lAttachShader將頂點(diǎn)著色器和片斷著色器連接到對象上应役。

// Link the program
glLinkProgram ( programObject );

// Check the link status
glGetProgramiv ( programObject, GL_LINK_STATUS, &linked );

if ( !linked )
{
  GLint infoLen = 0;

  glGetProgramiv ( programObject, GL_INFO_LOG_LENGTH, &infoLen );

  if ( infoLen > 1 )
  {
     char *infoLog = malloc ( sizeof ( char ) * infoLen );

     glGetProgramInfoLog ( programObject, infoLen, NULL, infoLog );
     esLogMessage ( "Error linking program:\n%s\n", infoLog );

     free ( infoLog );
  }

  glDeleteProgram ( programObject );
  return FALSE;
}

// Store the program object
userData->programObject = programObject;

連接程序情组,檢查錯誤。對象連接成功后扛吞,可以使用程序?qū)ο筮M(jìn)行渲染呻惕。

// Use the program object
glUseProgram ( userData->programObject );

調(diào)用glUseProgram來使用程序?qū)ο蟆?/p>

** 5.設(shè)置視口和清除顏色緩沖區(qū) **

** void Draw ( ESContext *esContext ) **
Draw回調(diào)函數(shù)用于繪制幀。

// Set the viewport
glViewport ( 0, 0, esContext->width, esContext->height );

設(shè)置視口的原點(diǎn)和寬高

// Clear the color buffer
glClear ( GL_COLOR_BUFFER_BIT );

繪圖中涉及多種緩沖區(qū)類型:顏色滥比、深度和模板亚脆。在本程序中只向顏色緩沖區(qū)中繪制圖形。在每一幀開始的時候盲泛,我們用glClear清除緩沖區(qū)濒持,清除顏色為glClearColor指定的顏色。在本程序中寺滚,清除顏色被設(shè)為(1.0柑营, 1.0, 1.0村视, 1.0)官套。

** 6.加載幾何形狀和繪制圖元 **

清除顏色緩沖區(qū)、設(shè)置視口和加載程序?qū)ο笾笠峡祝枰贫ㄈ切蔚膸缀涡螤睢?/p>

GLfloat vVertices[] = {  0.0f,  0.5f, 0.3f,
                            -0.5f, -0.5f, 0.5f,
                            0.5f, -0.5f, -0.4f
                         };
...
// Load the vertex data
glVertexAttribPointer ( 0, 3, GL_FLOAT, GL_FALSE, 0, vVertices );
glEnableVertexAttribArray ( 0 );

glDrawArrays ( GL_TRIANGLES, 0, 3 );

三角形的頂點(diǎn)由vVertices數(shù)組中的三個坐標(biāo)(x奶赔, y, z)指定杠氢。頂點(diǎn)位置使用glVertexAttribPointer加載到GL站刑,并連接到頂點(diǎn)著色器生命的vPosition屬性。
最后鼻百,使用glDrawArrays告訴OpenGL ES繪制圖元绞旅。

** 7.顯示后臺緩沖區(qū) **

屏幕上可見的幀緩沖區(qū)有一個像素數(shù)據(jù)的二維數(shù)組表示摆尝。但是如果我們直接繪制到緩沖區(qū),那么用戶在部分更新幀緩沖區(qū)的時候會看到偽像因悲。為了解決這個問題堕汞,我們使用雙緩沖區(qū)(前臺緩沖區(qū)和后臺緩沖區(qū))。所有渲染都發(fā)生在后臺緩沖區(qū)(不可見緩沖區(qū))囤捻,當(dāng)渲染完成之后臼朗,這個緩沖區(qū)被交換到前臺緩沖區(qū)(可見緩沖區(qū))邻寿。然后前臺緩沖區(qū)變成下一幀的后臺緩沖區(qū)蝎土。這種活動通過eglSwapBuffers控制(調(diào)用Draw毀掉函數(shù)之后調(diào)用該函數(shù))。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末绣否,一起剝皮案震驚了整個濱河市誊涯,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蒜撮,老刑警劉巖暴构,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異段磨,居然都是意外死亡取逾,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進(jìn)店門苹支,熙熙樓的掌柜王于貴愁眉苦臉地迎上來砾隅,“玉大人,你說我怎么就攤上這事债蜜∏绻。” “怎么了?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵寻定,是天一觀的道長儒洛。 經(jīng)常有香客問我,道長狼速,這世上最難降的妖魔是什么琅锻? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮向胡,結(jié)果婚禮上恼蓬,老公的妹妹穿的比我還像新娘。我一直安慰自己捷枯,他們只是感情好滚秩,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著淮捆,像睡著了一般郁油。 火紅的嫁衣襯著肌膚如雪本股。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天桐腌,我揣著相機(jī)與錄音拄显,去河邊找鬼。 笑死案站,一個胖子當(dāng)著我的面吹牛躬审,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蟆盐,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼承边,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了石挂?” 一聲冷哼從身側(cè)響起博助,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎痹愚,沒想到半個月后富岳,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡拯腮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年窖式,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片动壤。...
    茶點(diǎn)故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡萝喘,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出狼电,到底是詐尸還是另有隱情蜒灰,我是刑警寧澤,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布肩碟,位于F島的核電站强窖,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏削祈。R本人自食惡果不足惜翅溺,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望髓抑。 院中可真熱鬧咙崎,春花似錦、人聲如沸吨拍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽羹饰。三九已至伊滋,卻和暖如春碳却,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背笑旺。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工昼浦, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人筒主。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓关噪,卻偏偏與公主長得像,于是被迫代替她去往敵國和親乌妙。 傳聞我的和親對象是個殘疾皇子使兔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評論 2 348

推薦閱讀更多精彩內(nèi)容