Android OpenGL ES绘图教程之三 : 绘制图形

来源:互联网 发布:mac系统 移动硬盘 编辑:程序博客网 时间:2024/04/30 01:11
       在定义了将要被OpenGL绘制的形状之后,你当然想要绘制它们。使用OpenGL ES 2.0绘制图形需要的代码可能比你想象的要多,因为API提供了大量的图形渲染管道控制接口。
    这一章将介绍如何使用OpenGL ES 2.0 API绘制上一章中定义的形状
    1. 初始化形状
        在你做任何的绘制操作之前,你都必须进行初始化和加载计划绘制的形状。除非在执行的过程中形状所在的结构(原坐标)发生变化,你应该在render中的onSurfaceCreated()方法中初始化它们以提高内存和执行效率。
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
    ...

    // initialize a triangle
    mTriangle = new Triangle();
    // initialize a square
    mSquare = new Square();
}


   2. 绘制形状
       使用OpenGL ES 2.0绘制定义的形状需要大量的代码,因为你必须给图形渲染管线提供许多细节,特别是,你需要定义下面的细节:
   Vertex Shader - OpenGL ES graphics code for rendering the vertices of a shape.
   译:顶点着色器 - 渲染形状顶点的OpenGL ES图形代码
   Fragment Shader - OpenGL ES code for rendering the face of a shape with colors or textures.
   译:片元着色器 - 使用颜色或者纹理渲染形状表面的OpenGL ES图形代码
   Program - An OpenGL ES object that contains the shaders you want to use for drawing one or more shapes.
   译:Program - 包含了用来绘制形状的着色器的OpenGL ES对象
       你至少需要一个顶点着色器来绘制形状,一个片元着色器来对形状着色。这些着色器必须被编译和被添加到OpenGL ES程序中。下面是一个如何通过定义着色器来绘制图形的例子:
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着色语言(GLSL)代码,在OpenGL ES环境中使用之前必须被编译,为了编译这些代码,在你的renderer类中创建一个方法:
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 ES编程对象中,链接程序,在绘制对象的构造方法中执行这些操作,所以只会执行一次。
       注意:编译OpenGL着色器和链接程序从CPU处理周期和时间来看消耗是比较昂贵的,所以你应该避免执行超过一次。如果你在运行时还不知道着色器的内容,你应该只在着色器被创建的时候编译一次,然后缓存起来使用。
public class Triangle() {
    ...

    int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
    int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);

    mProgram = GLES20.glCreateProgram();             // create empty OpenGL ES Program
    GLES20.glAttachShader(mProgram, vertexShader);   // add the vertex shader to program
    GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
    GLES20.glLinkProgram(mProgram);                  // creates OpenGL ES program executables
}


    这个时候,你已经准备好执行实际的绘图命令了,使用OpenGL ES绘图需要指定一些参数来告诉渲染管线画什么和怎么画。因为绘图选项可以通过形状区分,所以让你的shape类包含绘制逻辑是个不错的方法。
    创建draw()方法来进行绘制,下面的代码设置了顶点着色器和片元着色器的position和color值,然后执行绘制方法。
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);
}


    当这些代码都有的时候,绘制对象的时候只需要在renderer的onDrawFrame()方法下调用draw方法。下面是程序的执行效果:



       这个代码示例还有一些问题。首先它不会让你的朋友印象深刻,其次当屏幕方向改变的时候形状会改变,有点被压扁。形状被扭曲的原因是对象的顶点没有跟着屏幕上GLSurfaceView展示的区域的比例进行修正,你可以使用下一节介绍的projection and camera view来修复这个问题。
       最后,这个三角形是固定的,有点枯燥。在后面的课程中,你可以学习使这个形状旋转,使OpenGL ES图形管线更加有趣。
1 0
原创粉丝点击