OpenGL与OpenGL ES

1、3D图像引擎简介

现今较为知名的3D图形引擎有OpenGL、DirectX

  • DirectX主要应用于Windows下游戏的开发,在此领域基本上一统天下。

  • OpenGL的应用领域较为广泛,适用于Unix、Mac OS、Linux以及Microsoft等几乎所有的操作系统,可以开发游戏、工业建模以及嵌入式设备。

2、OpenGL

OpenGL是Open Graphics Library的缩写,是个定义了一个跨编程语言、跨平台的编程接口的标准,与硬件无关,在多种不同的图形硬件系统上,完全通过软件的方式实现OpenGL的接口。OpenGL被当作客户端-服务器系统来实现的,应用程序是客户端,图形硬件厂商提供的OpenGL实现是服务器。

3、OpenGL ES

OpenGL ES(OpenGL for Embedded Systems) 是 OpenGL 的子集,针对手机、PDA 和游戏主机等嵌入式设备而设计。该规范也是由 Khronos Group 开发维护。

OpenGL ES 去除了四边形(GL_QUADS)、多边形(GL_POLYGONS) 等复杂图元,以及许多非绝对必要的特性,剩下最核心有用的部分。可以理解成是一个在移动平台上能够支持 OpenGL 最基本功能的精简规范。

3.1 OpenGL ES版本分类

Android上面的OpenGL ES一共有三个版本,1.0,2.0以及现在的3.x(3.1, 3.2)

⭐️ OpenGL ES 1.X:采用的是固定渲染管线。Android1.0和更高的版本支持这个API规范。

⭐️ OpenGL ES 2.X:可编程渲染管线,渲染能力大大提高。着色器是可编程的,灵活性高,程序员可发挥的空间大,编程比较难。Android 2.2(API 8)和更高的版本支持这个API规范。

⭐️ OpenGL ES 3.0 :是从 OpenGL 3.3规范衍生而来,向后兼容 OpenGL ES 2.0。Android 4.3(API 18)及更高的版本支持这个API规范。

⭐️ OpenGL ES3.1:基本上可以属于OpenGL 4.x的子集,向下兼容OpenGL ES3.0/2.0。Android 5.0(API 21)和更高的版本支持这个API规范。

⭐️ 使用OpenGL ES 1.0 / 1.1 API的图形编程与使用2.0及更高版本显着不同。 API的1.x版本具有更多的便利方法和固定的图形管道,而OpenGL ES 2.0和3.x API通过使用OpenGL shaders提供对管道更直接的控制。

⭐️ OpenGL ES 3.x API提供了比2.0 API更多的功能和更好的性能,并且还向后兼容2.0版本。 这意味着可以在编写面向OpenGL ES 2.0的应用程序时,有条件地包含OpenGL ES 3.x的图形功能(如果可用)。

一个问题:3D图形如何显示在2D平面?

4、OpenGL ES中基本概念

4.1、渲染管线

⭐️ 在OpenGL ES中,任何事物都在3D空间中,而屏幕和窗口却是2D像素数组,这导致OpenGL ES的大部分工作都是关于把3D坐标转变为适应你屏幕的2D像素。3D坐标转为2D坐标的处理过程是由OpenGL ES的图形渲染管线管理。管线渲染指的是一堆原始图形数据途经一个输送管道,期间经过各种变化处理最终出现在屏幕的过程。

⭐️ 图形渲染管线可以被划分为两个主要部分:第一部分把3D坐标转换为2D坐标,第二部分是把2D坐标转变为实际的有颜色的像素。

⭐️ *OpenGL 渲染管线流程为 :顶点数据 -> 顶点着色器 -> 图元装配 -> 几何着色器 -> 光栅化 -> 片段着色器 -> 逐片段处理 -> 帧缓冲

OpenGL与3D开发 - OpenGL与OpenGL ES

1. 顶点属性【Vertex data】: 我们以数组的形式传递3个3D坐标作为图形渲染管线的输入,用来表示一个三角形,这个数组叫做顶点数据(Vertex Data)

  • 顶点: 是一个3D坐标的数据集合

  • 顶点属性: 顶点数据用顶点属性表示,它可以包含任何我们想要的数据,但是为了简单,我们还是假定只由一个3D位置{x, y, z}和一些颜色值{r, b, g, r}组成。

2. 顶点着色器(Vertex Shader): 图形渲染管线的第一个部分是顶点着色器,它把一个单独的顶点作为输入。顶点着色器主要的目的是把3D坐标转为另一种3D坐标(屏幕2D坐标),同时顶点着色器允许我们对顶点属性进行一些基本处理。关键的操作就是顶点坐标变换及光照处理,每个顶点是分别单独处理的。这个阶段所接受的数据是每个顶点的属性特征,输出的则是变换后的顶点数据。

3. 图元装配(Primitive Assembly): 将顶点着色器输出的所有顶点作为输入,并所有的点装配成指定图元的形状。这里的图元就是指点、线、三角。OpenGL ES中最基础且唯一的多边形就是三角形,所有更复杂的图形都是由三角形组成的。复杂的图形都可以拆分成多个三角形。

  • GL_POINTS:以点的形式进行绘制,通常用在绘制粒子效果的场景。

  • GL_LINES:以线的形式进行绘制,通常用于绘制直线的场景。

  • GL_TRIANGLE_STRIP:以三角形的形式进行绘制,所有二维图像的渲染都会使用这种方式。

4. 几何着色器Geometry Shader): 图元装配阶段的输出会传递给几何着色器。几何着色器把图元形式的一系列顶点的集合作为输入,它可以通过产生新顶点构造出新的(或是其它的)图元来生成其他形状。

5. 光栅化阶段(Rasterization Stage) : 几何着色器的输出会被传入光栅化阶段,这里它会把图元映射为最终屏幕上相应的像素,生成供片段着色器(Fragment Shader)使用的片段(Fragment)。在片段着色器运行之前会执行裁切(Clipping)。裁切会丢弃超出你的视图以外的所有像素,用来提升执行效率。

6. 片段着色器: 主要目的是计算一个像素的最终颜色,这也是所有OpenGL高级效果产生的地方。通常,片段着色器包含3D场景的数据(比如光照、阴影、光的颜色等等),这些数据可以被用来计算最终像素的颜色。

7. 逐片段处理: 进行剪切、Alpha 测试、 模版测试、深度测试、混合等处理,这些操作将会最后影响其在帧缓冲区的颜色值。

8. 帧缓冲操作: 此阶段主要执行帧缓冲的写入操作,也是渲染管线的最后一步,负责将最终的像素点写到帧缓冲区。

5、OpenGL 坐标系理解

5.1、2D笛卡尔坐标

在二维绘图中,最为常用的坐标系统是笛卡尔坐标系统. 笛卡尔坐标由一个X和一个Y坐标构成.X表示水平方向位置,Y表示垂直方向的位置

5.2、3D笛卡尔坐标系

将2D笛卡尔坐标系系统扩展到三维空间中.从水平和垂直方向,增加了深度分量.

增加的深度分量用Z来表示,Z轴同时垂直于X,Y轴.它代表的是一条从屏幕中心朝向读者的直线

5.3、左手坐标系和右手坐标系

左手坐标系: 伸开左手,大拇指指向X轴正方向,食指指向Y轴正方向,其他三个手指指向Z轴正方向。

右手坐标系: 伸开右手,大拇指指向X轴正方向,食指指向Y轴正方向,其他三个手指指向Z轴正方向。

OpenGL中使用右手坐标系,Direct3D使用的是左手坐标系。

OpenGL ES采用的是右手坐标,选取屏幕中心为原点,从原点到屏幕边缘默认长度为1,也就是说默认情况下,从原点到(1,0,0)的距离和到(0,1,0)的距离在屏幕上展示的并不相同。即向右为X正轴方向,向左为X负轴方向,向上为Y轴正轴方向,向下为Y轴负轴方向,屏幕面垂直向上为Z轴正轴方向,垂直向下为Z轴负轴方向。

OpenGL与3D开发 - OpenGL与OpenGL ES

5.4、左手旋转规则、右手旋转规则

左右手旋转规则用于判断当前坐标系中物体旋转时正方向的判定。在右手坐标系中,确定旋转轴后,右手握成拳头,拇指指向旋转轴的正方向,其余手指的弯曲方向即为旋转的正方向,跟手指弯曲方向一致的旋转记为正向,相反则为负向。左手坐标注系中判断旋转方向的正负使用左手,其他规则一样。两者的示意图:

OpenGL与3D开发 - OpenGL与OpenGL ES

那么OpenGL 是如何将笛卡尔坐标系映射成可以在屏幕上显示的二维坐标的?

⭐️ OpenGL 要求输入的顶点坐标都是标准化设备坐标,即每个顶点的 x、y、z 都在 -1 到 1 之间,由标准化设备坐标转换为屏幕坐标的过程中会经历变换多个坐标系统,在这些特定的坐标系中,一些操作和计算可以更加方便。

5.5、对我们来说比较重要的总共有5个不同的坐标系统

  • 局部空间(Local Space,或者称为物体空间(Object Space))

  • 世界空间(World Space)

  • 观察空间(View Space,或者称为视觉空间(Eye Space))

  • 裁剪空间(Clip Space)

  • 屏幕空间(Screen Space)

物体顶点的起始坐标再局部空间(Local Space),这里称它为局部坐标(Local Coordinate),它在之后会变成世界坐标(world Coordinate),观测坐标(View Coordinate),裁剪坐标(Clip Coordinate),并最后以屏幕坐标(Screen Corrdinate)的形式结束

OpenGL与3D开发 - OpenGL与OpenGL ES

???? 局部坐标: 也称为对象坐标,是指物体所在的坐标系空间,即对象最开始的地方,也就是在被应用任何变换之前的初始位置和方向所在的坐标系,被称为当前绘图坐标系,该坐标不是固定的。

​ 例如: 我手中有一支钢笔,假设它的对象坐标范围-200~200,中心点是(0,0,0),但这只是对这支钢笔而言

????世界坐标系空间: 如果将所有的物体导入到程序当中,它们有可能会全挤在世界的原点(0, 0, 0)上。理想状态下是为每一个物体定义一个位置,从而能在更大的世界当中放置它们。世界空间中的坐标系正如其名:是指顶点相对于世界的坐标。物体的坐标将会从局部变换到世界空间;该变换一般是由模型矩阵(Model Matrix)实现。模型矩阵是一种变换矩阵,它能通过对物体进行位移、缩放、旋转来将它置于它本应该在的位置或朝向。例如:当把这只钢笔与一本书以及其他物品同时放在桌面上时,钢笔在桌面上的位置要通过平移、旋转等操作最后确定

????观察坐标系空间: 观察坐标系空间经常被称之OpenGL ES的摄像机视角,所以有时也称为摄像机坐标系空间(Camera Space)或视觉坐标系空间(Eye Space)。观察坐标系空间是将世界空间坐标转化为用户视野前方的坐标而产生的结果。观察坐标系空间通常是由一系列的位移和旋转的组合来完成,平移/旋转场景从而使得特定的对象被变换到摄像机的前方。这些组合在一起的变换通常存储在一个观察矩阵(View Matrix)里,它被用来将世界坐标变换到观察空间。例如:我们架设了一台摄像机,需要对桌面上的书和钢笔进行拍照,为了能够达到最好的拍摄角度和效果,这时需要再次对它们进行平移、旋转等一系列操作

????剪裁坐标系: 坐标到达观察空间之后,需要将其投影到裁剪坐标。裁剪坐标会被处理至-1.0到1.0的范围内,并判断哪些顶点将会出现在屏幕上。

将特定范围内的坐标转化到标准化设备坐标系的过程(而且它很容易被映射到2D观察空间坐标)被称之为投影,因为使用 投影矩阵 能将3D坐标投影到很容易映射到2D的标准化设备坐标系中。

裁剪空间的目标是能够方便地对渲染图元进行裁剪:完全位于这块空间内部的图元将会被保留,完全位于这块空间外部的图元将会被剔除,而与这块空间边界相交的图元就会被裁剪。那么,这块空间是如何决定的呢?答案是由 视锥体 (view frustum) 来决定。

OpenGL ES中有两种投影方式:正交投影和透视投影。

⭐️ 正交投影(Orthographic projection), 需要指定一个 正方形/长方形 的视景体,在视锥体以外的任何物体都不会被绘制,所以实际大小相同的物体在屏幕上都具有相同的大小。物体不会随距离观测点的位置而大小发生变化。正交投影比较适合平面图形/2D图形渲染时使用

⭐️ 透视投影(perspective projection),对于肉眼直观的感受是,近大远小的,这种视觉效果称之为透视。透视投影要模仿肉眼的这种效果,是使用透视投影矩阵来完成的;在3D开发中更为常见,同样需要指定视景体的,而这个视景体并不是类似于正方体,看起来像平截体。透视投影一般会使用于3D图像渲染,因为它会更加逼真,距离观测点越远,物体越小,距离观测点越近,物体越大。

⭐️ 屏幕坐标系:使用一个叫做视口变换(Viewport Transform)的过程,将剪裁坐标变成屏幕坐标。视口变换将位于-1.0到1.0范围的坐标变换到由glViewport()所定义的坐标范围内。最后变换出来的坐标将会送到光栅器,将其转化为片段。

相关文章: