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

来源:互联网 发布:linux 系统文件夹 编辑:程序博客网 时间:2024/05/16 09:52

因为最近的项目需要用到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里加上:

<uses-feature    android:glEsVersion="0x00020000"    android:required="true" />


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. * <p/> * 画一个图形:需要至少一个顶点着色器来绘制一个形状,以及一个片段着色器为该形状上色。 * 这些着色器必须被编译然后添加到一个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);    }}


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



1 0
原创粉丝点击