• GLSurFaceView 特性


    本文转载自http://blog.csdn.net/chenglifan/article/details/7523876

    GLSurfaceView是一个视图,继承至SurfaceView,它内嵌的surface专门负责OpenGL渲染。

            GLSurfaceView提供了下列特性:
                1> 管理一个surface,这个surface就是一块特殊的内存,能直接排版到android的视图view上。
                2> 管理一个EGL display,它能让opengl把内容渲染到上述的surface上。
                3> 用户自定义渲染器(render)。
                4> 让渲染器在独立的线程里运作,和UI线程分离。
                5> 支持按需渲染(on-demand)和连续渲染(continuous)。
                6> 一些可选工具,如调试。
            
    使用GLSurfaceView
            通常会继承GLSurfaceView,并重载一些和用户输入事件有关的方法。如果你不需要重载事件方法,GLSurfaceView也可以直接使用,你可以使用set方法来为该类提供自定义的行为。例如,GLSurfaceView的渲染被委托给渲染器在独立的渲染线程里进行,这一点和普通视图不一样,setRenderer(Renderer)设置渲染器。
            
    初始化GLSurfaceView
            初始化过程其实仅需要你使用setRenderer(Renderer)设置一个渲染器(render)。当然,你也可以修改GLSurfaceView一些默认配置。
                * setDebugFlags(int)
                * setEGLConfigChooser(boolean)
                * setEGLConfigChooser(EGLConfigChooser)
                * setEGLConfigChooser(int, int, int, int, int, int)
                * setGLWrapper(GLWrapper) 

    定制android.view.Surface
            GLSurfaceView默认会创建像素格式为PixelFormat.RGB_565的surface。如果需要透明效果,调用getHolder().setFormat(PixelFormat.TRANSLUCENT)。透明(TRANSLUCENT)的surface的像素格式都是32位,每个色彩单元都是8位深度,像素格式是设备相关的,这意味着它可能是ARGB、RGBA或其它。
            
    选择EGL配置
            Android设备往往支持多种EGL配置,可以使用不同数目的通道(channel),也可以指定每个通道具有不同数目的位(bits)深度。因此,在渲染器工作之前就应该指定EGL的配置。GLSurfaceView默认EGL配置的像素格式为RGB_656,16位的深度缓存(depth buffer),默认不开启遮罩缓存(stencil buffer)。
            如果你要选择不同的EGL配置,请使用setEGLConfigChooser方法中的一种。
            
    调试行为
            你可以调用调试方法setDebugFlags(int)或setGLWrapper(GLSurfaceView.GLWrapper)来自定义GLSurfaceView一些行为。在setRenderer方法之前或之后都可以调用调试方法,不过最好是在之前调用,这样它们能立即生效。
            
    设置渲染器
            总之,你必须调用setRenderer(GLSurfaceView.Renderer)来注册一个GLSurfaceView.Renderer渲染器。渲染器负责真正的GL渲染工作。
            
    渲染模式
            渲染器设定之后,你可以使用setRenderMode(int)指定渲染模式是按需(on demand)还是连续(continuous)。默认是连续渲染。
            
    Activity生命周期
            Activity窗口暂停(pause)或恢复(resume)时,GLSurfaceView都会收到通知,此时它的onPause方法和onResume方法应该被调用。这样做是为了让GLSurfaceView暂停或恢复它的渲染线程,以便它及时释放或重建OpenGL的资源。
            
    事件处理
            为了处理事件,一般都是继承GLSurfaceView类并重载它的事件方法。但是由于GLSurfaceView是多线程操作,所以需要一些特殊的处理。由于渲染器在独立的渲染线程里,你应该使用Java的跨线程机制跟渲染器通讯。queueEvent(Runnable)方法就是一种相对简单的操作,例如下面的例子。
            
    [java] view plaincopy
    1. class MyGLSurfaceView extends GLSurfaceView {  
    2.     private MyRenderer mMyRenderer;  
    3.   
    4.         public void start() {  
    5.             mMyRenderer = ...;  
    6.             setRenderer(mMyRenderer);  
    7.         }  
    8.   
    9.   
    10.         public boolean onKeyDown(int keyCode, KeyEvent event) {  
    11.   
    12.             if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {  
    13.                 queueEvent(new Runnable() {  
    14.                     // 这个方法会在渲染线程里被调用  
    15.                          public void run() {  
    16.                              mMyRenderer.handleDpadCenter();  
    17.                          }});  
    18.                      return true;  
    19.                  }  
    20.   
    21.                  return super.onKeyDown(keyCode, event);  
    22.             }  
    23.       }  
    24. }  
     
            (注:如果在UI线程里调用渲染器的方法,很容易收到“call to OpenGL ES API with no current context”的警告,典型的误区就是在键盘或鼠标事件方法里直接调用opengl es的API,因为UI事件和渲染绘制在不同的线程里。更甚者,这种情况下调用glDeleteBuffers这种释放资源的方法,可能引起程序的崩溃,因为UI线程想释放它,渲染线程却要使用它。)
    实例说明:
    GLSurfaceView是一个很好的基类对于构建一个使用OpenGL ES进行部分或全部渲染的应用程序。一个2D或3D的动作游戏就是一个很好的例子,例如一个2D或3D的可视化应用如谷歌地图。
     
    以下是一个简单的GLSurfaceView的应用,一个最简单的OpenGL ES应用代码如下:
     
    [java] view plaincopy
    1. package  com.javaeye.googlers  
    2.   
    3. import javax.microedition.khronos.egl.EGLConfig;  
    4. import javax.microedition.khronos.opengles.GL10;  
    5. import android.app.Activity;  
    6. import android.opengl.GLSurfaceView;  
    7. import android.os.Bundle;  
    8.    
    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.   
    27.     protected void onResume() {  
    28.         super.onResume();  
    29.         mGLView.onResume();  
    30.     }  
    31.   
    32.     private GLSurfaceView mGLView;  
    33. }  
    34.   
    35. class ClearRenderer implements GLSurfaceView.Renderer {  
    36.   
    37.     public void onSurfaceCreated(GL10 gl, EGLConfig config) {  
    38.         // Do nothing special.  
    39.     }   
    40.   
    41.     public void onSurfaceChanged(GL10 gl, int w, int h) {  
    42.         gl.glViewport(00, w, h);  
    43.     }  
    44.   
    45.     public void onDrawFrame(GL10 gl) {  
    46.         gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);  
    47.     }  
    48. }  
     
    这个程序并没有做太多东西:它在每帧是清除屏幕到黑色。但是它是一个完整的OpenGL应用程序,正确地按照Activity(活动)的生命周期实现。当活动暂停渲染它也暂停渲染,活动恢复它也恢复。你可以把这个例子作为一个基本的交互的示例程序。仅仅更多地调用了ClearRenderer.onDrawFrame() 方法。注意你甚至不需要子类化一个GLSurfaceView视图。
     
    GLSurfaceView.Renderer 有三个方法:
    onSurfaceCreated() :在开始渲染的时候被调用,无论什么时候OpenGL ES 渲染不得不重新被创建。(渲染是典型的丢失并重新创建当活动被暂停或恢复。)该方法一个创建长生命周期OpenGL资源(如材质)的好地方。
    onSurfaceChanged():该方法在surface大小改变时被调用。这是设置你opengl视图端的好地方。如果相机是固定的,不会围着场景移动,你也可以在这里设置你的相机。
    onDrawFrame():每帧的时候该方法都会被调用,这个用于画场景是可靠的。你完全可以通过调用glClear方法开清楚帧缓存,接着通过其他的opengl ES来调用画当前的场景。
     
    用户如何输入?
    假如你想做一个可以交互的程序(如游戏),通常你会实现GLSurfaceView子类,因为这是很容易获取用户输入事件。以下代码是一个清晰的长例子展示给你怎样做到这个:
     
    [java] view plaincopy
    1. package com.javaeye.googlers;  
    2.   
    3. import javax.microedition.khronos.egl.EGLConfig;  
    4. import javax.microedition.khronos.opengles.GL10;  
    5. import android.app.Activity;  
    6. import android.content.Context;  
    7. import android.opengl.GLSurfaceView;  
    8. import android.os.Bundle;  
    9. import android.view.MotionEvent;  
    10.   
    11. public class ClearActivity extends Activity {  
    12.   
    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.   
    37.     public ClearGLSurfaceView(Context context) {  
    38.         super(context);  
    39.         mRenderer = new ClearRenderer();  
    40.         setRenderer(mRenderer);  
    41.     }  
    42.   
    43.     public boolean onTouchEvent(final MotionEvent event) {  
    44.         queueEvent(new Runnable(){  
    45.             public void run() {  
    46.                 mRenderer.setColor(event.getX() / getWidth(),  
    47.                         event.getY() / getHeight(), 1.0f);  
    48.             }});  
    49.   
    50.             return true;  
    51.         }  
    52.   
    53.         ClearRenderer mRenderer;  
    54. }  
    55.    
    56.   
    57. class ClearRenderer implements GLSurfaceView.Renderer {  
    58.   
    59.     public void onSurfaceCreated(GL10 gl, EGLConfig config) {  
    60.         // Do nothing special.  
    61.     }  
    62.   
    63.     public void onSurfaceChanged(GL10 gl, int w, int h) {  
    64.         gl.glViewport(00, w, h);  
    65.     }  
    66.   
    67.     public void onDrawFrame(GL10 gl) {  
    68.         gl.glClearColor(mRed, mGreen, mBlue, 1.0f);  
    69.         gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);  
    70.     }  
    71.   
    72.    
    73.     public void setColor(float r, float g, float b) {  
    74.         mRed = r;  
    75.         mGreen = g;  
    76.         mBlue = b;  
    77.     }  
    78.   
    79.     private float mRed;  
    80.     private float mGreen;  
    81.     private float mBlue;  
    82. }  

     
    这个应用每帧都在清楚屏幕。当你点击屏幕时,它清除颜色基于你触屏时间的X、Y坐标。注意在 ClearGLSurfaceView.onTouchEvent()中使用queueEvent()。queueEvent()方法被安全地用于在UI线程和渲染线程之间进行交流。如果你愿意,你还可以使用一些其他的java线程间交流技术,例如Renderer 类本身的同步方法。然而,queueing 事件经常是一种用于处理线程间信息交流的更简单方式。
     
    其他的GLSurfaceView示例:
    如果你厌烦了上面的示例,你还可以从android的ApiDemo中找到更经典的示例,所有的openGL ES示例都是用GLSurfaceView视图转变的:
     
    GLSurfaceView - 一个旋转的三角形
    Kube - 一个魔方例子
    Translucent GLSurfaceView - 展示在一个透明的背景上显示3d动画
    Textured Triangle - 显示一个带纹理的3D三角形
    Sprite Text - 展示怎样用材质画出文字并混合进一个3d的场景中
    Touch Rotate - 展示怎样旋转一个3D物体来响应用户的输入

  • 相关阅读:
    强化训练1
    强化训练2
    变量的本质
    抽象层
    安装vs2015
    解决思路
    分析栈的缺点
    (转)使用yuicompressor-maven-plugin压缩js及css文件(二)
    (转)yuicompressor 与 maven结合,打包,压缩js,css (一)
    (转)Properties Editor为你解除通过native2ascii进行Unicode转码的烦恼
  • 原文地址:https://www.cnblogs.com/lemonhome/p/4492626.html
Copyright © 2020-2023  润新知