OpenGL ES(Android)的学习路径(概念)

Android包括高性能2D和3D图形开放图形库(OpenGL®的),具体而言,OpenGL ES的API支持。OpenGL是一个跨平台的图形API,用于指定的3D图形处理硬件标准的软件接口。ES是用于嵌入式设备的OpenGL规范的味道​​。Android支持OpenGL ES的API的几个版本:

  • 的OpenGL ES 1.0和1.1 - 本API规范是由Android 1.0及更高版本支持。
  • OpenGL ES 2.0的 - 这个API规范由Android 2.2的(API 8级)或更高版本支持。
  • 的OpenGL ES 3.0 - 本API规范是由Android 4.3(API级别18)和更高的支持。
  • 的OpenGL ES 3.1 - 这个API规范由是Android 5.0(API级别21)和更高的支持。

注意: 在设备上的OpenGL ES 3.0 API的支持,需要由设备制造商提供了这个图形管线的实现。运行Android 4.3或更高版本的设备可能不支持 OpenGL ES的3.0 API。有关检查在运行时支持哪些版本的OpenGL ES的信息,请参阅检查OpenGL ES版本

注意: 由Android框架所提供的特定的API是类似于J2ME JSR239 OpenGL ES的API,但是是不相同的。如果您熟悉J2ME JSR239规范,对变化的警报。


基础


Android的支持OpenGL既通过其框架API和原生开发套件(NDK)。本主题重点介绍了Android框架接口。有关NDK的更多信息,请参阅的Android NDK

有两个基础班在Android框架,让您创建和操纵符合OpenGL ES API的图形:GLSurfaceViewGLSurfaceView.Renderer。如果你的目标是使用OpenGL在你的Android应用程序,了解如何实现一个活动,这些类应该是你的第一个目标。

GLSurfaceView
这个类是 View在那里你可以绘制和操作使用OpenGL API调用的对象和在功能上类似 SurfaceView。您可以通过创建的实例中使用这个类 GLSurfaceView,并添加你  Renderer给它。但是,如果你想捕捉触摸屏事件,您应该扩展 GLSurfaceView类来实现触摸监听器,如图OpenGL的训练课中,  响应触摸事件
GLSurfaceView.Renderer
该接口定义了用于绘制在图形所需要的方法 GLSurfaceView。你必须提供这个接口作为一个单独的类的实现,并将其连接到您的 GLSurfaceView使用实例  GLSurfaceView.setRenderer()

GLSurfaceView.Renderer接口要求您实现以下方法:

  • onSurfaceCreated():系统调用这个方法一次,在创建的时候GLSurfaceView。使用此方法来执行只需要发生一次的操作,如设置OpenGL的环境参数或初始化的OpenGL图形对象。
  • onDrawFrame():系统调用上的每个重绘此方法GLSurfaceView。使用此方法作为主要执行点绘制(并重新绘制)图形对象。
  • onSurfaceChanged():系统调用这个方法的时候GLSurfaceView几何形状变化,包括大小的更改GLSurfaceView或设备屏幕的方向。例如,当设备从纵向变为横向系统调用此方法。使用此方法可以在变化做出反应GLSurfaceView容器。


OpenGL ES的包

一旦你建立了使用OpenGL ES的一个容器视图GLSurfaceViewGLSurfaceView.Renderer,就可以开始使用调用下列类的OpenGL的API:

如果你想开始建设有OpenGL ES的应用程序向右走,跟着 用OpenGL ES图形显示 类。

声明要求的OpenGL


如果应用程序使用的OpenGL功能,这些功能并非适用于所有的设备,您必须在您的这些要求的AndroidManifest.xml文件。以下是最常见的OpenGL清单的声明:

  • OpenGL ES版本的要求 -如果你的应用需要OpenGL ES的特定版本,您必须通过如下图所示添加以下设置你的清单声明要求。

    对于OpenGL ES 2.0的:

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

添加此声明将使谷歌播放从被安装在不支持OpenGL ES 2.0标准的设备将应用程序限制。如果应用程序是专为支持的OpenGL ES 3.0的设备,你也可以在你的清单中指定的:

对于OpenGL ES的3.0:

<!-- Tell the system this app requires OpenGL ES 3.0. -->
<uses-feature android:glEsVersion="0x00030000" android:required="true" />
对于OpenGL ES的3.1:

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

注: OpenGL ES的3.X API与2.0 API,这意味着你可以与你的应用程序中实现的OpenGL ES的更灵活的向后兼容。通过声明的OpenGL ES 2.0 API作为您清单的要求,您可以使用该API版本作为默认,检查在运行时API 3.X的可用性,然后如果设备支持使用OpenGL ES 3.x的功能它。有关检查设备所支持的OpenGL ES版本的更多信息,请参阅检查OpenGL ES版本

纹理压缩的要求 -如果应用程序使用的纹理压缩格式,则必须使用声明应用程序支持的格式,在你的清单文件 <supports-gl-texture>。有关可用纹理压缩格式的详细信息,请参阅 纹理压缩支持

在清单中声明纹理压缩需求隐藏您的用户不支持您的声明压缩类型的至少一个器件中的应用。有关谷歌Play如何过滤作品的纹理压缩的更多信息,请参阅 谷歌Play和纹理压缩过滤的部分<supports-gl-texture>文件。



贴图坐标绘制的对象


其中一个在Android设备上显示图形的基本问题是,他们的屏幕可以在大小和形状各不相同。OpenGL的承担方,统一坐标系统,默认情况下,兴致勃勃地绘制这些坐标到您的典型的非方形屏幕,就好像它是完美的正方形。

图1.默认OpenGL的坐标系(左)映射到一个典型Android装置画面(右)。

上面的图显示了统一协调假设左侧一个OpenGL框架体系,以及如何将这些坐标实际上映射到一个典型的设备屏幕在右侧横向。为了解决这个问题,你可以申请OpenGL的投影模式和相机意见,使您的图形对象具有在任何显示器上以正确的比例转换坐标。

为了运用投影和相机视图,您创建一个投影矩阵,摄像机视图矩阵,并将其应用到OpenGL渲染管线。使他们正确地映射到Android设备屏幕的投影矩阵重新计算图形的坐标。摄像机视图矩阵创建从一个特定的眼睛位置渲染对象的变换。


在OpenGL ES 1.0投影和相机视图

在ES 1.0 API,通过创建每个矩阵,然后将其添加到OpenGL的环境中应用投影和相机视图。

  1. 投影矩阵 -为了重新计算对象创建使用该设备屏幕的几何形状的投影矩阵坐标,以便他们绘制的正确比例。下面的示例代码演示如何修改onSurfaceChanged()一个方法GLSurfaceView.Renderer 实现来创建基于屏幕的宽高比的投影矩阵,并将其应用到OpenGL渲染环境。
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        gl.glViewport(0, 0, width, height);
    
        // make adjustments for screen ratio
        float ratio = (float) width / height;
        gl.glMatrixMode(GL10.GL_PROJECTION);        // set matrix to projection mode
        gl.glLoadIdentity();                        // reset the matrix to its default state
        gl.glFrustumf(-ratio, ratio, -1, 1, 3, 7);  // apply the projection matrix
    }
  2. 相机变换矩阵 -一旦你使用调整投影矩阵坐标系统,您还必须应用摄影机视图。下面的示例代码显示了如何修改onDrawFrame()一个方法GLSurfaceView.Renderer 实现应用模型视图,并使用 GLU.gluLookAt()实用工具创建一个观景穿越-它模拟摄像机位置。
    public void onDrawFrame(GL10 gl) {
        ...
        // Set GL_MODELVIEW transformation mode
        gl.glMatrixMode(GL10.GL_MODELVIEW);
        gl.glLoadIdentity();                      // reset the matrix to its default state
    
        // When using GL_MODELVIEW, you must set the camera view
        GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
        ...
    }

在OpenGL ES 2.0的和更高的投影和相机视图

在ES 2.0和3.0的API,则通过首先添加矩阵部件图形对象的顶点着色器应用于投影和相机视图。有了这个矩阵成员加入,你就可以生成和应用投影和镜头视角矩阵来你的对象。

  1. 添加矩阵顶点着色器 -创建视图投影矩阵的变量,并把它作为着色器的位置的乘数。在下面的例子中顶点着色器代码,所包含的uMVPMatrix部件允许你投影和相机的观看矩阵应用到使用此着色的物体的坐标。
    private final String vertexShaderCode =
    
        // This matrix member variable provides a hook to manipulate
        // the coordinates of objects that use this vertex shader.
        "uniform mat4 uMVPMatrix;   \n" +
    
        "attribute vec4 vPosition;  \n" +
        "void main(){               \n" +
        // The matrix must be included as part of gl_Position
        // Note that the uMVPMatrix factor *must be first* in order
        // for the matrix multiplication product to be correct.
        " gl_Position = uMVPMatrix * vPosition; \n" +
    
        "}  \n";

    注:上面的例子定义了一个变换矩阵成员在其中应用组合投影矩阵和摄像机视图矩阵顶点着色器。根据您的应用需求,您可能要定义你的顶点着色器单独的投影矩阵和摄像机观察矩阵的成员,以便可以独立改变它们。

  2. 访问着色器矩阵 -在你的顶点着色器创建一个钩子应用投影和摄像头视图后,你就可以访问该变量应用投影和摄像头观看矩阵。下面的代码演示如何修改onSurfaceCreated()一个方法GLSurfaceView.Renderer实现访问上面的顶点着色器中定义的矩阵变量。
    public void onSurfaceCreated(GL10 unused, EGLConfig config) {
        ...
        muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
        ...
    }
  3. 创建投影和相机的观看矩阵 -生成的投影和观察矩阵要应用的图形对象。下面的示例代码显示了如何修改onSurfaceCreated()onSurfaceChanged()一个方法 GLSurfaceView.Renderer实现创建摄像机视图矩阵,并根据设备的屏幕高宽比的投影矩阵。
    public void onSurfaceCreated(GL10 unused, EGLConfig config) {
        ...
        // Create a camera view matrix
        Matrix.setLookAtM(mVMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
    }
    
    public void onSurfaceChanged(GL10 unused, int width, int height) {
        GLES20.glViewport(0, 0, width, height);
    
        float ratio = (float) width / height;
    
        // create a projection matrix from device screen geometry
        Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
    }
  4. 应用投影和镜头视角矩阵 -要应用投影和相机视图变换,乘矩阵一起,然后将其设置到顶点着色器。下面的代码示例演示如何修改onDrawFrame()一个方法GLSurfaceView.Renderer实施,在上面的代码创建的投影矩阵和摄像机视图结合起来,然后将其应用于通过的OpenGL渲染图形对象。
    public void onDrawFrame(GL10 unused) {
        ...
        // Combine the projection and camera view matrices
        Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0);
    
        // Apply the combined projection and camera view transformations
        GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
    
        // Draw objects
        ...
    }

有关如何运用投影和相机视图与OpenGL ES 2.0的一个完整的示例,请参见与OpenGL ES的显示图形 类。


外形面和绕线


在OpenGL,形状的面是由三个或更多个三维空间中定义的表面。一组三个或更多个三维点(称为在OpenGL顶点)具有一个前表面和背面。你怎么知道它的脸前,这是回来了?好问题。答案与缠绕,或者,您在其中定义形状的点的方向去做。

图1.插图换算成逆时针顺序绘制坐标列表。

在本例中,三​​角形的点中,使得它们在反时针方向绘制的顺序进行定义。在这些坐标被绘制的顺序定义了形状的卷绕方向。默认情况下,在OpenGL,这是逆时针方向绘制面对的是前脸。在图1所示的三角形被定义,以便你正在寻找的形状的前表面(由OpenGL作为解释),而另一侧是背面。

为什么很重要知道哪一个形状的脸是前面?答案与OpenGL的一个常用的功能,叫做脸扑杀做。面剔除是用于OpenGL的环境,它允许渲染流水线忽略(未计算或绘制)的形状的背面,节省了时间,存储器和处理周期一​​个选项:

// enable face culling feature
gl.glEnable(GL10.GL_CULL_FACE);
// specify which faces to not draw
gl.glCullFace(GL10.GL_BACK);

如果您尝试使用面部特征扑杀不知道,你的形状,两侧都是正面和背面,你的OpenGL图形要看看有点薄,或可能显示不出来的。所以,总是定义一个逆时针绘制顺序你的OpenGL图形的坐标。

注:这是可以设置一个OpenGL环境治疗顺时针脸的前脸,但这样做需要更多的代码,并有可能当你问他们帮忙来迷惑经验丰富的开发人员的OpenGL。所以,不要做。


OpenGL的版本和设备兼容性


OpenGL ES的1.0和1.1 API规范由于Android 1.0已经支持。采用Android 2.2(API 8级)开始,该框架支持的OpenGL ES 2.0 API规范。OpenGL ES 2.0的是大多数Android设备的支持,推荐用于新的应用程序正在使用OpenGL开发的。的OpenGL ES 3.0的支持与Android 4.3(API级别18)和更高,在提供OpenGL ES的3.0 API的实现设备。有关支持OpenGL ES的特定版本的Android供电设备的相对数量的信息,请参阅 OpenGL ES版本仪表板

图形编程的OpenGL ES 1.0 / 1.1 API比使用2.0及更高版本显著不同。API的1.x的版本有更方便的方法和固定图形管线,而的OpenGL ES 2.0和3.0 API提供了通过利用OpenGL着色器流水线的更直接的控制。您应该谨慎考虑显卡的要求并选择最适合您的应用程序API版本。欲了解更多信息,请参阅 选择一个OpenGL API版本

OpenGL ES的3.0 API提供了额外的功能,比2.0 API的性能更好,也向后兼容。这意味着你可能会写你的应用程序针对的OpenGL ES 2.0和条件包含的OpenGL ES 3.0图形功能,如果他们都可用。有关检查为3.0 API的可用性的详细信息,请参阅 检查OpenGL ES版本

纹理压缩支持

纹理压缩可以通过减少存储需求的同时更有效地利用内存带宽增加显著OpenGL应用程序的性能。Android框架提供了ETC1压缩格式作为标准功能,包括支持ETC1Util实用工具类和etc1tool压缩工具(位于Android SDK中的<sdk>/tools/)。对于使用纹理压缩一个Android应用程序的示例,请CompressedTextureActivity在Android SDK中的代码示例(<sdk>/samples/<version>/ApiDemos/src/com/example/android/apis/graphics/)。

注意:该ETC1格式是由大多数Android设备的支持,但它不能保证是可用的。要检查是否支持设备上的ETC1格式,调用该ETC1Util.isETC1Supported()方法。

注:该ETC1纹理压缩格式不支持的纹理与透明度(alpha通道)。如果应用程序需要使用透明纹理,您应该调查在目标设备上可用的其他的纹理压缩格式。

该ETC2 / EAC纹理压缩格式,保证使用的OpenGL ES 3.0 API时可用。这种纹理格式提供良好的压缩比与高视觉质量和格式还支持透明度(Alpha通道)。

除了​​ETC格式,Android设备都根据自己的GPU芯片和OpenGL实现纹理压缩多样的支持。您应该调查你的目标来确定应用程序应该支持什么样的压缩类型的设备上的纹理压缩的支持。为了确定哪些纹理格式都支持特定设备上,必须查询设备和审查OpenGL扩展名,其中确定哪些纹理压缩格式(和其他的OpenGL功能)的设备支持。一些常用支持的纹理压缩格式如下:

  • ATITC(ATC) - ATI纹理压缩(ATITC或ATC)可在多种设备,并支持RGB纹理使用和不使用alpha通道固定利率压缩。这种格式可以通过几种OpenGL扩展名,例如表示:
    • GL_AMD_compressed_ATC_texture
    • GL_ATI_texture_compression_atitc
  • PVRTC - PowerVR的纹理压缩(PVRTC)可在各种设备,并支持2位和每像素4位的纹理具有或不具有alpha通道。这种格式是由以下OpenGL扩展名来表示:
    • GL_IMG_texture_compression_pvrtc
  • S3TC(DXT ñ / DXTC) - S3纹理压缩(S3TC)有几个格式变化(DXT1到DXT5)和不太广泛使用。该格式支持RGB纹理与4位字母或8位Alpha通道。这些格式由下列OpenGL扩展名来表示:
    • GL_EXT_texture_compression_s3tc
    有些设备只支持DXT1格式的变化; 这种有限的支持是由以下OpenGL扩展名来表示:
    • GL_EXT_texture_compression_dxt1
  • 3DC - 3DC纹理压缩(3DC)是支持RGB纹理与alpha通道较少广泛使用的格式。这种格式是由以下OpenGL扩展名来表示:
    • GL_AMD_compressed_3DC_texture

警告:这些纹理压缩格式不支持的所有设备。对这些格式的支持可以通过制造商和设备而异。有关如何确定的格式是一个特定的设备上什么纹理压缩的信息,请参阅下一节。

注意:一旦你决定哪些纹理压缩格式的应用程序将支持,确保您在使用清单声明它们<支持-GL纹理> 。使用此声明允许通过外部服务,如谷歌播放过滤,从而仅安装在支持您的应用要求的格式设备上的应用程序。有关详细信息,请参阅 OpenGL的舱单申报

确定OpenGL扩展

的OpenGL的实现通过Android设备在扩展OpenGL ES的API所支持的方面有所不同。这些扩展包括纹理压缩,但通常还包括其他扩展到OpenGL的功能集。

要确定哪些纹理压缩格式,和其他OpenGL扩展,支持在特定设备上:

  1. 运行在目标设备上下面的代码,以确定支持哪些纹理​​压缩格式:
    字符串扩展= 使用javax microedition Khronos的opengles GL10 glGetString 
            GL10 GL_EXTENSIONS );

    警告:此调用的结果通过设备的实际情况!您必须运行在多个目标设备此调用,以确定哪些类型的压缩通常支持。

  2. 阅读本方法的输出,以确定哪些OpenGL扩展支持在设备上。

Android的扩展包(AEP)

该AEP确保您的应用程序支持一套标准化OpenGL扩展超出了OpenGL的3.1规范中描述的一套核心。包装这些扩展一起鼓励一套一致的跨设备的功能,同时允许开发人员能够充分利用移动GPU设备的最新作物。

该AEP还改善了图像,渲染存储缓冲器,并在片段着色原子专柜的支持。

对于您的应用程序能够使用的AEP,该应用程序的清单必须声明的AEP是必需的。此外,平台版本必须支持它。

申报清单中的AEP要求如下:

<uses feature android:name="android.hardware.opengles.aep"
              android:required="true" />
要验证平台版本支持AEP,使用  hasSystemFeature(String) 方法,传入  FEATURE_OPENGLES_EXTENSION_PACK 作为参数。下面的代码片段显示了如何做到这一点的例子:

boolean deviceSupportsAEP = getPackageManager().hasSystemFeature
     (PackageManager.FEATURE_OPENGLES_EXTENSION_PACK);

如果该方法返回true,AEP支持。

有关AEP的更多信息,请在浏览其网页 的Khronos OpenGL ES的注册

检查OpenGL ES版本

有在Android设备上提供多个版本的OpenGL ES的。你可以指定你的应用程序需要在你的API的最低版本的清单,但你也可能想利用功能的新的API在同一时间。例如,对OpenGL ES 3.0 API与2.0版本的API向后兼容,所以你可能需要编写你的应用程序,以便它使用的OpenGL ES 3.0的功能,但如果3.0 API不回落到2.0 API可用。

利用比你的应用程序清单所需的最低更高版本的OpenGL ES功能之前,你的应用程序应检查设备上可用的API的版本。您可以通过以下两种方式之一进行:

  1. 尝试建立更高级别的OpenGL ES上下文(EGLContext),并检查结果。
  2. 创建最小支持OpenGL ES的背景和检查版本价值。

下面的示例代码演示了如何通过创建检查可用的OpenGL ES版本EGLContext和检查结果。这个例子说明如何检查的OpenGL ES 3.0的版本:

private static double glVersion = 3.0;

private static class ContextFactory implements GLSurfaceView.EGLContextFactory {

  private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;

  public EGLContext createContext(
          EGL10 egl, EGLDisplay display, EGLConfig eglConfig) {

      Log.w(TAG, "creating OpenGL ES " + glVersion + " context");
      int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, (int) glVersion,
              EGL10.EGL_NONE };
      // attempt to create a OpenGL ES 3.0 context
      EGLContext context = egl.eglCreateContext(
              display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
      return context; // returns null if 3.0 is not supported;
  }
}

如果createContext()上面的方法显示返回null,你的代码应该创建一个OpenGL ES 2.0的范围内,而不是和回落到只使用该API。

下面的代码示例演示如何首先创建一个支持的最低上下文,然后检查版本字符串检查OpenGL ES版本:

// Create a minimum supported OpenGL ES context, then check:
String version = javax.microedition.khronos.opengles.GL10.glGetString(
        GL10.GL_VERSION);
Log.w(TAG, "Version: " + version );
// The version format is displayed as: "OpenGL ES <major>.<minor>"
// followed by optional content provided by the implementation.

通过这种方法,如果您发现该设备支持更高级别的API版本,您必须销毁最小的OpenGL ES的背景下,并创建一个新的上下文具有较高可用的API版本。




选择一个OpenGL API版本


的OpenGL ES 1.0 API的版本(和1.1扩展),2.0版和3.0版的所有用于创建3D游戏,可视化和用户界面,提供了高性能的图形界面。显卡预设电台的的OpenGL ES 2.0和3.0在很大程度上是相似的,与代表附加功能的2.0 API的超集3.0版本。为OpenGL ES的1.0 / 1.1 API与OpenGL ES的编程2.0和3.0不同显著,因此开发商应该仔细考虑开始使用这些API开发之前以下因素:

  • 性能 -一般情况下,的OpenGL ES 2.0和3.0提供比ES 1.0 / 1.1版本更快的图形性能。不过,性能差异可以根据您的OpenGL应用程序上,运行在Android设备上由于硬件制造商的实现的OpenGL ES图形管线的不同而有所差异。
  • 设备的兼容性 -开发者应该考虑的设备类型,版本的Android和可用到他们的客户的OpenGL ES版本。对于OpenGL的兼容性跨设备的详细信息,请参阅OpenGL的版本和设备兼容性部分。
  • 编码方便 - OpenGL ES的1.0 / 1.1 API提供了一个固定的功能管线和方便的功能,这是不是在OpenGL ES的2.0或3.0的API可用。开发谁是新的OpenGL ES可能会发现编码版本1.0 / 1.1更快,更方便。
  • 图形控制 - OpenGL ES的2.0和3.0的API,通过使用着色器提供完全可编程管线提供更高程度的控制。与图形处理管线的更直接的控制,开发者可以创建效果,将是非常困难的使用1.0 / 1.1 API生成。
  • 纹理支持 - OpenGL ES的3.0 API有纹理压缩了最好的支持,因为它保证了ETC2压缩格式,支持透明的可用性。在1.x和2.0 API的实现通常包括支持ETC1,但是这纹理格式不支持透明度,所以你通常必须提供资源,通过你的目标设备支持的其他压缩格式。欲了解更多信息,请参阅纹理压缩支持

虽然性能,兼容性,便利性,控制等因素都可能影响你的决定,你应该根据你的想法为你的用户提供最佳体验挑一个OpenGL API版本。



猜你喜欢

转载自blog.csdn.net/Android_Technology/article/details/52474279