Android OpenGL ES 開發(三)— 繪製四邊形

我的視頻課程(基礎):《(NDK)FFmpeg打造Android萬能音頻播放器》

我的視頻課程(進階):《(NDK)FFmpeg打造Android視頻播放器》

我的視頻課程(編碼直播推流):《Android視頻編碼和直播推流》

上一篇博客我們以繪製三角形爲例講了OpenGL的繪製流程,並按照自己的意願繪製出了一個紅色的三角形,那麼現在我們就可以開始繪製四邊形了。

繪製四邊形其實就是繪製2個三角形,然後拼接成一個四邊形。然兒具體怎麼繪製呢,OpenGL中是有一定的規則的,下面我們就來看看一些常用的繪製方式:

首先我們看看OpenGL中的glDrawArray函數,這裏需要注意的是:在OpenGL中所有組合的圖形的繪製方向必須一致。

要麼都是順時針,要麼都是逆時針。

1、第一種繪製四邊形的方式

我們繪製三角形是這樣繪製的:

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

 這裏我們需要注意的就是第一個參數:GL_TRIANGLES,表示繪製三角形模式。然後第二個參數表示:從我們的頂點數組的哪個位置開始,然後第三個參數表示繪製幾個頂點。它會依次從頂點數組0開始繪製三個點組成一個三角形,這樣就把三角形繪製出來了。

然兒需要繪製四邊形的話,需要2個三角形,所以我們需要6個頂點,前面三個組成一個三角形,後面三個組成另一個三角形,比如我們繪製如下三角形:

那麼在GL_TRIANGLES繪製模式下,我們的2個三角形可以是(前提繪製方向一致)(v1,v2,v3)和(v2,v4,v3)也可以是其他組合方式,然後頂點數組我們就得按照頂點的順序把座標寫進去就是:

private float[] vertexData ={
            
            //第一個三角形座標
            -1f, 0f,
            0f, -1f,
            0f, 1f,

            //第二個三角形座標
            0f, -1f,
            1f, 0f,
            0f, 1f

    };

這樣我們的繪製方式就是從頂點數組的第0個元素開始,依次繪製6個元素就可以了:

GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6);

OpenGL就會先繪製前面三個點組成第一個三角形,再繪製後面3個點組成第二個三角形,最終展現出來的就是一個四邊形了。

2、第二種繪製四邊形的方式:

前面一種繪製四邊形或多邊形的方式比較簡單,需要繪製多少個就寫出多少個三角形的座標就行,然後依次繪製,然兒當繪製組個圖形時可能會寫許多重複的座標,也會導致內存的增大。所以OpenGL中還有另一個種繪製四邊形的方式,即用GL_TRIANGLE_STRIP(三角形帶的方式,其思路就是相鄰2個三角形共用一條邊,這樣繪製四邊形就不需要6個頂點了,只需要4個頂點就可以了。

我們還是以前面繪製的四邊形爲例,用GL_TRIANGLE_STRIP的方式來繪製四邊形,我們先來看一下繪製四邊形需要的其中一種頂點數組的排列方式:

    private float[] vertexData ={

            -1f, 0f,
            0f, -1f,
            0f, 1f,
            1f, 0f

    };

然後繪製的代碼如下:

GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);

 

那麼這裏OpenGL是怎麼繪製的呢?其實OpenGL繪製的第一個三角形是:(v1,v2,v3),第二個三角形是:(v3,v2,v4),這裏就需要牽扯到一個繪製的公式了,其中n表示頂點的索引值:

偶數:n-1, n-2, n

奇數:n-2, n-1, n

這個公式怎麼看呢?

1、首先我們可以確定的就是(v1,v2)第一條邊的座標,而且繪製方向是逆時針

2、然後接下來就是繪製第三個點的座標了,那麼第三個點就根據公式來,因爲是繪製第三個點,所以索引(n==3)然後3是奇數,根據公式得出(3-2,3-1,3)即:(v1,v2,v3)第一個三角形,而此時v3的座標可以是(0,1)也可以是(1,0),並且都是逆時針滿足條件;

3、接下來繪製第四個頂點了,此時(n==4)是偶數,根據公式得出(4-1,4-2,4)即:(v3,v2,v4):

3.1、當v3的座標是(0,1)的時候v4就只能是(1,0)了,那麼(v3,v2,v4)是逆時針並且和第一個三角形共用一條邊(v2,v3)滿足條件

3.2、當v3的座標是(1,0)時,v4座標是(0,1),此時(v3,v2,v4)是順時針不滿足條件

4、所以這樣就能確定四個點的座標了,就如圖所示,然後依次寫出座標就是(v1,v2,v3,v4),也就是我們定義的頂點數組的值。

3、主要源碼

頂點着色器:

attribute vec4 av_Position;
void main(){
    gl_Position = av_Position;
}

片源着色器:

precision mediump float;
uniform vec4 af_Color;
void main(){
    gl_FragColor = af_Color;
}

Render:

package com.ywl5320.opengldemo;

import android.content.Context;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

public class WlRender implements GLSurfaceView.Renderer{


    private Context context;

    private final float[] vertexData ={
//            -1f, 0f,
//            0f, -1f,
//            0f, 1f,
//
//
//            0f, -1f,
//            1f, 0f,
//            0f, 1f

            -1f, 0f,
            0f, -1f,
            0f, 1f,
            1f, 0f

    };
    private FloatBuffer vertexBuffer;
    private int program;
    private int avPosition;
    private int afColor;



    public WlRender(Context context)
    {
        this.context = context;
        vertexBuffer = ByteBuffer.allocateDirect(vertexData.length * 4)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer()
                .put(vertexData);
        vertexBuffer.position(0);
    }


    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {

        String vertexSource = WlShaderUtil.readRawTxt(context, R.raw.vertex_shader);
        String fragmentSource = WlShaderUtil.readRawTxt(context, R.raw.fragment_shader);
        program = WlShaderUtil.createProgram(vertexSource, fragmentSource);
        if(program > 0)
        {
            avPosition = GLES20.glGetAttribLocation(program, "av_Position");
            afColor = GLES20.glGetUniformLocation(program, "af_Color");
        }
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        GLES20.glViewport(0, 0, width, height);
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
        GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
        GLES20.glUseProgram(program);
        GLES20.glUniform4f(afColor, 1f, 0f, 0f, 1f);
        GLES20.glEnableVertexAttribArray(avPosition);
        GLES20.glVertexAttribPointer(avPosition, 2, GLES20.GL_FLOAT, false, 8, vertexBuffer);
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);



    }
}

總結:通過繪製四邊形(理論上是多邊形),我們知道了OpenGL的一些繪製規則,這有利於我們在以後的開發中組合出更復雜的圖形,達到更酷炫的效果。好了OpenGL繪製四邊形就講到這裏了!

最終效果圖如下:

 

示例源碼地址:

GitHub:Android-OpenGL-ES

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章