Android OpenGL ES 入门系列(四) --- 绘制形状

转载请注明出处

本文出自Hansion的博客


1.初始化形状

        绘制前,需要初始化并加载绘制的图形。如果图形的坐标不会在执行过程中发生变化,可以在onSurfaceCreated()中进行初始化和加载工作,这样会更省内存,提高执行效率。


public class MyGLRenderer implements GLSurfaceView.Renderer {

    ...

    private Triangle mTriangle;

    private Square   mSquare;

    public void onSurfaceCreated(GL10 unused, EGLConfig config) {

        ...

        // 初始化三角形

        mTriangle = new Triangle();

        // 初始化矩形

        mSquare = new Square();

    }

    ...

}


2.绘制形状

        使用 OpenGL ES 2.0 绘制图像需要你提供一些渲染细节,包括:
                顶点着色器(Vertex Shader ):用来渲染形状顶点的 OpenGL ES 代码
                片元着色器(Fragment Shader):使用颜色或纹理渲染形状表象的 OpenGL ES 代码
                程序 (Program):一个包含绘制一个或多个形状的着色器(shader)的OpenGL ES对象
        至少需要一个顶点着色器绘制一个形状,以及一个片元着色器为该形状上色。这些shader必须要被编译然后再添加到一个OpenGL ES program中,并利用这个 progrem 来绘制形状。


着色器写法举例:

public class Triangle {

    //顶点着色器

    private final String vertexShaderCode =

        "attribute vec4 vPosition;" +

        "void main() {" +

        "  gl_Position = vPosition;" +

        "}";

    //片元着色器

    private final String fragmentShaderCode =

        "precision mediump float;" +

        "uniform vec4 vColor;" +

        "void main() {" +

        "  gl_FragColor = vColor;" +

        "}";

    ...

}

着色器包含了OpenGL Shading Language(GLSL)代码,想在 OpenGL 环境中使用 它,必须先编译:

    /**
     * 加载并编译着色器代码
     * @param type 渲染器类型 {GLES20.GL_VERTEX_SHADER, GLES20.GL_FRAGMENT_SHADER}
     * @param shaderCode  GLSL渲染器代码
     * @return
     */
    public static int loadShader(int type, String shaderCode){
        int shader = GLES20.glCreateShader(type);
        GLES20.glShaderSource(shader, shaderCode);
        GLES20.glCompileShader(shader);
        return shader;
    }

接下来我们就编译色器代码并将它们添加至一个 OpenGL ES Program 对象中,然后执行链接方法。
但这一系列操作非常消耗CPU,所以最好写在形状的构造方法中,避免多次调用。如果执行时不知道着色器的内容,可以创建一次后进行缓存供以后使用。


public class Triangle() {

    ...


    private final int mProgram;

    public Triangle() {

        ...

        int vertexShader = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER,vertexShaderCode);
        int fragmentShader = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,fragmentShaderCode);
        // 编译着色器代码
        int vertexShader = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER,vertexShaderCode);
        int fragmentShader = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,fragmentShaderCode);
        // 创建一个OpenGL ES Program
        mProgram = GLES20.glCreateProgram();
        // 添加顶点着色器到Program
        GLES20.glAttachShader(mProgram, vertexShader);
        // 添加片元着色器到Program
        GLES20.glAttachShader(mProgram, fragmentShader);
        // 链接创建OpenGL ES可执行文件
        GLES20.glLinkProgram(mProgram);
    }
}
至此,我们已经准备好了被绘制的形状信息,要让OpenGL ES绘制,我们就要告诉它要绘制什么以及如何绘制。因为每个形状的绘图设置可能有所不同,所以最好将绘图逻辑写在形状自己的类里面。


我们创建一个draw()方法进行指定并绘制:



private int mPositionHandle;
private int mColorHandle;
private final int vertexCount = triangleCoords.length / COORDS_PER_VERTEX;
private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex

public void draw() {
    // 将Program添加至OpenGL ES环境
    GLES20.glUseProgram(mProgram);
    // 获取顶点着色器的vPosition成员
    mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
    // 启用顶点属性数组。如果启用,那么当glDrawArrays或者glDrawElements被调用时,顶点属性数组会被使用。
    GLES20.glEnableVertexAttribArray(mPositionHandle);
    // 准备形状坐标数据
    GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
            GLES20.GL_FLOAT, false,
            vertexStride, vertexBuffer);
    // 获取片元着色器的vColor成员
    mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
    // 设置绘制颜色
    GLES20.glUniform4fv(mColorHandle, 1, color, 0);
    // 绘制形状
    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
    // 禁用顶点属性数组
    GLES20.glDisableVertexAttribArray(mPositionHandle);
}


然后我们在渲染器的onDrawFrame方法中,调用draw()方法即可进行绘制


public void onDrawFrame(GL10 unused) {

    ...

    mTriangle.draw();
}


运行效果如下:





这个三角形目前不能根据GLSurfaceView显示的屏幕区域的比例进行校正,所以显示的时候总是在横向或竖向上被压扁。我们可以在下一章中使用投影和相机视图来解决这个问题。



参考:

OpenGL ES 2.0官方实例教程







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值