android opengl 使用 安卓使用opengl_概念先行

一、前期基础是知识储备

笔者计划写三篇文章来详细分析OpenGL ES基础的同时也是入门关键的三个点:

①OpenGL ES是什么?与OpenGL的关系是什么?——概念部分

②使用OpenGL ES绘制2D/3D图形的第一步:定义图形;——运用部分

③使用OpenGL ES绘制出②步骤中定义好的图形:——运用部分,难点所在

通过这三篇文章的分析,就像给万丈高楼垫定了基石,万丈高楼平地起,后面利用OpenGLES做各种效果,各种变换都是建立在这三步的图形编程理解之上的。

android opengl 使用 安卓使用opengl_拉起框架_02

话不多说正文开始

(1)什么是OpenGL?

原作者   硅谷图形公司(SGI)

开发者   KhronosGroup

稳定版本   4.6(2017年7月31日 )

编程语言      C

操作系统      跨平台

类型       API

网站       http://www.opengl.org

OpenGL(英语:Open Graphics Library,译名:开放图形库或者“开放式图形库”)是用于渲染2D、3D矢量图形的跨语言、跨平台的应用程序编程接口(API)。这个接口由近350个不同的函数调用组成,用来从简单的图形比特绘制复杂的三维景象。OpenGL常用于CAD、虚拟实境、科学可视化程序和电子游戏开发。

为了加强它的多语言和多平台特性,已经用很多语言开发了OpenGL的各种绑定和移植——Java、Python、Perl、VisualBasic等等。

(2)什么是OpenGL ES?

原作者   KhronosGroup

开发者   KhronosGroup

稳定版本      3.1(2014年3月17日 )

编程语言      C

操作系统      跨平台

系统平台      跨平台

类型       API

网站       www.khronos.org/opengles

OpenGL ES(OpenGLfor Embedded Systems)是 OpenGL 三维图形API的子集,针对手机掌上电脑游戏主机等嵌入式设备而设计。该API由Khronos集团定义推广,科纳斯是一个图形软硬件行业协会,该协会主要关注图形和多媒体方面的开放标准。

OpenGL ES是从OpenGL裁剪定制而来的,去除了glBegin/glEnd,四边形(GL_QUADS)、多边形(GL_POLYGONS)等复杂图元等许多非绝对必要的特性

其实换句话说,由于手机等终端由于GPU、内存、性能等各方面的限制,不可能像电脑端那样完美执行OpenGL,所以,Khronos集团就为OpenGl提供了一个子集—OpenGl ES。

经过多年发展,现在主要有两个版本,OpenGL ES 1.x针对固定管线硬件的,OpenGL ES 2.x针对可编程管线硬件。现在Android开发使用的灵活度和可定制化程度更高的OpenGL ES 2.0版本,入门门槛相对于之前的OpenGL ES 1.x更高。

(3)OpenGL ES 1.x和OpenGL ES 2.x的区别——说明为什么OpenGL ES 2.0开发难度提高

android opengl 使用 安卓使用opengl_android opengl 使用_03

释义—OpenGL ES2.0, you make me write everything?—OpenGL ES2.0,你要让我自己实现所有事?

OpenGL ES版本內容变化有显著的差异,1.x还是fixed function pipeline(固定管线硬件),到了2.x就变成programmable pipeline(可编程管线硬件),也就是说,使用2.x的时候,尽管写最简单的程式(如基本作图、三角形、矩形或动作translate、rotate、scale等),一定要写shader(着色器/渲染器)才能运作,因而提高了入门的门槛。

OpenGL ES 1.x是以OpenGL1.5规格來制定,强调API使用硬体加速来实现;

OpenGL ES 2.x则是以OpenGL2.0來制定,强调使用可程式化3D绘图管线,可以产生shader和program object,藉由OpenGL ES Shading Language來写vertex shader(顶点着色器)和fragment shader(片元着色器)。

android opengl 使用 安卓使用opengl_拉起框架_04

这是OpenGL ES 1.x固定管线硬件的运作方式;(关注橙色部分)

android opengl 使用 安卓使用opengl_OpenGL ES_05

这是OpenGL ES 2.x可编程管线硬件的运作方式;(关注橙色部分)

从上面两幅图的对比,我们知道2.x跟1.x版的差异在于vertex shader(顶点着色器)是原本的 transform 和 lighting 的部分,fragment shader(片元着色器)則是对应到 texture、colour sum、fog、alpha test 等功能;也就是说,这些(橙色的部分)本來在fixed function pipeline 時会由系統來做的計算,現在在programmable pipeline 都要自己写 shader程式來做计算了,所以掌握的难度有所提高。

二、上代码,简单使用OpenGL ES

PS:准备工作

我们用的是Android Studio;

支持OpenGL ES 2.0或更高版本的Android设备。

android opengl 使用 安卓使用opengl_OpenGL ES_06

前面,一直在说使用OpenGL ES2.0难度有所提高……这里又说简单使用,是不是矛盾了?真的,相信笔者,这里说简单使用,是因为我们真的只是把使用框架建立起来,所以简单。分四步走:

第一步在 Manifest 配置文件中声明使用 OpenGL ES2.0;

<!--0x00020000 代表使用 OpenGL ES 2.0 接口-->

<uses-featureandroid:glEsVersion="0x00020000" android:required="true"/>

第二步为 OpenGL ES 图形创建一个 Activity;

使用 OpenGL ES 的Android 应用跟其它类型的应用主要的区别体现在 Activity 布局内容上的差异。通常我们会使用 TextView、Button等已经封装好的控件。而如果使用 OpenGL ES 的我们就得继承GLSurfaceView 来自己写子类实现了。

public class OpenGLSample01Activity extends AppCompatActivity {

    GLSurfaceView mGLSurfaceView;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setTitle("OpenGLSample01");

        // Create a GLSurfaceView instance and set it
        // as the ContentView for this Activity.
        mGLSurfaceView = new MyGLSurfaceView(this);
        setContentView(mGLSurfaceView);
    }
}

我们自定义一个MyGLSurfaceView,获得实例之后,作为参数传入setContentView中作为视图。到此为止,Activity创建完毕。

第三步自定义一个 MyGLSurfaceView 对象,继承自GLSurfaceView;

GLSurfaceView,看到这里有没有想起Android中View的孪生兄弟SurfaceView,专门用来处理需要频繁刷新的页面的SurfaceView,其实GLSurfaceView在OpEnGL中只是作为View容器,用来存放图形的,并且和Activity实现绑定。

class MyGLSurfaceView extends GLSurfaceView {

    private final MyGLRenderer mRenderer;

    public MyGLSurfaceView(Context context){
        super(context);

        // Create an OpenGL ES 2.0 context
        setEGLContextClientVersion(2);

        mRenderer = new MyGLRenderer();

        // Set the Renderer for drawing on the GLSurfaceView
        setRenderer(mRenderer);
        // Set the RenderMode
        mGLSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
    }
}

从代码我们可以看到,GLSurfaceView自己并不做太多和绘制图形相关的任务。绘制对象的任务是由该 View 中配置的 GLSurfaceView.Renderer 所控制的。在代码中,我们设置了GL ES版本,并将GLSurfaceView和Render连接起来。RenderMode有两种RENDERMODE_WHEN_DIRTY 和RENDERMODE_CONTINOUSLY,前者是懒惰渲染,需要手动调用glSurfeaceView.requestRender() 才会进行更新,而后者则是不停渲染。

第四步实现GLSurfaceView.Renderer接口,配置自己的渲染器;

在一个使用 OpenGL ES 的应用中,必定少不了 GLSurfaceView.Renderer 接口的实现。该接口会控制和其相关联的GLSurfaceView 的绘制行为内容(即绘制的图形和图形的特效),Renderer这个类中有三个方法会被系统调用,所以需要实现下面三个方法:

onSurfaceCreated():在Surface被创建时回调,用来配置 View 的 OpenGL ES 环境,只会被回调一次;

onDrawFrame():在绘制每一帧的时候回调;

onSurfaceChanged():在每次Surface尺寸变化时回调,例如当设备的屏幕方向发生改变时。

下面是一个非常基本的 OpenGL ES 渲染器的实现,它仅仅在GLSurfaceView 中画一个黑色的背景:

public class MyGLRenderer implements GLSurfaceView.Renderer {

    public void onSurfaceCreated(GL10 unused, EGLConfig config) {
        // Set the background frame color
        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    }

    public void onDrawFrame(GL10 unused) {
        // Redraw background color
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
    }

    public void onSurfaceChanged(GL10 unused, int width, int height) {
        //利用glViewport()设置Screen space的大小,在onSurfaceChanged中回调
        GLES20.glViewport(0, 0, width, height);
    }
}

Render接口重写的三个方法中调用的GLES20的API方法解析:

glClearColor()-设置清空屏幕用的颜色,接收四个参数分别是:红色、绿色、蓝色和透明度分量,0表示透明,1.0f相反;

glClear()-清空屏幕,清空屏幕后调用glClearColor()中设置的颜色填充屏幕;

glViewport()-设置视图的尺寸,这就告诉了OpenGL可以用来渲染surface的大小。

通过以上四步,我们就做完了一个简单但是颇为完整的OpenGL ES的绘制流程,是不是如笔者之前所说的还是比较简单的:

①创建一个GlSurfaceView,绑定至Activity;

②为这个GlSurfaceView设置渲染;

③在GlSurfaceView.renderer中绘制处理显示数据;

每一步的职责和任务清晰。那么为什么说颇为完整,因为不涉及到具体的图形的绘制和图形特效的处理,也即没有出现前文花大量笔墨阐述的shader着色器的相关运用,那么shader着色器到底如何使用,图形如何定义和绘制,我们在接下来的文章里接着分析。