OpenGL 教程(1):Android OpenGL ES 之畫三角形

本文主要介紹入門基于Android OpenGL ES的Hello world工程基本環(huán)境搭建。

效果圖

概要

  • 編譯OpenGL 程序
  • 配置相關(guān)頂點(diǎn)數(shù)據(jù)
  • 繪制操作

介紹

使用OpenGL繪制圖形時(shí),類似向服務(wù)器發(fā)起各種繪制的請求,本地端代碼其實(shí)就是圍繞著如何發(fā)起請求、組織數(shù)據(jù),因此OpenGL其實(shí)是一個(gè)大的狀態(tài)機(jī),接收各種指令而進(jìn)行繪制操作。

編譯OpenGL 程序

既然OpenGL是在服務(wù)器端運(yùn)行的,它肯定也需要運(yùn)行代碼的。OpenGL的代碼是由本地提交源文件,進(jìn)行編譯、連接、運(yùn)行的,這和C語言的運(yùn)行的流程是一致的。
OpenGL上運(yùn)行代碼分為頂點(diǎn)著色器和片段著色器,頂點(diǎn)著色器是告訴GPU三角形的三個(gè)頂點(diǎn)是在哪里畫,片段著色器是告訴GPU這個(gè)三角形中每個(gè)像素是要畫成什么樣的顏色。如何來表示這個(gè)邏輯,OpenGL用的是自己的GLSL語言,這其實(shí)也跟C語言是差不多的。

version 300 es           
in vec4 vPosition;          
void main()                 
 {                            
    gl_Position = vPosition;  
}  

以上是頂點(diǎn)著色器的代碼,“gl_Position = vPosition ”中,gl_Position 是內(nèi)置變量,其實(shí)就是告訴CPU當(dāng)前要在哪個(gè)位置頂點(diǎn)。編譯一個(gè)OpenGL 代碼實(shí)現(xiàn)如下:

String vShaderStr =
   "#version 300 es               \n"
   +   "in vec4 vPosition;           \n"
   + "void main()                  \n"
   + "{                            \n"
   + "   gl_Position = vPosition;  \n"
   + "}                            \n";

String 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";

int vertexShader;
int fragmentShader;
int programObject;
int[] linked = new int[1];

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

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

if ( programObject == 0 )
{
   return;
}

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

// Bind vPosition to attribute 0
GLES30.glBindAttribLocation ( programObject, 0, "vPosition" );

// Link the program
GLES30.glLinkProgram ( programObject );

// Check the link status
GLES30.glGetProgramiv ( programObject, GLES30.GL_LINK_STATUS, linked, 0 );

if ( linked[0] == 0 )
{
   Log.e ( TAG, "Error linking program:" );
   Log.e ( TAG, GLES30.glGetProgramInfoLog ( programObject ) );
   GLES30.glDeleteProgram ( programObject );
   return;
}

其中加載編譯任一著色器代碼如下:

private int LoadShader ( int type, String shaderSrc )
   {
      int shader;
      int[] compiled = new int[1];

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

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

      // Load the shader source
      GLES30.glShaderSource ( shader, shaderSrc );

      // Compile the shader
      GLES30.glCompileShader ( shader );

      // Check the compile status
      GLES30.glGetShaderiv ( shader, GLES30.GL_COMPILE_STATUS, compiled, 0 );

      if ( compiled[0] == 0 )
      {
         Log.e ( TAG, GLES30.glGetShaderInfoLog ( shader ) );
         GLES30.glDeleteShader ( shader );
         return 0;
      }

      return shader;
   }

以上的所有操作就是給GPU準(zhǔn)備一個(gè)可供著色器運(yùn)行的程序,但是目前仍沒有上傳數(shù)據(jù)。

上傳渲染數(shù)據(jù)

說明

上傳給著色器的數(shù)據(jù)分為兩種:
屬性數(shù)據(jù)(Attribute):如頂點(diǎn)位置、紋理坐標(biāo)、用于光線計(jì)算的表面法線用于計(jì)算屏幕上每個(gè)頂點(diǎn)的最終位置,針對(duì)每個(gè)頂點(diǎn)著色器都會(huì)執(zhí)行一次
Uniform數(shù)據(jù): 我在理解中,屬性數(shù)據(jù)如果相當(dāng)于常量數(shù)據(jù),那么Uniform相當(dāng)于程序中的變量,每次渲染時(shí)CPU都可以給其上傳一個(gè)新的值供著色器使用

上傳數(shù)據(jù)

要上傳數(shù)據(jù)給CPU,需要先綁定頂點(diǎn)著色器的位置:

GLES30.glBindAttribLocation ( programObject, 0, "vPosition" );

以上綁定程序programObject頂點(diǎn)著色器的vPosition屬性變量的標(biāo)識(shí)下標(biāo)為0,該下標(biāo)是對(duì)vPosition操作的標(biāo)識(shí),接下來上傳頂點(diǎn)數(shù)據(jù) :

GLES30.glVertexAttribPointer ( 0, 3, GLES30.GL_FLOAT, false, 0, mVertices );
GLES30.glEnableVertexAttribArray ( 0 );

glVertexAttribPointer用來上傳頂點(diǎn)數(shù)據(jù)

public static void glVertexAttribPointer(
        int indx,
        int size,
        int type,
        boolean normalized,
        int stride,
        java.nio.Buffer ptr
    )

上傳數(shù)據(jù)的參數(shù)比較多,涵義如下:

int index,//屬性數(shù)據(jù)下標(biāo)位置,也就是之前綁定的下標(biāo)
int size,//每個(gè)頂點(diǎn)有多少個(gè)分量與其關(guān)聯(lián),如果只使用(x,y),那就是2
int type,//頂點(diǎn)的數(shù)據(jù)類型
boolean normalized,//type為整形有意義
int stride,//一個(gè)數(shù)據(jù)存儲(chǔ)于多個(gè)屬性時(shí),表示每個(gè)頂點(diǎn)的跨距
java.nio.Buffer ptr//數(shù)據(jù)區(qū)

繪制圖形

直接使用頂點(diǎn)數(shù)據(jù)不使用VBO來繪制使用的是:

void glDrawArrays(  GLenum      mode,
    GLint   first,
    GLsizei     count);

對(duì)應(yīng)在本程序中使用:

GLES30.glDrawArrays ( GLES30.GL_TRIANGLES, 0, 3 );

mode 指繪制模式,包括點(diǎn)、線、三角形等方式
first 指原來頂點(diǎn)數(shù)據(jù)的以指定的size(3)切分之后的起始坐標(biāo)
count 指繪制3個(gè)三個(gè)形

結(jié)語

示例代碼

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容