Android官方开发文档Training系列课程中文版:OpenGL绘图之图形绘制

原文地址:http://android.xsoftlab.net/training/graphics/opengl/draw.html

如果你还不清楚如何定义图形及坐标系统,请移步:Android官方开发文档Training系列课程中文版:OpenGL绘图之图形定义

在定义了图形之后,你接下来需要做的就是将它绘制到屏幕上。不过使用OpenGL ES 2.0 API来绘制这个图形所需要的代码量可能要比想象中的多一些,这是因为API为图形渲染管道提供了大量的控制细节。

这节课会展示如何绘制上节课所定义的图形。

初始化图形

在开始任何绘制之前,你必须先初始化并加载这个图形。除非是在执行的过程中图形的结构发生了改变。这个时候你应该在渲染器的onSurfaceCreated()方法中去初始化它们,这样可以使内存和进程的效率提升。

public class MyGLRenderer implements GLSurfaceView.Renderer {
    ...
    private Triangle mTriangle;
    private Square   mSquare;
    public void onSurfaceCreated(GL10 unused, EGLConfig config) {
        ...
        // initialize a triangle
        mTriangle = new Triangle();
        // initialize a square
        mSquare = new Square();
    }
    ...
}

绘制图形

绘制自定义图形需要大量的代码,因为你必须给图形渲染管道提供大量的渲染细节。尤其是下面这些必须定义:

  • Vertex Shader - 图形顶点的渲染.
  • Fragment Shader - 图形表面的颜色或纹理的渲染。
  • Program - 一个含有多个渲染器的OpenGL ES对象,可以用它来绘制一个或者多个图形。

你需要至少一个顶点渲染器来绘制图形,并需要一个表面渲染器来为图形着色。这些渲染器首先必须是可执行的,然后才能将其添加到OpenGL ES程序中,这时才能被用来绘制图形。下面定义了一个最基本的可以用来绘制图形的渲染器:

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渲染语言代码,这些代码必须先在OpenGL ES环境中编译通过。为了编译这些代码,需要在渲染器类中创建一个功能方法:

public static int loadShader(int type, String shaderCode){
    // create a vertex shader type (GLES20.GL_VERTEX_SHADER)
    // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
    int shader = GLES20.glCreateShader(type);
    // add the source code to the shader and compile it
    GLES20.glShaderSource(shader, shaderCode);
    GLES20.glCompileShader(shader);
    return shader;
}

为了可以绘制图形,必须先编译这些渲染器代码,然后再将其添加到OpenGL程序中,最后再链接到程序中。需要将这些工作放入绘制对象的构造方法中,所以这些工作只用做一次。

Note: OpenGL ES的编译与链接过程需要消耗较高的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);
        // create empty OpenGL ES Program
        mProgram = GLES20.glCreateProgram();
        // add the vertex shader to program
        GLES20.glAttachShader(mProgram, vertexShader);
        // add the fragment shader to program
        GLES20.glAttachShader(mProgram, fragmentShader);
        // creates OpenGL ES program executables
        GLES20.glLinkProgram(mProgram);
    }
}

这时就可以真正的开始绘制了。图形的绘制需要提供若干的参数来告诉渲染管道想要绘制什么及如何绘制。因为绘制选项可以定义多种多样的图形形式,所以可以自定义一个拥有独立绘制逻辑的类来绘制各种图形。

创建一个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() {
    // Add program to OpenGL ES environment
    GLES20.glUseProgram(mProgram);
    // get handle to vertex shader‘s vPosition member
    mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
    // Enable a handle to the triangle vertices
    GLES20.glEnableVertexAttribArray(mPositionHandle);
    // Prepare the triangle coordinate data
    GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
                                 GLES20.GL_FLOAT, false,
                                 vertexStride, vertexBuffer);
    // get handle to fragment shader‘s vColor member
    mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
    // Set color for drawing the triangle
    GLES20.glUniform4fv(mColorHandle, 1, color, 0);
    // Draw the triangle
    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
    // Disable vertex array
    GLES20.glDisableVertexAttribArray(mPositionHandle);
}

一旦完成以上所有的代码,最后只需要调用一下draw()方法就可以开始绘制了:

public void onDrawFrame(GL10 unused) {
    ...
    mTriangle.draw();
}

当程序启动之后,设备上就会出现以下图形:

上面的示例代码还有几个问题:首先,它不会给人留下什么深刻的印象。其次,当屏幕旋转的时候,这个三角形会有一点被压扁的感觉。这是因为在旋转的时候,代码中所定义的顶点的相对位置被压缩了。这些问题将会在下节课得到解决。

最后,这三角形是固定不变的,这会有些让人有些不爽的感觉。在Adding Motion的课程中将会使这个图形可以随着手势旋转而旋转,还可以通过渲染管道做到其它更多有意思的事情。

时间: 2024-12-15 01:51:46

Android官方开发文档Training系列课程中文版:OpenGL绘图之图形绘制的相关文章

Android官方开发文档Training系列课程中文版:目录

原文地址 : http://android.xsoftlab.net/training/index.html 引言 在翻译了一篇安卓的官方文档之后,我觉得应该做一件事情,就是把安卓的整篇训练课程全部翻译成英文,供国内的开发者使用,尤其是入门开发者,虽然现在网络上有很多入门课程,但是还是依靠官方文档学习来的靠谱,安卓官方文档是一系列的课程,使每个人可以系统的掌握安卓的知识,相比其它课程来说,它为开发者提供了查缺补漏的功能. 在这里你可以领略到安卓开发世界的精彩. Tips : 同时,本目录可以作为

Android官方开发文档Training系列课程中文版:通知用户之构建通知

原文地址:http://android.xsoftlab.net/training/notify-user/index.html 引言 通知用于在有事件发生时,将事情以更便捷的方式展示给用户.用户可以在他们方便的时候直接与通知交互. Notifications design guide课程讲述了如何设计有效的通知以及何时去使用它们.这节课将会学习如何实现通用的通知设计. 构建通知 这节课的实现主要基于NotificationCompat.Builder类,NotificationCompat.B

Android官方开发文档Training系列课程中文版:手势处理之多点触控处理

原文地址:http://android.xsoftlab.net/training/gestures/multi.html 多点触控是指多个手指同时触摸屏幕的情况.这节课主要学习如何检测多点触控手势. 记录多个触控点 当多根手指同时触碰到屏幕时,系统会产生以下触摸事件: ACTION_DOWN -第一个触碰到屏幕的点.它是手势的起始事件.这个触控点的指针数据在MotionEvent对象中的索引总是0. ACTION_POINTER_DOWN -除第一个触控点之外的其它点.这个触控点的指针数据的索

Android官方开发文档Training系列课程中文版:网络操作之网络连接

原文地址:http://android.xsoftlab.net/training/basics/network-ops/index.html 引言 这节课将会学习最基本的网络连接,监视网络连接状况及网络控制等内容.除此之外还会附带描述如何解析.使用XML数据. 这节课所包含的示例代码演示了最基本的网络操作过程.开发者可以将这部分的代码作为应用程序最基本的网络操作代码. 通过这节课的学习,将会学到最基本的网络下载及数据解析的相关知识. Note: 可以查看课程Transmitting Netwo

Android官方开发文档Training系列课程中文版:网络操作之XML解析

原文地址:http://android.xsoftlab.net/training/basics/network-ops/xml.html 扩展标记语言(XML)是一系列有序编码的文档.它是一种很受欢迎的互联网数据传输格式.像需要频繁更新内容的网站来说,比如新闻站点或者博客,需要经常更新它们的XML源,以使外部程序可以保持内容的同步变化.对于含有网络连接态的APP应用来说,上传及解析XML数据是一个通用的任务.这节课将会学习如何解析XML文档及如何使用XML中的数据. 选择解析器 我们推荐使用X

Android官方开发文档Training系列课程中文版:动画视图之转场框架介绍

原文地址:http://android.xsoftlab.net/training/transitions/index.html 引言 Activity所呈现的UI经常会由用户的输入或者其它事件而发生变化.比如,一个含有输入框的Activity,在用户输入要查找的关键字之后,这个输入框就会隐藏,并会在输入框的地方展示搜索后的结果. 为了可以在这样的情况下呈现出连贯的视觉效果,可以在不同View展示与隐藏过程中使用动画.这些动画可以为用户提供一种反馈,并会帮助他们学习应用是如何流转的. Andro

Android官方开发文档Training系列课程中文版:性能优化建议

原文地址:http://android.xsoftlab.net/training/articles/perf-tips.html 本篇文章主要介绍那些可以提升整体性能的微小优化点.它与那些能突然改观性能效果的优化手段并不属于同一类.选择正确的算法与数据结构必然是我们的第一总则,但是这不是我们这篇文章要介绍的.你应该将这篇文章所提及的知识点作为编码的日常习惯,这可以提升常规代码的执行效率. 下面是书写代码的基本准则: 绝不要做你不需要的工作. 如果可以不申请内存就不要申请,要合理复用已有的对象.

Android官方开发文档Training系列课程中文版:OpenGL绘图之环境配置

原文地址:http://android.xsoftlab.net/training/graphics/opengl/index.html 引言 Android framework层为创建绚丽的功能性UI提供了大量的标准工具.然而,如果想要以更多方式来控制屏幕的绘制,或者在三维图形中绘制,那么就需要使用其它工具了.Android framework所提供的OpenGL ES API为我们提供了一系列的工具,这些工具可以用来显示一些高端大气.天马行空的图形,只要你能想得到,那么它就可以做得到.此外,

Android官方开发文档Training系列课程中文版:打印内容之自定义文档打印

原文地址:http://android.xsoftlab.net/training/printing/custom-docs.html 对于一些应用,比如绘图类APP,版面设计类APP以及其它APP,这些APP都关注图形的输出,有一个漂亮的打印页面是它们的关键特性.在这种情况下,就不单单是打印一张图片或者是HTML文档这么简单了.这些程序对于这种类型的打印需要对页面中每样事物的控制都特别的精细,包括字体.文本流.页面间距.页眉.页脚以及图形元素. 创建打印输出对于程序来说是完全自定义的,这需要更