1. 程式人生 > >Android OpenGL ES2.0 實現步驟

Android OpenGL ES2.0 實現步驟

定義頂點資料

頂點資料描述了OpenGL世界中元素的位置,下面定義了繪製一個三角形所需要的頂點資料,x,y,z對應三角形的每個頂點座標,其中z代表深度,x1,y1對應著色器的顏色程式碼。

float vertices[] = {
            // x      y     z     x1    y1
            0.0f, 1.0f, 0.0f, 0.3f, 1.0f,
            -0.8f, -0.8f, 0f, 0.0f, 0.0f,
            0.8f, -0.8f, 0.0f, 0.6f, 0.0f,
    };

頂點資料轉換

java的資料結構在opengl中無法直接使用,我們需要轉成OpenGL能識別的buffer格式,我們將上面建立的頂點資料轉換成了ByteBuffer型別。

ByteBuffer verticesByteBuffer = ByteBuffer.allocateDirect(vertices.length * 4).order(ByteOrder.nativeOrder());
            verticesFloatBuffer = verticesByteBuffer.asFloatBuffer().put(vertices);
            verticesFloatBuffer.position(0);

編寫頂點和片段著色器

頂點著色器定義了vec3型別的位置屬性aPosition,它的長度為3,與上面的頂點陣列中的x,y,z相對應。aTexCoord代表紋理座標,它與頂點陣列中的x1,y1列相對應。

    private final String mVertexShader =
            "varying vec2 texCoord;\n" +
                    "attribute vec3 aPosition;\n" +
                    "attribute vec2 aTexCoord;\n" +

                    "void main() {\n" +
                    "  gl_Position = vec4(aPosition,1);\n" +
                    "  texCoord = aTexCoord;\n"
+ "}\n"; private final String mFragmentShader = "varying vec2 texCoord;\n" + "uniform sampler2D sTexture;\n" + "void main() {\n" + " gl_FragColor = texture2D(sTexture,texCoord);\n" + "}\n";

建立頂點&著色器Shader

這個過程是將編寫的頂點指令碼和著色器指令碼函式進行編譯,編譯完後將返回對應shader的控制代碼id

int vertexShader = createMyShader(GL_VERTEX_SHADER, mVertexShader);
int fragmentShader = createMyShader(GL_FRAGMENT_SHADER, mFragmentShader);

    private int createMyShader(int type, String textCode) {
        int shader = glCreateShader(type);
        glShaderSource(shader, textCode);
        glCompileShader(shader);
        //<editor-fold desc="檢查是否錯誤">
        int[] compiled = new int[1];
        glGetShaderiv(shader, GL_COMPILE_STATUS, compiled, 0);
        checkGlError("createMyShader");
        if (compiled[0] == 0) {
            glDeleteShader(shader);
            shader = 0;
        }
        //</editor-fold>
        return shader;
    }

建立GLProgram

建立gl程式的最核心的部分其實是將頂點shader和著色器shader與program進行關聯,從progam中獲取maPositionHandle和maTexCoordHandle的目的是為了方便後面進行頂點屬性說明是用到。

int program = createMyProgram(vertexShader, fragmentShader);

private int createMyProgram(int vertexShader, int fragmentShader) {
        int program = glCreateProgram();
        if (program != 0) {
            GLES20.glAttachShader(program, vertexShader);
            checkGlError("glAttachShader");
            GLES20.glAttachShader(program, fragmentShader);
            checkGlError("glAttachShader");
            GLES20.glLinkProgram(program);
            int[] linkStatus = new int[1];
            GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
            if (linkStatus[0] != GLES20.GL_TRUE) {
                Log.e("TEST", "Could not link program: ");
                Log.e("TEST", GLES20.glGetProgramInfoLog(program));
                GLES20.glDeleteProgram(program);
                program = 0;
            }
        }
        return program;
    }
int maPositionHandle = glGetAttribLocation(program, "aPosition");
int maTexCoordHandle = glGetAttribLocation(program, "aTexCoord");

建立和繫結紋理

int[] textures = new int[1];
        GLES20.glGenTextures(1, textures, 0);
        mTextureID = textures[0];
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureID);

        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);

        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);

        InputStream is = getResources()
                .openRawResource(R.raw.ab);
        Bitmap bitmap;
        try {
            bitmap = BitmapFactory.decodeStream(is);
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                // Ignore.
            }
        }

        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
        bitmap.recycle();
        //啟用紋理
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        //繫結紋理
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureID);

頂點屬性說明

/**
*指定maPositionHandle對應3個大小float,20代表整個資料段的長
*度,最後一個引數代表offset值(表示讀取的偏移量)。
*整體可理解為:整個資料段長度為20位元組,正好是我們定義的頂點資料的一行的長度(5個浮點型座標),maPositionHandle需要12位元組長度(3個浮點型座標),讀取的偏移量是0,所以取的資料正好是前面的x,y,z座標。
**/
glVertexAttribPointer(maPositionHandle, 3, GL_FLOAT, false, 20, 0);
//啟用頂點屬性陣列
glEnableVertexAttribArray(maPositionHandle);
glVertexAttribPointer(maTexCoordHandle, 2, GL_FLOAT, false, 20, 12);
//啟用頂點屬性陣列
glEnableVertexAttribArray(maTexCoordHandle);

繪製元素

GLES20.glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glUseProgram(program);
glDrawArrays(GL_TRIANGLES, 0, 5);
GLES20.glUseProgram(0);