GLSurfaceView代码分析

来源:互联网 发布:mac 删除多个文件 编辑:程序博客网 时间:2024/05/17 04:35
SDK 中的 android.opengl.GLSurfaceView 类提供如下功能:

在 OpenGL ES 和 View 系统之间建立联系;
使得 OpenGL ES 可以工作在 Activity 生命周期中;
可选择合适的 frame buffer 像素格式;
创建并管理一个单独的渲染线程,可以实现平滑的动画;
提供 debugging 工具和 API。
一个简单的 GLSurfaceView 应用
  1. package com.example.android.apis.graphics;

  2. import javax.microedition.khronos.egl.EGLConfig;
  3. import javax.microedition.khronos.opengles.GL10;

  4. import android.app.Activity;
  5. import android.opengl.GLSurfaceView;
  6. import android.os.Bundle;

  7. public class ClearActivity extends Activity {
  8. @Override
  9. protected void onCreate(Bundle savedInstanceState) {
  10. super.onCreate(savedInstanceState);
  11. mGLView = new GLSurfaceView(this);
  12. mGLView.setRenderer(new ClearRenderer());
  13. setContentView(mGLView);
  14. }

  15. @Override
  16. protected void onPause() {
  17. super.onPause();
  18. mGLView.onPause();
  19. }

  20. @Override
  21. protected void onResume() {
  22. super.onResume();
  23. mGLView.onResume();
  24. }

  25. private GLSurfaceView mGLView;
  26. }

  27. class ClearRenderer implements GLSurfaceView.Renderer {
  28. public void onSurfaceCreated(GL10 gl, EGLConfig config) {
  29. // Do nothing special.
  30. }

  31. public void onSurfaceChanged(GL10 gl, int w, int h) {
  32. gl.glViewport(0, 0, w, h);
  33. }

  34. public void onDrawFrame(GL10 gl) {
  35. gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
  36. }
  37. }
复制代码
这个程序功能很简单,每帧绘制时将屏幕设置成黑色。但它是一个完整的工作在 Activity 生命周期中的 OpenGL 程序。当 activity 暂停时,它暂停渲染;当 activity 继续时,它继续渲染。可以将这个程序用作非交互式的 demo 程序。可以在 ClearRenderer.onDrawFrame() 接口中增加 OpenGL 调用做很多的绘制。
GLSurfaceView.Render 接口有三个方法:

onSurfaceCreated():该方法在渲染开始前调用,OpenGL ES 的绘制上下文被重建时也会被调用。当 activity 暂停时绘制上下文会丢失,当 activity 继续时,绘制上下文会被重建。另外,创建长期存在的 OpenGL 资源(如 texture)往往也在这里进行。
onSurfaceChanged():当 surface 的尺寸发生改变时该方法被调用。往往在这里设置 viewport。若你的 camera 是固定的,也可以在这里设置 camera。
onDrawFrame():每帧都通过该方法进行绘制。绘制时通常先调用 glClear 函数来清空 framebuffer,然后在调用 OpenGL ES 的起它的接口进行绘制。
输入如何处理若是开发一个交互型的应用(如游戏),通常需要子类化 GLSurfaceView,由此可以获取输入事件。下面有个例子:

  1. package com.google.android.ClearTest;

  2. import javax.microedition.khronos.egl.EGLConfig;
  3. import javax.microedition.khronos.opengles.GL10;

  4. import android.app.Activity;
  5. import android.content.Context;
  6. import android.opengl.GLSurfaceView;
  7. import android.os.Bundle;
  8. import android.view.MotionEvent;

  9. public class ClearActivity extends Activity {
  10.     @Override
  11.     protected void onCreate(Bundle savedInstanceState) {
  12.         super.onCreate(savedInstanceState);
  13.         mGLView = new ClearGLSurfaceView(this);
  14.         setContentView(mGLView);
  15.     }

  16.     @Override
  17.     protected void onPause() {
  18.         super.onPause();
  19.         mGLView.onPause();
  20.     }

  21.     @Override
  22.     protected void onResume() {
  23.         super.onResume();
  24.         mGLView.onResume();
  25.     }

  26.     private GLSurfaceView mGLView;
  27. }

  28. class ClearGLSurfaceView extends GLSurfaceView {
  29.     public ClearGLSurfaceView(Context context) {
  30.         super(context);
  31.         mRenderer = new ClearRenderer();
  32.         setRenderer(mRenderer);
  33.     }

  34.     public boolean onTouchEvent(final MotionEvent event) {
  35.         queueEvent(new Runnable(){
  36.             public void run() {
  37.                 mRenderer.setColor(event.getX() / getWidth(),
  38.                         event.getY() / getHeight(), 1.0f);
  39.             }});
  40.             return true;
  41.         }

  42.         ClearRenderer mRenderer;
  43. }

  44. class ClearRenderer implements GLSurfaceView.Renderer {
  45.     public void onSurfaceCreated(GL10 gl, EGLConfig config) {
  46.         // Do nothing special.
  47.     }

  48.     public void onSurfaceChanged(GL10 gl, int w, int h) {
  49.         gl.glViewport(0, 0, w, h);
  50.     }

  51.     public void onDrawFrame(GL10 gl) {
  52.         gl.glClearColor(mRed, mGreen, mBlue, 1.0f);
  53.         gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
  54.     }

  55.     public void setColor(float r, float g, float b) {
  56.         mRed = r;
  57.         mGreen = g;
  58.         mBlue = b;
  59.     }

  60.     private float mRed;
  61.     private float mGreen;
  62.     private float mBlue;
  63. }
复制代码
这个应用在每一帧中清空屏幕。当 tap 屏幕时,改变屏幕的颜色。这里在 ClearGLSurfaceView.onTouchEvent() 中使用了 queueEvent()。queueEvent() 方法用于在 UI 线程和渲染线程间通信。也可以用起它的 Java 线程通信技术,如 synchronized 方法,但 queueEvent 最简单的线程通信方法。
其他的 GLSurfaceView 例子在 Android SDK 的 API Demo例子程序中还有很多例子:

GLSurfaceView
Kube
Translucent GLSurfaceView:透明背景
Textured Triangle:纹理贴图
Sprite Text:在 texture 上写文本并显示在 3D 场景中
Touch Rotate:旋转 3D 对象
选择一个 SurfaceGLSurfaceView 提供了接口可选择 surface 的类型。默认情况下, GLSurfaceView 会使用一个 16 位 RGB frame buffer,带 16 位深度。你也可以根据自己的需要进行选择,比如在 Translucent GLSurfaceView 例子里,需要一个 Alpha 通道来实现透明。GLSurfaceView 提供了 setEGLSurfaceChooser()方法来选择 surface。
选择一个 RGB (565)的16位 framebuffer,接口如下:


setEGLConfigChooser(boolean needDepth)


若要定制 red, green, blue, alpha 和 depth,则用如下接口:

setEGLConfigChooser(int redSize, int greenSize,int blueSize, int alphaSize,int depthSize, int stencilSize)


使用自己实现的 EGLConfigChooser,用如下的接口:

setEGLConfigChooser(EGLConfigChooser configChooser)


持续型渲染模式 & 通知型渲染模式大多数 3D 应用,如游戏、模拟等都是持续型渲染的动画,还有些 3D 应用是反应式的(reactive),它们往往先被动等待,当用户有了动作再做出反应。对于这种应用,持续渲染屏幕是浪费时间。若开发反应式的应用,可以调用下面的方法

GLSurfaceView.setRenderMode(RENDERMODE_WHEN_DIRTY);

停止持续渲染。当调用
GLSurfaceView.requestRender()时,程序再渲染屏幕。
调试GLSurfaceView.setDebugFlags() 方法可以激活 log 或者错误检测,它们可以帮助调试 OpenGL ES 调用。具体使用时,在 GLSurfaceView 的构造函数中,调用 setRender() 之前调用 GLSurfaceView.setDebugFlags()就可以了。下面是个例子:

public ClearGLSurfaceView(Context context) {
    super(context);
    // Turn on error-checking and logging
    setDebugFlags(DEBUG_CHECK_GL_ERROR | DEBUG_LOG_GL_CALLS);
    mRenderer = new ClearRenderer();
    setRenderer(mRenderer);
}
0 0