Android: OpenGL ES 1.0/1.1/2.0/3.0初探

看着网上关于OpenGL ES相关的教程很少,有的也是基于iOS或者是Android Java相关的教程,对于Android Native应用的教程基本上找不到。

  • Android系统对OpenGL ES的支持情况

– OpenGL ES 1.0/1.1: Android 1.0及以上

– OpenGL ES 2.0: Android 2.2(API 8)及以上

– OpenGL ES 3.0: Android 4.3(API 18)及以上

– OpenGL ES 3. 1: Android 5.0(API 21)及以上

对于Android原生系统来说,emulator运行时如果没有启用host GPU硬件加速的情况下,可以通过软件模拟OpenGL ES 1.0/1.1对窗口进行绘制。在Android系统开机过程中出现的bootanimation,图象就是通过OpenGL ES 1.0/1.1进行绘制,显示在屏幕上的。相关的代码可以参考frameworks/base/opengl/libagl与system/core/pixelflinger。

  • Android原生代码中几个比较有意思的应用

使用的是Android-5.1.1_r15分支中的代码。对于OpenGL ES 1.0/1.1中的应用,可以参考frameworks/base/cmds/bootanimation与frameworks/native/opengl/tests。

1. frameworks/native/opengl/tests/gl2_basic

OpenGL ES 2.0引入了shader language,最明显的是你可以在代码中看到vertex shader与fragment shader。简单来说对于你将到绘制的点、线、面中的每一个将来显示在屏幕上的点都会走一遍vertex shader确定点的位置,再走一遍fragment shader确定点的颜色。

下面这段代码会在屏幕上绘制一个三角形:

const GLfloat gTriangleVertices[] = { 0.0f, 0.5f, -0.5f, -0.5f,
        0.5f, -0.5f };

void renderFrame() {
    glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
    checkGlError("glClearColor");
    glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
    checkGlError("glClear");

    glUseProgram(gProgram);
    checkGlError("glUseProgram");

    glVertexAttribPointer(gvPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, gTriangleVertices);
    checkGlError("glVertexAttribPointer");
    glEnableVertexAttribArray(gvPositionHandle);
    checkGlError("glEnableVertexAttribArray");
    glDrawArrays(GL_TRIANGLES, 0, 3);
    checkGlError("glDrawArrays");
}

这个App中使用到的vertex shader与fragment shader:

static const char gVertexShader[] = "attribute vec4 vPosition;\n"
    "void main() {\n"
    "  gl_Position = vPosition;\n"
    "}\n";

static const char gFragmentShader[] = "precision mediump float;\n"
    "void main() {\n"
    "  gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
    "}\n";

上面的代码片段其实就是对绘制的图象使用绿色进行填充。最终在屏幕上会出现如下图象:

2016_04_03_gl2_basic

2. frameworks/native/opengl/tests/angles

原文请看这里:http://jet.ro/visuals/4k-intros/san-angeles-observation/

————————————————————————

San Angeles Observation OpenGL ES version example

Copyright 2004-2005 Jetro Lauha

Web: http://iki.fi/jetro/

See file license.txt for licensing information.

————————————————————————

This is an OpenGL ES port of the small self-running demonstration called “San Angeles Observation”, which was first presented in the Assembly’2004 event. It won the first place in the 4 KB intro competition category.

The demonstration features a sightseeing of a futuristic city having many different kind of buildings and items. Everything is flat shaded with three different lights.

The original version was made for desktop with OpenGL. It was naturally heavily size optimized in order to fit it in the size limit. For this OpenGL ES version example much of the code is cleaned up and the sound is removed. Also detail level is lowered, although it still contains over 60000 faces.

对应的Android APK代码在development/ndk/platforms/android-4/samples/san-angeles,附相应的Android.mk:

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)                                                                     
LOCAL_MODULE_TAGS := optional                                                             
LOCAL_MODULE := libsanangeles                                                             
LOCAL_SRC_FILES := \
    jni/importgl.c \                                                                      
    jni/demo.c \
    jni/app-android.c
LOCAL_CFLAGS := -DDISABLE_IMPORTGL                                                        
LOCAL_SHARED_LIBRARIES := libdl liblog libGLESv1_CM                                       
include $(BUILD_SHARED_LIBRARY)                                                           

include $(CLEAR_VARS)                                                                     
LOCAL_MODULE_TAGS := tests                                                                
LOCAL_PACKAGE_NAME := SanAngeles 
ifneq ($(ONE_SHOT_MAKEFILE),)                                                             
TARGET_BUILD_APPS := $(LOCAL_PACKAGE_NAME)                                                
endif
LOCAL_JNI_SHARED_LIBRARIES := libsanangeles
LOCAL_DIST_BUNDLED_BINARIES := true
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PROGUARD_ENABLED := disabled
include $(BUILD_PACKAGE)

有意思的是这个demo在emulator里面运行速度可能更快,详见src/com/example/SanAngeles/DemoActivity.java中的comments:

 * This program demonstrates how to use a GLSurfaceView from Java
 * along with native OpenGL calls to perform frame rendering.
 *
 * Touching the screen will start/stop the animation.
 *
 * Note that the demo runs much faster on the emulator than on
 * real devices, this is mainly due to the following facts:
 *
 * - the demo sends bazillions of polygons to OpenGL without
 *   even trying to do culling. Most of them are clearly out
 *   of view.
 *
 * - on a real device, the GPU bus is the real bottleneck
 *   that prevent the demo from getting acceptable performance.
 *
 * - the software OpenGL engine used in the emulator uses
 *   the system bus instead, and its code rocks 🙂
  • pixelshaders.com中几个比较有意思的应用

Pixel Sharers中提供了一些关于如何使用shader language简单的sample,并且使用的shader language的语法与OpenGL ES基本相同,非常适合我等初学者学习。由于其中的demo只包含有fragment shader的代码,我们还需要添加额外的代码才能在Android系统中运行(当然,你也可以直接使用他所提供的shader editor在线编辑调试)。

为了简化流程,我们通过修改frameworks/native/opengl/tests/gl2_basic代码来实现(绘制一个全屏的四边形):

const GLfloat gTriangleVertices[] = {
    -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f,
    -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f
};

void renderFrame() {
#if 0
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    checkGlError("glClearColor");
    glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
    checkGlError("glClear");
#endif

    glUseProgram(gProgram);
    checkGlError("glUseProgram");

    glVertexAttribPointer(gvPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, gTriangleVertices);
    checkGlError("glVertexAttribPointer");
    glEnableVertexAttribArray(gvPositionHandle);
    checkGlError("glEnableVertexAttribArray");
    glDrawArrays(GL_TRIANGLES, 0, 6);
    checkGlError("glDrawArrays");
}

下面看一下其中的几个简单例子:

a. http://pixelshaders.com/proposal/

代码:

static const char gVertexShader[] =
    "attribute vec4 vPosition;\n"
    "\n"
    "varying vec2 position;\n"
    "\n"
    "void main() {\n"
    "  gl_Position = vPosition;\n"
    "  position = vec2(vPosition.x, vPosition.y);\n"
    "}\n";

static const char gFragmentShader[] =
    "precision mediump float;\n"
    "\n"
    "varying vec2 position;\n"
    "\n"
    "void main() {\n"
    "  vec2 p = position - vec2(0., 0.);\n"
    "\n"
    "  float radius = length(p);\n"
    "  float angle = atan(p.y, p.x);\n"
    "\n"
    "  gl_FragColor.r = radius;\n"
    "  gl_FragColor.g = 0.0;\n"
    "  gl_FragColor.b = abs(angle / 3.14159);\n"
    "  gl_FragColor.a = 1.0;\n"
    "}\n";

效果如下图:

2016_04_03_pixelshaders_gradients

b. http://pixelshaders.com/examples/sampling-displacement.html

代码:

static const char gVertexShader[] = 
    "attribute vec4 vPosition;\n" 
    "\n" 
    "varying vec2 position;\n" 
    "\n" 
    "void main() {\n" 
    "  gl_Position = vPosition;\n" 
    "  position = vec2(vPosition.x, vPosition.y);\n" 
    "}\n"; 
 
static const char gFragmentShader[] = 
    "precision mediump float;\n" 
    "\n" 
    "varying vec2 position;\n" 
    "\n" 
    "float checkerboard(vec2 p, float steps) {\n" 
    "  float x = floor(p.x * steps);\n" 
    "  float y = floor(p.y * steps);\n" 
    "  return mod(x + y, 2.);\n" 
    "}\n" 
    "\n" 
    "void main() {\n" 
    "  vec2 p = position;\n" 
    "\n" 
    "  float brightness = checkerboard(p, 20.);\n" 
    "  gl_FragColor.rgb = vec3(brightness);\n" 
    "  gl_FragColor.a = 1.;\n" 
    "}\n"; 

效果:

2016_04_03_pixelshader_checkerboard

c. http://pixelshaders.com/examples/quasicrystal.html

代码:

static const char gVertexShader[] =
    "attribute vec4 vPosition;\n"
    "\n"
    "varying vec2 position;\n"
    "\n"
    "void main() {\n"
    "  gl_Position = vPosition;\n"
    "  position = vec2(vPosition.x, vPosition.y);\n"
    "}\n";

static const char gFragmentShader[] =
    "precision mediump float;\n"
    "\n"
    "varying vec2 position;\n"
    "uniform float time;\n"
    "\n"
    "float wave(vec2 p, float angle) {\n"
    "  vec2 direction = vec2(cos(angle), sin(angle));\n"
    "  return cos(dot(p, direction));\n"
    "}\n"
    "\n"
    "float wrap(float x) {\n"
    "  return abs(mod(x, 2.)-1.);\n"
    "}\n"
    "\n"
    "void main() {\n"
    "  vec2 p = (position - 0.5) * 50.;\n"
    "\n"
    "  float brightness = 0.;\n"
    "  for (float i = 1.; i <= 11.; i++) {\n"
    "    brightness += wave(p, time / i);\n"
    "  }\n"
    "\n"
    "  brightness = wrap(brightness);\n"
    "\n"
    "  gl_FragColor.rgb = vec3(brightness);\n"
    "  gl_FragColor.a = 1.;\n"
    "}\n";

由于fragment shader中使用了uniform,所以还需要修改代码更新time:

void renderFrame() {
#if 0
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    checkGlError("glClearColor");
    glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
    checkGlError("glClear");
#endif
    static nsecs_t start = systemTime();

    glUseProgram(gProgram);
    checkGlError("glUseProgram");

    nsecs_t end = systemTime();
    GLuint uniTime = glGetUniformLocation(gProgram, "time");
    glUniform1f(uniTime, (float)(end - start) / 1000000000);

    glVertexAttribPointer(gvPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, gTriangleVertices);
    checkGlError("glVertexAttribPointer");
    glEnableVertexAttribArray(gvPositionHandle);
    checkGlError("glEnableVertexAttribArray");
    glDrawArrays(GL_TRIANGLES, 0, 6);
    checkGlError("glDrawArrays");
}

效果:

  • open.gl中比较有意思的应用

原文链接:https://open.gl/depthstencils

代码请从这里下载:2016_04_03_opengl_stencil.tar.gz

由于代码中使用glm库,还需要下载如下代码:

$ git clone https://github.com/g-truc/glm.git
$ pushd glm && git checkout 66b714c && popd

效果:

  • 相关的参考文档:
  1. https://www.khronos.org/opengles/
  2. http://www.opengl.org/documentation/specs/version2.0/glspec20.pdf
  3. http://developer.android.com/guide/topics/graphics/opengl.html
  4. http://iki.fi/jetro/
  5. http://jet.ro/visuals/san-angeles-observation/
  6. http://pixelshaders.com/
  7. https://open.gl/depthstencils

发表评论

电子邮件地址不会被公开。 必填项已用*标注