码迷,mamicode.com
首页 > 移动开发 > 详细

Android OpenGL ES零基础系列(一):理解GLSurfaceView,GLSurfaceView.Render的基本用法

时间:2016-07-13 16:33:34      阅读:5463      评论:0      收藏:0      [点我收藏+]

标签:

转载请注明出处

前言

OpenGL ES是OpenGL的一个子集,是针对手机、PDA和游戏主机等嵌入式设备而设计的。该API由Khronos集团定义推广,Khronos是一个图形软硬件行业协会,该协会主要关注图形和多媒体方面的开放标准。
因此OpenGL ES作为第三方库被应用在android中。
到目前为止,OpenGL ES已经发展有了3个版本,OpenGL ES 1.0 , OpenGL ES 2.0 , OpenGL ES 3.0。其中OpenGL ES 1.0 是以OpenGL 1.3规范为基础,OpenGL ES 2.0 是以OpenGL 2.0 为基础,OpenGL ES 3.0是移动设备专用,以OpenGL 4.3为标准。

正文:利用OpenGL ES 2.0创建简单的三角图形

第一步:创建GLSurfaceView对象

生成GLSurfaceView的方法有2种,可以直接在xml中写,也可以在代码中new。
本文我们选用后一种,eg:

public class SunnyOpenGLActivity extends FragmentActivity {
    private GLSurfaceView mGLSurfaceView;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initView();
    }

    @Override
    protected void onResume() {
        super.onResume();
        mGLSurfaceView.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
        mGLSurfaceView.onPause();
    }

    private void initView() {
        mGLSurfaceView = new GLSurfaceView(this);
    }

第二步:自定义Render类实现GLSurfaceView.Render接口

这一步是最重要的一步,因为着色器的生成,矩阵的变换,纹理的加载等都是在这里实现的,GLSurfaceView.Render有三个重要的待实现的接口:
onSurfaceCreated(GL10 glUnused,EGLConfig config);
onSurfaceChanged(GL10 glUnused,int width,int height);
onDrawFrame(GL10 glUnused);
以上三个方法回调的时机分别如下:
onSurfaceCreated:当GLSurfaceView 实例生成时回调;
onSurfaceChanged:当手机横/竖屏切换时回调;
onDrawFrame:是由系统自动回调的,它会以一定的帧频率来调用重绘View。
当设置GLSurfaceView的渲染模式o为GLSurfaceView.RENDERMODE_CONTINUOUSLY或不设置时,系统就会主动渲染,就会回调onDrawFrame()方法
SunnyGLRender类如下:

public class SunnyGLRender implements GLSurfaceView.Renderer {
    private int mProgram;
    private int maPostionHandle;

    private FloatBuffer mTriangleVB;
    //定义顶点(vertex)着色命令语句
    private final String vertexShaderCode =
            "uniform mat4 uMVPMatrix; \n" +
            "attribute vec4 vPosition; \n" +
                    "void main(){              \n" +
                    " gl_Position = vPosition; \n" +
                    "}                         \n";


    private final String fragmentShaderCode =
            "precision mediump float;\n" +
                    "void main(){ \n" +
                    " gl_FragColor = vec4 (0.63671875,0.76953125,0.22265625,1.0);\n" +
                    "}\n";

    //应用投影与相机视图
    private int muMVPMatrixHandle;
    //用于存储变换矩阵结果的总变换矩阵[4*4]
    private float[] mMVPMatrix = new float[16];
    //[4*4]的视图变换矩阵
    private float[] mVMatrix = new float[16];
    //[4*4]的投影变换矩阵
    private float[] mProjMatrix = new float[16];
    //[4*4]的模型变换矩阵
    private float[] mMMatrix = new float[16];

    public float mAngle;

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {

        //GLES20:为OpenGL ES2.0版本,相应的
        //GLES30:OpenGL ES3.0
        //黑色背景
        GLES20.glClearColor(0.5f,0.5f,0.5f,1.0f);
        //glClear:清除缓冲区标志,这里为:清除颜色缓冲及深度缓冲,把整个窗口清除为黑色背景
        GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
        initShapes();
        int vertextShader = loadShader(GLES20.GL_VERTEX_SHADER,vertexShaderCode);
        int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,fragmentShaderCode);
        //申请特定的着色器,program != 0 申请成功
        mProgram = GLES20.glCreateProgram();
        if(mProgram != 0 ){
        GLES20.glAttachShader(mProgram,vertextShader);
        GLES20.glAttachShader(mProgram,fragmentShader);
        //连接着色器
        GLES20.glLinkProgram(mProgram);
           int[] linkStatus = new int[1];
            //查看着色器连接情况
            GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
            if (linkStatus[0] != GLES20.GL_TRUE) {
                //连接失败
                Log.e(TAG, "Could not link program: ");
                Log.e(TAG, GLES20.glGetProgramInfoLog(program));
                GLES20.glDeleteProgram(program);
                program = 0;
            }
           //获取着特定着色器vPosition参数。
        maPostionHandle = GLES20.glGetAttribLocation(mProgram,"vPosition");


       }
    }

    /**
     * 初始化三角形的一些参数
     */
    private void initShapes() {
    /**
     * X,Y,Z三轴坐标
     * U,V也即S,T,是图片,视频等以纹理的形式加载到GLSurfaceView中时的坐标
     * U,V是无方向的
     */
        float trianlgeCoords[] = {
            //X,Y,Z,U,V
            -1.0f, -0.5f, 0, -0.5f, 0.0f,
            1.0f, -0.5f, 0, 1.5f, -0.0f,
            0.0f,  1.11803399f, 0, 0.5f,  1.61803399f
        };

        ByteBuffer vbb = ByteBuffer.allocateDirect(trianlgeCoords.length * 4);
        vbb.order(ByteOrder.nativeOrder());
        mTriangleVB = vbb.asFloatBuffer();
        mTriangleVB.put(trianlgeCoords);
        mTriangleVB.position(0);
    }

    /**
     * 加载指定着色器
     * @param type
     * @param shaderCode
     * @return
     */
    private int loadShader(int type,String shaderCode){

        int shader = GLES20.glCreateShader(type);
        if(shader != 0 ){
        //加载着色器脚本程序(即本例的String 变量命令语句)
         GLES20.glShaderSource(shader,shaderCode);
         //编译着色器脚本程序
         GLES20.glCompileShader(shader);
         int[] compiled = new int[1];
            //查看编译结果
            GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
            if (compiled[0] == 0) {
                //编译失败,释放申请的着色器
                GLES20.glDeleteShader(shader);
                shader = 0;
            }
        } 
        return shader;
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        GLES20.glViewport(0, 0, width, height);

        float ratio = (float) width/height;
        //调用此方法来计算生成透视投影矩阵
        Matrix.frustumM(mProjMatrix,0,-ratio,ratio,-1,1,3,7);
        //当Sucrface改变时,获取指定着色器的uMVPMatrix参数
        muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram,"uMVPMatrix");
        //设定相机的视角
        //调用此方法产生摄像机9参数位置矩阵
        Matrix.setLookAtM(mVMatrix,0,
        0,0,-3, //相机的x,y,z坐标
        0,0,0,//目标对应的x,y,z坐标
        0,1.0f,1.0f//相机的视觉向量(upx,upy,upz,三个向量最终的合成向量的方向为相机的方向)
        );

    }

    @Override
    public void onDrawFrame(GL10 gl) {
        // Redraw background color

        //把左矩阵投影矩阵与右矩阵视图矩阵变换后的结果存储在总矩阵mMVPMatrix中
        Matrix.multiplyMM(mMVPMatrix,0,mProjMatrix,0,mVMatrix,0);
      //  GLES20.glUniformMatrix4fv(muMVPMatrixHandle,1,false,mMVPMatrix,0);

        //为三角形创建一个旋转动作
        /*long time = SystemClock.uptimeMillis() % 4000L;
        mAngle = 0.090f * ((int)time);*/
        //创建一个绕x,y,z轴旋转一定角度的矩阵
        Matrix.setRotateM(mMMatrix,0,mAngle,0,0,1.0f);
        Matrix.multiplyMM(mMVPMatrix,0,mVMatrix,0,mMMatrix,0);
        Matrix.multiplyMM(mMVPMatrix,0,mProjMatrix,0,mMVPMatrix,0);
        GLES20.glUniformMatrix4fv(muMVPMatrixHandle,1,false,mMVPMatrix,0);


        //把Program用到OpenGL环境中
        GLES20.glUseProgram(mProgram);
        //准备画三角形的数据
             //为指定着色器取出的参数赋值   GLES20.glVertexAttribPointer(maPostionHandle,3,GLES20.GL_FLOAT,false,12,mTriangleVB);
             //使用这个从指定着色器中取出的参数的值
        GLES20.glEnableVertexAttribArray(maPostionHandle);

        //开始画
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES,0,3);

    }
}

第三步:权限声明

经过以上二步,程序还不能运行,得在AndroidManifest.xml中声明相应权限。

<!-- Tell the system this app requires OpenGL ES 2.0. -->
    <uses-feature
        android:glEsVersion="0x00020000"
        android:required="true" />

运行程序 就可以看到三角形了。

下一节

参考资料

Android OpenGL ES2.0 开发文档
Android OpenGL ES 应用(二) 纹理
浅学OpenGLES2.0
google ApiDemo(这个自己看官方Demo就好了,就没有贴出下载地址了)

Android OpenGL ES零基础系列(一):理解GLSurfaceView,GLSurfaceView.Render的基本用法

标签:

原文地址:http://blog.csdn.net/u011153817/article/details/51891759

(2)
(1)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!