Android OpenGL ES 开发教程(三)

本章将从绘图这方面总结OpenGL ES的绘图实际操作过程,以及绘图的相关原理。

一、 基本绘图过程:
1. GLSurfaceView 用来展示OpenGL ES所绘制的图形,其中封装了Surface。
创建对象: new GLSurfaceView(this); 此处this指的是Activity
2. 使用GLSurfaceView的setRenderer(Renderer renderer);方法关联渲染对象。即要写一个具体类实现Interface GLSurfaceView.Renderer。
实现Renderer接口:

public class MyRender implements GLSurfaceView.Renderer {
    // IOPenGLDrawer 是自定义的一个具体绘图接口。
    private IOpenGLDrawer drawObject;

    public MyRender(IOpenGLDrawer drawObject) {
        this.drawObject = drawObject;
    }

    @Override
    public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
        // 设置背景颜色为黑色
        gl10.glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
        // 设置阴影为平滑模式(非必须的设置)
        gl10.glShadeModel(GL10.GL_SMOOTH);
        // 设置深度缓存
        gl10.glClearDepthf(1.0f);
        // 启用深度测试
        gl10.glEnable(GL10.GL_DEPTH_TEST);
        // 所做深度测试的类型
        gl10.glDepthFunc(GL10.GL_LEQUAL);
        // 对透视进行修正
        gl10.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);

    }

    @Override
    public void onSurfaceChanged(GL10 gl10, int width, int height) {
        gl10.glViewport(0, 0, width, height);
        gl10.glMatrixMode(GL10.GL_PROJECTION);
        gl10.glLoadIdentity();

        GLU.gluPerspective(gl10, 90f, (float)width/(float)height, 0.1f, 100f);
        gl10.glMatrixMode(GL10.GL_MODELVIEW);
        gl10.glLoadIdentity();
    }

    @Override
    public void onDrawFrame(GL10 gl10) {
        // 清除屏幕颜色和深度缓存
        gl10.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
        // 绘制
        drawObject.DrawScene(gl10);
    }

}

顺便看一下IOPenGLDrawer接口吧:

public interface IOpenGLDrawer {
    void DrawScene(GL10 gl);
}

然后你要绘制的对象,封装一个类(下面我封装了DrawPoint.java、DrawLine.java、Draw20D.java、DrawSolarSystem.java等类,主要是为了了解一下绘制过程,看两个有代表性的,一个绘制点、一个绘制20面体)

——-一大波代码快来袭————————–

DrawPoint.java

public class DrawPoint implements IOpenGLDrawer {
    private final FloatBuffer vertexBuffer;
    private float vertexArray[] = {
      -1f, -0.4f * 1.732f, 0.0f,
       0.8f, -0.4f * 1.732f, 0.0f,
       0.0f, 0.4f * 1.732f, 0.0f,
       0.0f, 0.0f, 0.0f
    };

    public DrawPoint() {
        ByteBuffer vbb = ByteBuffer.allocateDirect(vertexArray.length * 4);
        vbb.order(ByteOrder.nativeOrder());
        vertexBuffer = vbb.asFloatBuffer();
        vertexBuffer.put(vertexArray);
        vertexBuffer.position(0);
    }

    @Override
    public void DrawScene(GL10 gl) {
        // 相当于设置画笔颜色
        gl.glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
        // 设置点的大小
        gl.glPointSize(8f);
        // 重置为单位矩阵
        gl.glLoadIdentity();

        // 向Z轴负方向平移4个单位?随便定的
        gl.glTranslatef(0, 0, -4);
        // 开启顶点设置
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        // 设置顶点数组,顶点坐标为3维坐标, 坐标数据类型为GL10.GL_FLOAT, 数据从数组的第一位开始下标为0, 顶点数组为vertexBuffer
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
        // 有了数据后开始绘制点
        /**
         * 可以有两种绘制方法:
         * 1.使用 {@link GL10#glDrawArrays(int mode, int first, int count)}
         * 这个方法。此方法的特点是绘制的顺序是由给定的数组的数据顺序确定的,顺序不能被改变
         *    1) @params mode 是指的绘制的图形类型:(有点、线、三角形三种图形):
         *       (在这里假定顶点有P0, P1, P2, P3, P4, P5, P6, P7)
         *       {@link GL10#GL_POINTS}           指定主表的散点即 P0~P7 8个单独的点
         *       {@link GL10#GL_LINES}            单独的线段 P0P1/P2P3/P4P5/P6P7   *P8不会被绘制
         *       {@link GL10#GL_LINE_STRIP}      连续的线段         P0P1/P1P2/P2P3/P3P4/P4P5/P5P6/P6P7/P7P8
         *       {@link GL10#GL_LINE_LOOP}       首尾相连封闭的线段  P0P1/P1P2/P2P3/P3P4/P4P5/P5P6/P6P7/P7P8/P8P0
         *       {@link GL10#GL_TRIANGLES}        多个不想关联的三角形  P0P1P2/P3P4P5     不足三个点的将不会被绘制
         *       {@link GL10#GL_TRIANGLE_STRIP}  相关联的三角形       P0P1P2/P1P2P3/P2P3P4/P3P4P5/P4P5P6/P5P6P7
         *       {@link GL10#GL_TRIANGLE_FAN}    共顶点的三角形       P0P1P2/P0P2P3/P0P3P4/P0P4P5/P0P5P6/P0P6P7
         *
         *   2) @params first 是指的从第几个顶点开始绘制,一般为0
         *   3) @params count 是总计要绘制的顶点的数量,设置为vertexArray.length
         * 2.使用 {@link GL10#glDrawElements(int mode, int count, int type, java.nio.Buffer indices)}
         *   1) @params mode     同 {@link GL10#glDrawArrays(int mode, int first, int count)}中的 @params mode
         *   2) @params count    绘制图元的数量乘以一个图元的顶点数?
         *   3) @params type     只能使用 {@link GL10#GL_UNSIGNED_BYTE} {@link GL10#GL_UNSIGNED_SHORT}
         *   4) @params indices  指向索引存储位置的指针
         */


        gl.glDrawArrays(GL10.GL_POINTS, 0, vertexArray.length/3);
        // 关闭顶点设置
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
    }
}

Draw20D.java:

public class Draw20D implements IOpenGLDrawer {
    private static final float X = 0.525731112119133606f;
    private static final float Z = 0.850650808352039932f;
    // 1.顶点数组
    private static final float vertices[] = {
            -X, 0.0f,  Z,
            X, 0.0f,  Z,
            -X, 0.0f, -Z,
            X, 0.0f, -Z,
            0.0f,  Z,  X,
            0.0f,  Z, -X,
            0.0f, -Z,  X,
            0.0f, -Z, -X,
            Z,  X, 0.0f,
            -Z,  X, 0.0f,
            Z, -X, 0.0f,
            -Z, -X, 0.0f
    };
    // 2.这个数组是干什么的?
    private static final short indices[] = {
            0,4,1,  0,9,4,  9,5,4,  4,5,8,  4,8,1,
            8,10,1, 8,3,10, 5,3,8,  5,2,3,  2,7,3,
            7,10,3, 7,6,10, 7,11,6, 11,0,6, 0,1,6,
            6,1,10, 9,0,11, 9,11,2, 9,2,5,  7,2,11
    };
    // 3.颜色数组
    private static final float colors[] = {
            0f,0f,1f,1f,
            0f,1f,0f,1f,
            1f,0f,0f,1f,
            0f,1f,1f,1f,
            1f,0f,1f,1f,
            1f,1f,0f,1f,
            0.1f, 0.2f, 0.3f, 1f,
            0.1f, 0.3f, 0.2f, 1f,
            0.2f, 0.1f, 0.3f, 1f,
            0.2f, 0.3f, 0.1f, 1f,
            0.3f, 0.2f, 0.1f, 1f,
            0.3f, 0.1f, 0.2f, 1f
    };

    private FloatBuffer vertexBuffer, colorBuffer;
    private ShortBuffer indicesBuffer;
    private float angle = 0f;

    public Draw20D() {
        ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
        vbb.order(ByteOrder.nativeOrder());
        vertexBuffer = vbb.asFloatBuffer();
        vertexBuffer.put(vertices);
        vertexBuffer.position(0);

        ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2);
        ibb.order(ByteOrder.nativeOrder());
        indicesBuffer = ibb.asShortBuffer();
        indicesBuffer.put(indices);
        indicesBuffer.position(0);

        ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length * 4);
        cbb.order(ByteOrder.nativeOrder());
        colorBuffer = cbb.asFloatBuffer();
        colorBuffer.put(colors);
        colorBuffer.position(0);
    }

    // 此处要注意代码的顺序,不能在绘制前关闭顶点设置!!!
    @Override
    public void DrawScene(GL10 gl) {
        // 1.设置画笔的颜色为红色
        gl.glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
        gl.glLoadIdentity();
        gl.glTranslatef(0, 0, -4);
        // 2.让20面体进行旋转
        gl.glRotatef(angle, 0, 1, 0);

        // 3.1 只绘制前面
        gl.glFrontFace(GL10.GL_CCW);
        // 3.2 开启忽略面
        gl.glEnable(GL10.GL_CULL_FACE);
        // 3.3 设置忽略背面
        gl.glCullFace(GL10.GL_BACK);
        // 3.4 关闭忽略面
        gl.glDisable(GL10.GL_CULL_FACE);

        // 4.1 开启顶点设置
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        // 4.2 将顶点数据传入
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);

        // 5.1 开启颜色设置
        gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
        // 5.2 将颜色数据传入
        gl.glColorPointer(4, GL10.GL_FLOAT, 0, colorBuffer);
        /**
         * 此处使用的是 {@link GL10#glDrawElements(int mode, int count, int type, java.nio.Buffer indices)}
         *   1) @params mode     同 {@link GL10#glDrawArrays(int mode, int first, int count)}中的 @params mode
         *   2) @params count    绘制图元的数量乘以一个图元的顶点数?
         *   3) @params type     只能使用 {@link GL10#GL_UNSIGNED_BYTE} {@link GL10#GL_UNSIGNED_SHORT}
         *   4) @params indices  指向索引存储位置的指针--->这是一个short数组,并且次数组包含的因子是顶点的下标index
         *                       此处的顶点数组的长度是12,因此index是0~11,这个索引数组包含的信息是要绘制的三角形的三个顶点的坐标
         *                       在顶点数组中的index,因此成为索引指针。索引指针绘制三角形时以三个数据为一组。
         */
        gl.glDrawElements(GL10.GL_TRIANGLES, indices.length,
                GL10.GL_UNSIGNED_SHORT, indicesBuffer);


        // 5.3 关闭颜色设置
        gl.glDisableClientState(GL10.GL_COLOR_ARRAY);

        // 4.3 关闭顶点设置
        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);

        angle++;
    }

}

源代码下载

——————不怎么华丽的分割线—————————————–

关于其中一些重要方法的解释请看第四章:Android OpenGL ES开发教程(四)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值