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

 

 

 

 

猜你喜欢

转载自blog.csdn.net/ywl5320/article/details/81161147