Android openGL ES 2.0入门--画三角形、正方形

因为最近的项目需要用到openGL ES 2.0,折腾了半天,查了网上一大堆资料,都没找到系统的openGL ES 2.0的学习资料。经过这半天,总算自己写了一个可以画出三角形和正方形的代码,顺便对网上一堆的代码封装了下。嗯,开始说吧。

首先感谢这篇教程:

http://hukai.me/android-training-course-in-chinese/graphics/opengl/environment.html

以及它的android官方原文:https://developer.android.com/training/graphics/opengl/shapes.html


不想往下看的同学,源码在这里:

http://download.csdn.net/detail/code_better/9592177


其他的我就不多说了,想说的都在注释里:

项目结构图:


先在manifest.xml里加上:


MainActivity:

/**
 * GLSurfaceView相当于画布
 * 主要绘画工作都在Renderer里
 */
public class MainActivity extends AppCompatActivity {

    private GLSurfaceView glSurfaceView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //创建一个GLSurfaceView实例
        glSurfaceView = new MyGLSurfaceView(this);
        //将glSurfaceView设置为activity的ContentView.
        setContentView(glSurfaceView);
    }
    @Override
    protected void onPause() {
        super.onPause();
        if (glSurfaceView != null) {
            glSurfaceView.onPause();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (glSurfaceView != null) {
            glSurfaceView.onResume();
        }
    }
}



MyGLSurfaceView:

class MyGLSurfaceView extends GLSurfaceView {

    public MyGLSurfaceView(Context context) {
        super(context);
        // 创建一个OpenGL ES 2.0 context,非常重要
        setEGLContextClientVersion(2);
        //设置Renderer到GLSurfaceView
        setRenderer(new MyGL20Renderer());
        // 只有在绘制数据改变时才绘制view
        //此设置会阻止绘制GLSurfaceView的帧,直到你调用了requestRender(),这样会非常高效
//        setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
    }
}

MyGL20Renderer:

public class MyGL20Renderer implements GLSurfaceView.Renderer {

    //声明一个三角形对象
    Triangle triangle = null;
    //声明一个正方形对象
    Square square = null;

    public void onSurfaceCreated(GL10 unused, EGLConfig config) {
        //设置背景的颜色
        GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
        triangle = new Triangle();
        square = new Square();
    }

    public void onDrawFrame(GL10 unused) {
        // 重绘背景色
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);

        //绘制三角形
//        triangle.draw();
        //绘制矩形
        square.draw();
    }

    public void onSurfaceChanged(GL10 unused, int width, int height) {
        GLES20.glViewport(0, 0, width, height);
    }
}



Util:

/**
 * Created by 炜贤 on 2016/8/1.
 * 

* 画一个图形:需要至少一个顶点着色器来绘制一个形状,以及一个片段着色器为该形状上色。 * 这些着色器必须被编译然后添加到一个OpenGL ES Program当中,并利用它来绘制形状。 */ public class Util { /** * float类型大小为4个字节 */ private static final int LENGTH = 4; 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;" + "}"; public int loadShader(int type, String shaderCode) { // 创建一个vertex shader类型(GLES20.GL_VERTEX_SHADER) // 或一个fragment shader类型(GLES20.GL_FRAGMENT_SHADER) int shader = GLES20.glCreateShader(type); // 将源码添加到shader并编译它 GLES20.glShaderSource(shader, shaderCode); GLES20.glCompileShader(shader); return shader; } /** * 顶点着色器(Vertex Shader):用来渲染形状顶点的OpenGL ES代码 * * @return 顶点着色器 */ public int getVertexShader() { return loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode); } /** * 片段着色器(Fragment Shader):使用颜色或纹理渲染形状表面的OpenGL ES代码。 * * @return 片段着色器 */ public int getFragmentShader() { return loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode); } /** * 程式(Program):一个OpenGL ES对象,包含了你希望用来绘制一个或更多图形所要用到的着色器 * 程式(program)是用来装配着色器的(个人理解) * * @return 程式 */ public int getProgram() { //获取顶点着色器 int vertexShader = getVertexShader(); //获取片段着色器 int fragmentShader = getFragmentShader(); int program = GLES20.glCreateProgram(); // 创建空的OpenGL ES Program GLES20.glAttachShader(program, vertexShader); // 将vertex shader添加到program GLES20.glAttachShader(program, fragmentShader); // 将fragment shader添加到program GLES20.glLinkProgram(program); // 创建可执行的 OpenGL ES program // 添加program到OpenGL ES环境中 GLES20.glUseProgram(program); return program; } /** * @param coords_per_vertex 每个顶点的坐标数 * @param vertexBuffer 浮点缓冲区 * @param color 颜色数组,数组的四个数分别为图形的RGB值和透明度 */ public void draw(int coords_per_vertex, FloatBuffer vertexBuffer, float color[]) { //获取程式 int program = getProgram(); //得到处理到顶点着色器的vPosition成员 int vPositionHandler = GLES20.glGetAttribLocation(program, "vPosition"); // 启用一个指向图形的顶点数组的handle GLES20.glEnableVertexAttribArray(vPositionHandler); // 准备坐标数据 GLES20.glVertexAttribPointer(vPositionHandler, coords_per_vertex, GLES20.GL_FLOAT, false, LENGTH * coords_per_vertex, vertexBuffer); // 得到处理到片段着色器的vPosition成员 int mColorHandle = GLES20.glGetUniformLocation(program, "vColor"); // 设置颜色 GLES20.glUniform4fv(mColorHandle, 1, color, 0); // 绘制三角形比较简单,这里采用glDrawArrays方法(默认是逆时针方向) GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3); // 禁用指向图形的顶点数组 GLES20.glDisableVertexAttribArray(vPositionHandler); } /** * * @param coords_per_vertex 每个顶点的坐标数 * @param vertexBuffer 浮点缓冲区 * @param color 颜色数组,数组的四个数分别为图形的RGB值和透明度 * @param drawOrder 绘制顶点的顺序(按逆时针方向) * @param drawListBuffer 绘图顺序顶点的缓冲区 */ public void draw(int coords_per_vertex, FloatBuffer vertexBuffer, float color[], short drawOrder[], ShortBuffer drawListBuffer) { //获取程式 int program = getProgram(); //得到处理到顶点着色器的vPosition成员 int vPositionHandler = GLES20.glGetAttribLocation(program, "vPosition"); // 启用一个指向图形的顶点数组的handle GLES20.glEnableVertexAttribArray(vPositionHandler); // 准备坐标数据 GLES20.glVertexAttribPointer(vPositionHandler, coords_per_vertex, GLES20.GL_FLOAT, false, LENGTH * coords_per_vertex, vertexBuffer); // 得到处理到片段着色器的vPosition成员 int mColorHandle = GLES20.glGetUniformLocation(program, "vColor"); // 设置颜色 GLES20.glUniform4fv(mColorHandle, 1, color, 0); // 绘制图形 GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length, GLES20.GL_UNSIGNED_SHORT, drawListBuffer); // 禁用指向图形的顶点数组 GLES20.glDisableVertexAttribArray(vPositionHandler); } }


Triangle:

/**
 * 三角形
 */
public class Triangle {

    private FloatBuffer vertexBuffer;

    // 设置每个顶点的坐标数
    static final int COORDS_PER_VERTEX = 3;
    // 设置三角形顶点数组
    static float triangleCoords[] = { // 默认按逆时针方向顺序绘制
            0.0f, 0.622008459f, 0.0f,   // 顶
            -0.5f, -0.311004243f, 0.0f,   // 左底
            0.5f, -0.311004243f, 0.0f    // 右底
    };

    // 设置图形的RGB值和透明度
    float color[] = {0.63671875f, 0.76953125f, 0.22265625f, 1.0f};

    /**
     * 初始化
     * 流程:创建一个顶点的缓冲区空间,然后将其作为一个浮点的缓冲区,
     * 然后将坐标加到这个缓冲区中,然后将读指针指向第一个位置
     */
    public Triangle() {
        // 初始化顶点字节缓冲区,用于存放形状的坐标,
        ByteBuffer bb = ByteBuffer.allocateDirect(
                // (每个浮点数占用4个字节)
                triangleCoords.length * 4);
        // 设置使用设备硬件的原生字节序
        bb.order(ByteOrder.nativeOrder());

        // 将ByteBuffer作为一个浮点缓冲区
        vertexBuffer = bb.asFloatBuffer();
        // 把坐标都添加到FloatBuffer中
        vertexBuffer.put(triangleCoords);
        // 设置buffer从第一个坐标开始读
        vertexBuffer.position(0);
    }

    /**
     * 绘图
     */
    public void draw(){
        new Util().draw(COORDS_PER_VERTEX,vertexBuffer,color);
    }
}



Square:

/**
 * 正方形
 */
public class Square {

    //顶点缓冲区
    private FloatBuffer vertexBuffer;
    //绘图顺序顶点缓冲区
    private ShortBuffer drawListBuffer;

    // 每个顶点的坐标数
    static final int COORDS_PER_VERTEX = 3;
    //正方形四个顶点的坐标
    static float squareCoords[] = {-0.5f, 0.5f, 0.0f,   // top left
            -0.5f, -0.5f, 0.0f,   // bottom left
            0.5f, -0.5f, 0.0f,   // bottom right
            0.5f, 0.5f, 0.0f}; // top right

    private short drawOrder[] = {0, 1, 2, 0, 2, 3}; // 顶点的绘制顺序
    // 设置图形的RGB值和透明度
    float color[] = {0.63671875f, 0.76953125f, 0.22265625f, 1.0f};

    public Square() {
        // initialize vertex byte buffer for shape coordinates
        ByteBuffer bb = ByteBuffer.allocateDirect(
                // (坐标数 * 4)
                squareCoords.length * 4);
        bb.order(ByteOrder.nativeOrder());
        vertexBuffer = bb.asFloatBuffer();
        vertexBuffer.put(squareCoords);
        vertexBuffer.position(0);

        // 为绘制列表初始化字节缓冲
        ByteBuffer dlb = ByteBuffer.allocateDirect(
                // (对应顺序的坐标数 * 2)short是2字节
                drawOrder.length * 2);
        dlb.order(ByteOrder.nativeOrder());
        drawListBuffer = dlb.asShortBuffer();
        drawListBuffer.put(drawOrder);
        drawListBuffer.position(0);
    }

    /**
     * 绘图
     */
    public void draw() {
        new Util().draw(COORDS_PER_VERTEX, vertexBuffer, color, drawOrder, drawListBuffer);
    }
}


这个画出来的三角形和正方形的效果并不是我们预想的的那样,那是因为投影的问题,请看我之后的博客吧,谢谢!



你可能感兴趣的:(android,openGL)