阅读 341

Android OpenGl Es 学习(一):创建一个OpenGl es程序

概述

这是一个新的系列,学习OpengGl Es,其实是《OpenGl Es 应用开发实践指南 Android卷》的学习笔记,感兴趣的可以直接看这本书,当然这个会记录自己的理解,以下只作为笔记,以防以后忘记

之后会对本书的前九章依次分析记录

Android OpenGl Es 学习(一):创建一个OpenGl es程序

Android OpenGl Es 学习(二):定义顶点和着色器

Android OpenGl Es 学习(三):编译着色器

Android OpenGl Es 学习(四):增填颜色

Android OpenGl Es 学习(五):调整宽高比

Android OpenGl Es 学习(六):进入三维

Android OpenGl Es 学习(七):使用纹理

Android OpenGl Es 学习(八):构建简单物体

Android OpenGl Es 学习(九):增添触摸反馈

最终是要实现一个曲棍球的简单游戏,类似这样的

创建一个新项目

首先用Android Studio 创建一个新的项目

初始化OpenGl

我们使用GLSurfaceView来初始化OpenGlGLSurfaceView会处理OpenGl初始化过程中比较基本的操作,比如配置显示设备(display)以及在后台线程中渲染,GLSurfaceView可以更快的处理Activity的生命周期,GLSurfaceView为此提供了很多辅助方法

在xml书写GLSurfaceView

 <android.opengl.GLSurfaceView
        android:id="@+id/glsurface"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
复制代码

在Activity初始化GLSurfaceView

        GLSurfaceView glSurfaceView = findViewById(R.id.glsurface);
复制代码

判断支持OpenGl版本

我们用的是2.0版本,所以判断手机是否支持2.0版本

 private boolean supportsEs2() {
        ActivityManager activityManager =
                (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        ConfigurationInfo configurationInfo = activityManager
                .getDeviceConfigurationInfo();
       
        final boolean supportsEs2 =
                configurationInfo.reqGlEsVersion >= 0x20000
                        || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1
                        && (Build.FINGERPRINT.startsWith("generic")
                        || Build.FINGERPRINT.startsWith("unknown")
                        || Build.MODEL.contains("google_sdk")
                        || Build.MODEL.contains("Emulator")
                        || Build.MODEL.contains("Android SDK built for x86")));

        return supportsEs2;
    }
复制代码

为OpenGl2.0配置渲染表面

  private void initData() {
        if (supportsEs2()) {
            AirHockKeyRender myGlRender = new AirHockKeyRender(this);
            //设置opengl版本
            glSurfaceView.setEGLContextClientVersion(2);
            glSurfaceView.setRenderer(myGlRender);
            //RenderMode 有两种,RENDERMODE_WHEN_DIRTY 和 RENDERMODE_CONTINUOUSLY,前者是懒惰渲染,需要手动调用
            // glSurfaceView.requestRender() 才会进行更新,而后者则是不停渲染。
            glSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
        } else {
            Log.d("mmm", "不支持2.0版本");
        }
    }
复制代码

如果支持2.0版本,就设置版本号,在设置渲染器

适配Activity的生命周期

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

    @Override
    protected void onPause() {
        super.onPause();
        glSurfaceView.onPause();
    }
复制代码

创建Renderer类

class AirHockKeyRender implements GLSurfaceView.Renderer {
    public AirHockKeyRender(Context context) {

    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        //当surface被创建时,GlsurfaceView会调用这个方法,这个发生在应用程序
        // 第一次运行的时候或者从其他Activity回来的时候也会调用

        GLES20.glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        //在Surface创建以后,每次surface尺寸大小发生变化,这个方法会被调用到,比如横竖屏切换

        GLES20.glViewport(0, 0, width, height);
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        //当绘制每一帧数据的时候,会调用这个放方法,这个方法一定要绘制一些东西,即使只是清空屏幕
        //因为这个方法返回后,渲染区的数据会被交换并显示在屏幕上,如果什么都没有话,会看到闪烁效果

        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
    }
}
复制代码

GlSurafceView会在一个单独的线程调用渲染的方法,默认情况下会以设备屏幕刷新率不断的渲染,也可以按照请求选渲染,RenderMode 有两种,RENDERMODE_WHEN_DIRTYRENDERMODE_CONTINUOUSLY,前者是懒惰渲染,需要手动调用 glSurfaceView.requestRender() 才会进行更新,而后者则是不停渲染。

方法描述
GLES20.glClearColor设置清空屏幕用的颜色,前三个参数分别是 红 绿 蓝 最后一个参数成为阿尔发(alpha)代表透明度,上面我们把第一个设为1,其余为0,表示红色
GLES20.glViewport设置视口尺寸,告诉opengl迎来渲染的surface尺寸大小
GLES20.glClear清空屏幕,并用之前glClearColor定义的颜色填充

最后

现在我们第一个程序已经写出来的,运行后是这样的

完整代码

public class MainActivity extends AppCompatActivity {

    private GLSurfaceView glSurfaceView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();
        initData();
    }

    private void initData() {
        if (supportsEs2()) {
            AirHockKeyRender myGlRender = new AirHockKeyRender(this);
            //设置opengl版本
            glSurfaceView.setEGLContextClientVersion(2);
            glSurfaceView.setRenderer(myGlRender);
            //RenderMode 有两种,RENDERMODE_WHEN_DIRTY 和 RENDERMODE_CONTINUOUSLY,前者是懒惰渲染,需要手动调用
            // glSurfaceView.requestRender() 才会进行更新,而后者则是不停渲染。
            glSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
        } else {
            Log.d("mmm", "不支持2.0版本");
        }
    }

    private void initView() {
        glSurfaceView = findViewById(R.id.glsurface);
    }

    private boolean supportsEs2() {
        // Check if the system supports OpenGL ES 2.0.
        ActivityManager activityManager =
                (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        ConfigurationInfo configurationInfo = activityManager
                .getDeviceConfigurationInfo();
        // Even though the latest emulator supports OpenGL ES 2.0,
        // it has a bug where it doesn't set the reqGlEsVersion so
        // the above check doesn't work. The below will detect if the
        // app is running on an emulator, and assume that it supports
        // OpenGL ES 2.0.
        final boolean supportsEs2 =
                configurationInfo.reqGlEsVersion >= 0x20000
                        || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1
                        && (Build.FINGERPRINT.startsWith("generic")
                        || Build.FINGERPRINT.startsWith("unknown")
                        || Build.MODEL.contains("google_sdk")
                        || Build.MODEL.contains("Emulator")
                        || Build.MODEL.contains("Android SDK built for x86")));

        return supportsEs2;
    }

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

    @Override
    protected void onPause() {
        super.onPause();
        glSurfaceView.onPause();
    }
}
复制代码
class AirHockKeyRender implements GLSurfaceView.Renderer {

    public AirHockKeyRender(Context context) {
     
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        //当surface被创建时,GlsurfaceView会调用这个方法,这个发生在应用程序
        // 第一次运行的时候或者从其他Activity回来的时候也会调用

        GLES20.glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        //在Surface创建以后,每次surface尺寸大小发生变化,这个方法会被调用到,比如横竖屏切换

        GLES20.glViewport(0, 0, width, height);
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        //当绘制每一帧数据的时候,会调用这个放方法,这个方法一定要绘制一些东西,即使只是清空屏幕
        //因为这个方法返回后,渲染区的数据会被交换并显示在屏幕上,如果什么都没有话,会看到闪烁效果

        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
    }
}
复制代码