OpenGL ES总结(一)OpenGL 初识

导读:OpenGL是在图形图像中,非常优秀的渲染库,文中Demo下载地址:https://github.com/hejunlin2013/OpenGL31,看下今天的Agenda:

  • OpenGL是什么?
  • OpenGL主要功能是什么?
  • OpenGL ES是什么?
  • Android中如何描述OpenGL ES版本
  • 映射坐标绘制对象
  • 坐标列表转化为逆时针绘制顺序
  • 小总结

OpenGL ES 3.1 Demo实践

OpenGL是什么?

OpenGL(全写Open Graphics Library)是指定义了一个跨编程语言、跨平台的编程接口规格的专业的图形程序接口。它用于三维图像(二维的亦可),是一个功能强大,调用方便的底层图形库。

OpenGL™ 是行业领域中最为广泛接纳的 2D/3D 图形 API,其自诞生至今已催生了各种计算机平台及设备上的数千优秀应用程序。OpenGL™ 是独立于视窗操作系统或其它操作系统的,亦是网络透明的。在包含CAD、内容创作、能源、娱乐、游戏开发、制造业、制药业及虚拟现实等行业领域中,OpenGL™ 帮助程序员实现在 PC、工作站、超级计算机等硬件设备上的高性能、极具冲击力的高视觉表现力图形处理软件的开发。

OpenGL主要功能是什么?

OpenGL是一个开放的三维图形软件包,它独立于窗口系统和操作系统,以它为基础开发的应用程序可以十分方便地在各种平台间移植;OpenGL可以与Visual C++紧密接口,便于实现机械手的有关计算和图形算法,可保证算法的正确性和可靠性;OpenGL使用简便,效率高。它具有七大功能:

  • 1、建模:OpenGL图形库除了提供基本的点、线、多边形的绘制函数外,还提供了复杂的三维物体(球、锥、多面体、茶壶等)以及复杂曲线和曲面绘制函数。
  • 2、变换:OpenGL图形库的变换包括基本变换和投影变换。基本变换有平移、旋转、缩放、镜像四种变换,投影变换有平行投影(又称正射投影)和透视投 影两种变换。其变换方法有利于减少算法的运行时间,提高三维图形的显示速度。
  • 3、颜色模式设置:OpenGL颜色模式有两种,即RGBA模式和颜色索引(Color Index)。
  • 4、光照和材质设置:OpenGL光有自发光(Emitted Light)、环境光(Ambient Light)、漫反射光(Diffuse Light)和高光(Specular Light)。材质是用光反射率来表示。场景(Scene)中物体最终反映到人眼的颜色是光的红绿蓝分量与材质红绿蓝分量的反射率相乘后形成的颜色。
  • 5、纹理映射(Texture Mapping)。利用OpenGL纹理映射功能可以十分逼真地表达物体表面细节。
  • 6、位图显示和图象增强图象功能除了基本的拷贝和像素读写外,还提供融合(Blending)、抗锯齿(反走样)(Antialiasing)和雾(fog)的特殊图象效果处理。以上三条可使被仿真物更具真实感,增强图形显示的效果。
  • 7、双缓存动画(Double Buffering)双缓存即前台缓存和后台缓存,简言之,后台缓存计算场景、生成画面,前台缓存显示后台缓存已画好的画面。

OpenGL ES是什么?

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

Android包括支持高性能2d和3d图形与开放图形库(OpenGL®),具体来说,OpenGL ES API。OpenGL是一个跨平台图形API,用于指定一个标准为3 d图形处理硬件的软件接口。OpenGL 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)和更高。

Android支持OpenGL通过其框架API和本地开发工具包(NDK)。

在Android框架有两个基本类,让你创建和操作图形与OpenGL ES API:GLSurfaceView GLSurfaceView.Renderer。

GLSurfaceView

  • 这是一个视图类,我们可以使用OpenGL绘制和操作对象API调用和SurfaceView是相似的函数。您可以使用这个类创建一个实例GLSurfaceView并add到你的Renderer(渲染器)。
  • public void setRenderer(GLSurfaceView.Renderer renderer)
  • 起到连接OpenGL ES与Android 的View层次结构之间的桥梁作用。
  • 使得Open GL ES库适应于Anndroid系统的Activity生命周期。
  • 使得选择合适的Frame buffer像素格式变得容易。
  • 创建和管理单独绘图线程以达到平滑动画效果。
  • 提供了方便使用的调试工具来跟踪OpenGL ES函数调用以帮助检查错误。

GLSurfaceView.Renderer

这个接口定义了在GLSurfaceView绘制图形时所需的方法。既然是接口,那么就必须有一个实现该接口的类。然后使用GLSurfaceView.setRenderer(这里接收那个具体实类)方法,把这个实现类set到GLSurfaceView上。

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

  • onSurfaceCreated():创建GLSurfaceView时回调。使用这个方法来执行操作,只需要发生一次,如设置OpenGL环境参数或初始化OpenGL图形对象。设置一些绘制时不常变化的参数,比如:背景色,是否打开 z-buffer等。
  • onDrawFrame():每绘制一帧的时回调。
  • onSurfaceChanged():GLSurfaceView几何变化时回调,包括GLSurfaceView大小的变化或设备的屏幕变换。

Android中如何描述OpenGL ES版本?

AndroidManifest.xml中加入: For OpenGL ES 2.0:

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

For OpenGL ES 3.0:

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

For OpenGL ES 3.1:

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

映射坐标绘制对象

OpenGL是假定一个正方形,统一系统坐标,默认情况下,它是将这些看起来在非正方形的屏幕上,看起来像正方形。

默认的OpenGL坐标系(左)映射到一个典型的Android设备屏幕(右)。

上面的图显示了(左边)一个OpenGL的统一坐标系统,和如何将这些坐标映射到(右边)一个典型的横向设备屏幕。为了解决这个问题,我们可以应用OpenGL正确的比例下通过投影模式和相机视图坐标转换你的图形对象。

为了应用投影和相机视图,我们创建一个投影矩阵和一个相机视图矩阵并将它们应用于OpenGL渲染管道中。投影矩阵重新计算你的图形的坐标,使他们正确地映射到Android设备的屏幕。相机视图矩阵创建一个转换,它将从一个特定的位置显示对象。

投影(Projection)和OpenGL ES 1.0相机视图( Camera View )

投影矩阵——创建一个投影矩阵使用设备屏幕以重新计算对象的几何坐标所以他们用正确的比例。下面的示例代码演示了如何修改onSurfaceChanged GLSurfaceView()方法。渲染器实现来创建一个基于屏幕的长宽比和投影矩阵应用于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
}

相机变换矩阵——一旦你使用投影矩阵调整坐标系统,我们还必须添加一个相机视图。下面的示例代码显示了如何修改onDrawFrame GLSurfaceView()方法。渲染器实现应用模型视图,并使用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,应用投影和相机视图首先要添加一个矩阵图形的顶点着色器(Shader)对象成员。添加了这个矩阵成员,我们可以生成和应用投影和相机观察矩阵对象。

顶点着色器添加矩阵——为视图创建一个变量投影矩阵,包括乘数着色器的位置。在下面的例子中顶点着色器代码,包括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";

访问着色矩阵之后,创建一个钩在你的顶点着色器应用投影和相机视图中,您可以访问该变量应用投影和相机观测矩阵。下面的代码演示如何修改onSurfaceCreated GLSurfaceView()方法。渲染器实现访问上面的顶点着色器中定义的矩阵变量。

public void onSurfaceCreated(GL10 unused, EGLConfig config) {
    ...
    muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, 
"uMVPMatrix");
    ...
}

创建投影和相机观察矩阵——生成投影矩阵和查看应用的图形对象。下面的示例代码显示了如何修改onSurfaceCreated()和onSurfaceChanged GLSurfaceView()方法。渲染器实现创建相机视图矩阵和投影矩阵基于设备的屏幕宽高比。

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);
}

应用投影和相机观察矩阵——应用投影和相机视图的转换,将矩阵的相乘,然后设置在顶点着色器中。下面的代码显示了如何修改onDrawFrame GLSurfaceView()方法。渲染器实现结合投影矩阵和相机视图中创建上面的代码,然后把它应用到由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,一个形状是一个表面由三个或更多的点在三维空间中定义的。一组三个或更多三维点(称为顶点在OpenGL)有正面和背面。你怎么知道哪面是正面和背面?答案是 winding,或者简单的说,你定义点的方向。

坐标列表转化为逆时针绘制顺序

在这个例子中,三角形的点是通过一定的顺序定义的,以致它们是通过逆时针方向绘制的。这些坐标定义的顺序就是环绕方向。默认情况下,在OpenGL中,我们正对的方向是逆时针画的方向。上图所示的三角形定义,我们看到就是正面,另一边是背面。

为什么我们要知道,我们面对的是不是正面?原因是:在处理OpenGL的常用特性时,有一个叫Face culling的环境因素,Face culling是OpenGL中一个可以参考的环境,它可以让你在渲染到pipeline的过程中忽略背面(不计算或绘制),节省时间,内存和处理周期。

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

如果我们尝试使用Face culling特性,但又不知道它的形状是正面和背面,我们的OpenGL图形看起来有点怪,或者有时根本不显示。所以,总是定义我们的OpenGL图形的坐标逆时针顺序。

以上小总结:

  • OpenGL 绘制的都是图形,包括形状和填充,基本形状是三角形。
  • 每个形状都有顶点,Vertix,顶点的序列就是一个图形。
  • 图形有正反面,如果我们看向一个图形,它的顶点序列是逆时针方向,那我们看到的就是正面。
  • Shader,着色器,用来描述如何绘制(渲染),GLSL 是 OpenGL 的编程语言,全称就叫 OpenGL - -Shader Language。OpenGL 渲染需要两种 shader,vertex 和 fragment。
  • Vertex shader,控制顶点的绘制,指定坐标、变换等。
  • Fragment shader,控制形状内区域渲染,纹理填充内容。

OpenGL ES 3.1 Demo实践

效果图:

MainActivity

MyGLSurfaceView

Renderer

Square

Triangle

第一时间获得博客更新提醒,以及更多android,源码分析,最新开源项目推荐,更多有价值的思考,欢迎关注我的微信公众号,扫一扫下方二维码或者长按识别二维码

原文发布于微信公众号 - 何俊林(DriodDeveloper)

原文发表时间:2017-03-13

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏向治洪

自定义Interpolator

nterpolator这个东西很难进行翻译,直译过来的话是补间器的意思,它的主要作用是可以控制动画的变化速率,比如去实现一种非线性运动的动画效果。那么什么叫做非...

2177
来自专栏图形学与OpenGL

机械版CG 实验2 直线生成算法的实现

理解基本图形元素光栅化的基本原理,掌握一种基本图形元素光栅化算法,利用OpenGL实现直线光栅化的DDA算法。

1962
来自专栏月色的自留地

Grapher--寂寞无名的神器

2097
来自专栏冰霜之地

高效的多维空间点索引算法 — Geohash 和 Google S2

每天我们晚上加班回家,可能都会用到滴滴或者共享单车。打开 app 会看到如下的界面:

6505
来自专栏HT

基于HTML5和WebGL的3D网络拓扑结构图

现在,3D模型已经用于各种不同的领域。在医疗行业使用它们制作器官的精确模型;电影行业将它们用于活动的人物、物体以及现实电影;视频游戏产业将它们作为计算机与视频游...

5095
来自专栏racaljk

A星寻路算法(A* Search Algorithm)

你是否在做一款游戏的时候想创造一些怪兽或者游戏主角,让它们移动到特定的位置,避开墙壁和障碍物呢?

4683
来自专栏生信宝典

R语言学习 - 散点图绘制

散点图 散点图在生物信息分析中是应用比较广的一个图,常见的差异基因火山图、功能富集分析泡泡图、相关性分析散点图、抖动图、PCA样品分类图(后续推出)等。凡是想展...

3607
来自专栏数据小魔方

图表中异常值的特殊截断处理

今天跟大家聊聊在图表制作中异常值的处理方式! 相信大家都遇到过这种情况 用一组数据作图 可是偏偏就遇到那么一两个特变态的异常值 不信自己感受一下 ? 其中有一...

3719
来自专栏菜鸟前端工程师

JavaScript学习笔记019-原生js运动框架0时间运动框架

1652
来自专栏Petrichor的专栏

图像处理: 如何将 像素值 控制在 值域[0, 255]

在做计算机视觉方向项目的时候,往往需要进行图像处理。但是在此过程中,常常会遇到 对 像素值 进行 变换计算 后,像素值 超出 值域区间 [0, 255] 的情况...

1534

扫码关注云+社区

领取腾讯云代金券