Gallery 3D 代码分析之 GLSurfaceView

 

  •      使得 OpenGL ES 可以工作在 Activity 生命周期中;
  •      可选择合适的 frame buffer 像素格式;
  •      创建并管理一个单独的渲染线程,可以实现平滑的动画;
  •      提供 debugging 工具和 API。


  • 一个简单的 GLSurfaceView 应用

    Java代码 复制代码
    1. package com.example.android.apis.graphics;   
    2.   
    3. import javax.microedition.khronos.egl.EGLConfig;   
    4. import javax.microedition.khronos.opengles.GL10;   
    5.   
    6. import android.app.Activity;   
    7. import android.opengl.GLSurfaceView;   
    8. import android.os.Bundle;   
    9.   
    10. public class ClearActivity extends Activity {   
    11.     @Override  
    12.     protected void onCreate(Bundle savedInstanceState) {   
    13.         super.onCreate(savedInstanceState);   
    14.         mGLView = new GLSurfaceView(this);   
    15.         mGLView.setRenderer(new ClearRenderer());   
    16.         setContentView(mGLView);   
    17.     }   
    18.   
    19.     @Override  
    20.     protected void onPause() {   
    21.         super.onPause();   
    22.         mGLView.onPause();   
    23.     }   
    24.   
    25.     @Override  
    26.     protected void onResume() {   
    27.         super.onResume();   
    28.         mGLView.onResume();   
    29.     }   
    30.   
    31.     private GLSurfaceView mGLView;   
    32. }   
    33.   
    34. class ClearRenderer implements GLSurfaceView.Renderer {   
    35.     public void onSurfaceCreated(GL10 gl, EGLConfig config) {   
    36.         // Do nothing special.   
    37.     }   
    38.   
    39.     public void onSurfaceChanged(GL10 gl, int w, int h) {   
    40.         gl.glViewport(00, w, h);   
    41.     }   
    42.   
    43.     public void onDrawFrame(GL10 gl) {   
    44.         gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);   
    45.     }   
    46. }  
    package com.example.android.apis.graphics;
    
    import javax.microedition.khronos.egl.EGLConfig;
    import javax.microedition.khronos.opengles.GL10;
    
    import android.app.Activity;
    import android.opengl.GLSurfaceView;
    import android.os.Bundle;
    
    public class ClearActivity extends Activity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            mGLView = new GLSurfaceView(this);
            mGLView.setRenderer(new ClearRenderer());
            setContentView(mGLView);
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            mGLView.onPause();
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            mGLView.onResume();
        }
    
        private GLSurfaceView mGLView;
    }
    
    class ClearRenderer implements GLSurfaceView.Renderer {
        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
            // Do nothing special.
        }
    
        public void onSurfaceChanged(GL10 gl, int w, int h) {
            gl.glViewport(0, 0, w, h);
        }
    
        public void onDrawFrame(GL10 gl) {
            gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
        }
    }
    
    


    这个程序功能很简单,每帧绘制时将屏幕设置成黑色。但它是一个完整的工作在 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,由此可以获取输入事件。下面有个例子:

    Java代码 复制代码
    1. package com.google.android.ClearTest;   
    2.   
    3. import javax.microedition.khronos.egl.EGLConfig;   
    4. import javax.microedition.khronos.opengles.GL10;   
    5.   
    6. import android.app.Activity;   
    7. import android.content.Context;   
    8. import android.opengl.GLSurfaceView;   
    9. import android.os.Bundle;   
    10. import android.view.MotionEvent;   
    11.   
    12. public class ClearActivity extends Activity {   
    13.     @Override  
    14.     protected void onCreate(Bundle savedInstanceState) {   
    15.         super.onCreate(savedInstanceState);   
    16.         mGLView = new ClearGLSurfaceView(this);   
    17.         setContentView(mGLView);   
    18.     }   
    19.   
    20.     @Override  
    21.     protected void onPause() {   
    22.         super.onPause();   
    23.         mGLView.onPause();   
    24.     }   
    25.   
    26.     @Override  
    27.     protected void onResume() {   
    28.         super.onResume();   
    29.         mGLView.onResume();   
    30.     }   
    31.   
    32.     private GLSurfaceView mGLView;   
    33. }   
    34.   
    35. class ClearGLSurfaceView extends GLSurfaceView {   
    36.     public ClearGLSurfaceView(Context context) {   
    37.         super(context);   
    38.         mRenderer = new ClearRenderer();   
    39.         setRenderer(mRenderer);   
    40.     }   
    41.   
    42.     public boolean onTouchEvent(final MotionEvent event) {   
    43.         queueEvent(new Runnable(){   
    44.             public void run() {   
    45.                 mRenderer.setColor(event.getX() / getWidth(),   
    46.                         event.getY() / getHeight(), 1.0f);   
    47.             }});   
    48.             return true;   
    49.         }   
    50.   
    51.         ClearRenderer mRenderer;   
    52. }   
    53.   
    54. class ClearRenderer implements GLSurfaceView.Renderer {   
    55.     public void onSurfaceCreated(GL10 gl, EGLConfig config) {   
    56.         // Do nothing special.   
    57.     }   
    58.   
    59.     public void onSurfaceChanged(GL10 gl, int w, int h) {   
    60.         gl.glViewport(00, w, h);   
    61.     }   
    62.   
    63.     public void onDrawFrame(GL10 gl) {   
    64.         gl.glClearColor(mRed, mGreen, mBlue, 1.0f);   
    65.         gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);   
    66.     }   
    67.   
    68.     public void setColor(float r, float g, float b) {   
    69.         mRed = r;   
    70.         mGreen = g;   
    71.         mBlue = b;   
    72.     }   
    73.   
    74.     private float mRed;   
    75.     private float mGreen;   
    76.     private float mBlue;   
    77. }  
    package com.google.android.ClearTest;
    
    import javax.microedition.khronos.egl.EGLConfig;
    import javax.microedition.khronos.opengles.GL10;
    
    import android.app.Activity;
    import android.content.Context;
    import android.opengl.GLSurfaceView;
    import android.os.Bundle;
    import android.view.MotionEvent;
    
    public class ClearActivity extends Activity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            mGLView = new ClearGLSurfaceView(this);
            setContentView(mGLView);
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            mGLView.onPause();
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            mGLView.onResume();
        }
    
        private GLSurfaceView mGLView;
    }
    
    class ClearGLSurfaceView extends GLSurfaceView {
        public ClearGLSurfaceView(Context context) {
            super(context);
            mRenderer = new ClearRenderer();
            setRenderer(mRenderer);
        }
    
        public boolean onTouchEvent(final MotionEvent event) {
            queueEvent(new Runnable(){
                public void run() {
                    mRenderer.setColor(event.getX() / getWidth(),
                            event.getY() / getHeight(), 1.0f);
                }});
                return true;
            }
    
            ClearRenderer mRenderer;
    }
    
    class ClearRenderer implements GLSurfaceView.Renderer {
        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
            // Do nothing special.
        }
    
        public void onSurfaceChanged(GL10 gl, int w, int h) {
            gl.glViewport(0, 0, w, h);
        }
    
        public void onDrawFrame(GL10 gl) {
            gl.glClearColor(mRed, mGreen, mBlue, 1.0f);
            gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
        }
    
        public void setColor(float r, float g, float b) {
            mRed = r;
            mGreen = g;
            mBlue = b;
        }
    
        private float mRed;
        private float mGreen;
        private float mBlue;
    }


    其他的 GLSurfaceView 例子

    在 Android SDK 的 API Demo例子程序中还有很多例子:

    •      GLSurfaceView
    •      Kube
    •      Translucent GLSurfaceView:透明背景
    •      Textured Triangle:纹理贴图
    •      Sprite Text:在 texture 上写文本并显示在 3D 场景中
    •      Touch Rotate:旋转 3D 对象



    选择一个 Surface

    GLSurfaceView 提供了接口可选择 surface 的类型。默认情况下, GLSurfaceView 会使用一个 16 位 RGB frame buffer,带 16 位深度。你也可以根据自己的需要进行选择,比如在 Translucent GLSurfaceView 例子里,需要一个 Alpha 通道来实现透明。GLSurfaceView 提供了 setEGLSurfaceChooser()方法来选择 surface。

    选择一个 RGB (565)的16位 framebuffer,接口如下:

    Java代码 复制代码
    1. setEGLConfigChooser(boolean needDepth)  
    setEGLConfigChooser(boolean needDepth)



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

    Java代码 复制代码
    1. setEGLConfigChooser(int redSize, int greenSize,int blueSize, int alphaSize,int depthSize, int stencilSize)  
    setEGLConfigChooser(int redSize, int greenSize,int blueSize, int alphaSize,int depthSize, int stencilSize)
    



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

    Java代码 复制代码
    1. setEGLConfigChooser(EGLConfigChooser configChooser)  
    setEGLConfigChooser(EGLConfigChooser configChooser)



    持续型渲染模式 & 通知型渲染模式

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

    Java代码 复制代码
    1. GLSurfaceView.setRenderMode(RENDERMODE_WHEN_DIRTY);  
    GLSurfaceView.setRenderMode(RENDERMODE_WHEN_DIRTY);



    停止持续渲染。当调用

    Java代码 复制代码
    1. GLSurfaceView.requestRender()  
    GLSurfaceView.requestRender()



    时,程序再渲染屏幕。
    调试

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

    Java代码 复制代码
    1. public ClearGLSurfaceView(Context context) {   
    2.     super(context);   
    3.     // Turn on error-checking and logging   
    4.     setDebugFlags(DEBUG_CHECK_GL_ERROR | DEBUG_LOG_GL_CALLS);   
    5.     mRenderer = new ClearRenderer();   
    6.     setRenderer(mRenderer);   
    7. }  

    你可能感兴趣的:(游戏,工作,android,Google,OS)