Android中使用opengl es2.0基础(2)- 三角形的绘制

Opengl ES2.0 三角形的绘制

先从二维图形的绘制进行Opengl es的学习,本节为3角形的绘制。

1、在绘图前首先要知道Opengl es在android手机系统中的坐标系:

以手机屏幕的中心为原点,x,y的方向如上图所示;z的方向为垂直屏幕的空间,以屏幕向外为正方向。

默认为按逆时针方向绘制。

默认x在屏幕的范围(-1,1),y在屏幕的范围(-1,1)。


2、我们要绘制图形,必须知道图形的顶点坐标

//设置三角形顶点数组,顶点逆时针排版
    private float coords[] = {   
            0.0f,  0.5f, 0.0f,
            -0.5f, 0.0f, 0.0f,
            0.5f, 0.0f, 0.0f
    };

然后把顶点坐标数组缓存到Buffer中:

// 初始化顶点字节缓冲区,用于存放形状的坐标,每个浮点数占用4个字节
        ByteBuffer bb = ByteBuffer.allocateDirect(coords.length * 4);
        //设置使用设备硬件的原生字节序
        bb.order(ByteOrder.nativeOrder());

        //从ByteBuffer中创建一个浮点缓冲区
        FloatBuffer floatBuffer = bb.asFloatBuffer();
        // 把坐标都添加到FloatBuffer中
        floatBuffer.put(coords);
        //设置buffer从第一个坐标开始读
        floatBuffer.position(0);

3、创建并编译顶点、片断shader

vertex shader类型:GLES20.GL_VERTEX_SHADER

fragment shader类型:GLES20.GL_FRAGMENT_SHADER

shader的创建流程如下图:

           

实现如下:

private static final String vertexShaderCode =
            "attribute vec4 vPosition;" +
                    "void main() {" +
                    "  gl_Position = vPosition;" +
                    "}";

    private static final String fragmentShaderCode =
            "precision mediump float;" +
                    "uniform vec4 vColor;" +
                    "void main() {" +
                    "  gl_FragColor = vColor;" +
                    "}";
上面的shaderCode如果要弄懂,需要去学习GLSL的相关知识,这里不做过多说明。


// 编译shader代码
        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER,vertexShaderCode);
        int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,fragmentShaderCode);

public static int loadShader(int type, String shaderCode){
        //vertex shader类型(GLES20.GL_VERTEX_SHADER)或fragment shader类型(GLES20.GL_FRAGMENT_SHADER)
        int shader = GLES20.glCreateShader(type);

        // 将源码添加到shader并编译它
        GLES20.glShaderSource(shader, shaderCode);
        GLES20.glCompileShader(shader);

        return shader;
    }

4、创建程序Program

Program的创建流程如下图:


初始化处理如下:

// 创建空的OpenGL ES Program
        program = GLES20.glCreateProgram();

        // 将vertex shader添加到program
        GLES20.glAttachShader(program, vertexShader);

        // 将fragment shader添加到program
        GLES20.glAttachShader(program, fragmentShader);

        // 创建可执行的 OpenGL ES program
        GLES20.glLinkProgram(program);

绘图时添加以下代码:

// 添加program到OpenGL ES环境中
        GLES20.glUseProgram(program);

5、绘制前还要准备相关的顶点、片断数据:

获取shader的内存位置,把数据写入内存中

       // 获取指向vertex shader的成员vPosition的内存地址
        positionHandle = GLES20.glGetAttribLocation(program, "vPosition");

        // 启用一个指向三角形的顶点数组
        GLES20.glEnableVertexAttribArray(positionHandle);

        //准备三角形的坐标数据
        GLES20.glVertexAttribPointer(positionHandle, 3,
                GLES20.GL_FLOAT, false,
                3 * 4, vertexBuffer);

        // 获取指向fragment shader的成员vColor的内存地址
        colorHandle = GLES20.glGetUniformLocation(program, "vColor");

        // 上传缓冲,把color写入vColor的内存中
        GLES20.glUniform4fv(colorHandle, 1, color, 0);

6、绘制3角形

在GLES20.glDrawArrays(....)的第一个参数为绘制的图元,可以是点、线、面。可以自行配置。我们绘制三角形采用GLES20.GL_TRIANGLES

// glDrawArrays 使用VetexBuffer 来绘制,顶点的顺序由vertexBuffer中的顺序指定。
        // GLES20.GL_TRIANGLES 绘制的类型为3角形,从0开始
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, coords.length / 3);

完整的代码如下:

创建一个Triangle类,实现GLSerfaceView.Renderer接口:

public class Triangle implements GLSurfaceView.Renderer
{
    private static final String vertexShaderCode =
            "attribute vec4 vPosition;" +
                    "void main() {" +
                    "  gl_Position = vPosition;" +
                    "}";

    private static final String fragmentShaderCode =
            "precision mediump float;" +
                    "uniform vec4 vColor;" +
                    "void main() {" +
                    "  gl_FragColor = vColor;" +
                    "}";

    //定点的缓存
    private FloatBuffer vertexBuffer;
    //OpenGL ES Program
    private int program;
    //设置三角形顶点数组
    private float coords[] = {   // 默认按逆时针方向绘制
            0.0f,  0.5f, 0.0f,
            -0.5f, 0.0f, 0.0f,
            0.5f, 0.0f, 0.0f
    };

    // 设置三角形颜色和透明度(r,g,b,a),蓝色不透明
    private float color[] = {0.0f, 0.0f, 1.0f, 1.0f};

    private int positionHandle;
    private int colorHandle;

    /**
     * 仅调用一次,用于设置view的OpenGLES环境
     */
    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config)
    {
        //设置清屏背景色RGBA,白色不透明
        GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);

        // 初始化顶点字节缓冲区
        vertexBuffer = BufferUtil.getFloatBuffer(coords);

        // 编译shader代码
        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER,vertexShaderCode);
        int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,fragmentShaderCode);

        // 创建空的OpenGL ES Program
        program = GLES20.glCreateProgram();

        // 将vertex shader添加到program
        GLES20.glAttachShader(program, vertexShader);

        // 将fragment shader添加到program
        GLES20.glAttachShader(program, fragmentShader);

        // 创建可执行的 OpenGL ES program
        GLES20.glLinkProgram(program);
    }

    /**
     * 如果view的几何形状发生变化就调用,例如当竖屏变为横屏时
     */
    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height)
    {
        //设置视窗大小及位置
        GLES20.glViewport(0, 0, width, height);
    }

    /**
     * 每次View被重绘时被调用
     */
    @Override
    public void onDrawFrame(GL10 gl)
    {
        //清除深度缓冲与颜色缓冲
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT|GLES20.GL_DEPTH_BUFFER_BIT);

        // 添加program到OpenGL ES环境中
        GLES20.glUseProgram(program);

        // 获取指向vertex shader的成员vPosition的handle
        positionHandle = GLES20.glGetAttribLocation(program, "vPosition");

        // 启用一个指向三角形的顶点数组的handle
        GLES20.glEnableVertexAttribArray(positionHandle);

        //准备三角形的坐标数据
        GLES20.glVertexAttribPointer(positionHandle, 3,
                GLES20.GL_FLOAT, false,
                3 * 4, vertexBuffer);

        // 获取指向fragment shader的成员vColor的handle
        colorHandle = GLES20.glGetUniformLocation(program, "vColor");

        // 上传缓冲
        GLES20.glUniform4fv(colorHandle, 1, color, 0);

        // glDrawArrays 使用VetexBuffer 来绘制,顶点的顺序由vertexBuffer中的顺序指定。
        // GLES20.GL_TRIANGLES 绘制的类型为3角形
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, coords.length / 3);

        //glDrawElements 可以重新定义顶点的顺序,顶点的顺序由indices Buffer 指定
        //GLES20.glDrawElements(GLES20.GL_TRIANGLES,indices.length,GLES20.GL_UNSIGNED_INT,indexBuffer);

        // 禁用指向三角形的顶点数组
        GLES20.glDisableVertexAttribArray(positionHandle);
    }

    public static int loadShader(int type, String shaderCode){
        //vertex shader类型(GLES20.GL_VERTEX_SHADER)或fragment shader类型(GLES20.GL_FRAGMENT_SHADER)
        int shader = GLES20.glCreateShader(type);

        // 将源码添加到shader并编译它
        GLES20.glShaderSource(shader, shaderCode);
        GLES20.glCompileShader(shader);

        return shader;
    }
}

public class BufferUtil
{

    public static FloatBuffer getFloatBuffer(float[] coords)
    {
        // 初始化顶点字节缓冲区,用于存放形状的坐标,每个浮点数占用4个字节
        ByteBuffer bb = ByteBuffer.allocateDirect(coords.length * 4);
        //设置使用设备硬件的原生字节序
        bb.order(ByteOrder.nativeOrder());

        //从ByteBuffer中创建一个浮点缓冲区
        FloatBuffer floatBuffer = bb.asFloatBuffer();
        // 把坐标都添加到FloatBuffer中
        floatBuffer.put(coords);
        //设置buffer从第一个坐标开始读
        floatBuffer.position(0);
        return floatBuffer;
    }
}

Activity和GLSurfaceView的处理在上一节中有介绍,如果不懂请看上一章节。


工程已上传Github,欢迎下载https://github.com/chyss/OpenglTriangle


运行结果如下:

                              



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值