Displaying Graphics with OpenGL ES(三)——Drawing Shapes

来源:互联网 发布:嵌入式linux启动 编辑:程序博客网 时间:2024/09/21 06:32

Drawing Shapes

在用OpenGl定义shapes后,就要画出他们了。画出形状需要大量的代码,因为API提供了强大的图形渲染通道。

1.初始化 Shapes

在你画之前,必须初始化和加载shape。除非执行程序期间改变shapes的构造( 原始坐标),你应该初始化他们在onSurfaceCreate()方法里为了渲染消耗内存和执行效率。

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();    }    ...}

2.Draw a Shape

通过绘制OpenGL ES 2.0的定义shape需要的代码量较大,因为你必须提供很多细节的图形渲染通道。具体而言,您必须定义如下:
~Vertex Shader:为渲染图形顶点的OpenGL ES图形代码。
~Fragment Shader:渲染shape正面的颜色和纹理的OpenGL ES 代码。
~Program:一个OpenGL ES对象,其中包含要用于绘制一个或多个shapes的着色器。

至少需要一个vertex shader 和 一个fragment shader。这些shaders必须被编译和添加到OpenGL ES program。下面是一个最基本的三角形shaders,你可以在Triangle.class里定义:

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 ES的环境中使用该编译OpenGL着色语言(GLSL)代码。编译这段代码,在你的渲染器类创建一个实用方法:

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;}

为了绘制shape,您必须编译shader代码,将其添加到OpenGL ES的程序对象,然后链接程序。这是绘制的对象的构造函数,所以只进行一次。

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);    }}

下面,你就可以添加绘制shape的实际调用。绘制形状与OpenGL ES需要您指定几个参数来告诉画什么渲染通道以及如何绘制它。由于绘图选项可以通过形状有所不同,所以在你的形状类包含自己的绘画逻辑是个好想法。
创建绘制形状的draw()方法。此代码设置形状的顶点着色器颜色值和fragment着色器的位置,然后执行绘图功能。

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 vertexpublic 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()方法从渲染的onDrawFrame()方法里:

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

然后运行程序,可以看到:
这里写图片描述
Figure 1. Triangle绘制没有用到Projection或Camera View。

此代码示例的一些问题。首先,它不会打动你的朋友。其次,三角形是有点压扁,并改变形状,当您更改设备的屏幕方向。形状歪斜的原因是由于对象的顶点未针对其中显示GLSurfaceView屏幕区域的比例校正。可以使用在下一章的投影和相机视图解决这个问题。

最后,三角形是固定的,这是一个有点无聊。在Add Motion 章节里,可以使这种形状旋转,做更多有趣的使用的OpenGL ES图形通道。

0 0