在OpenGL ES开发中,有些概念会经常用到,在这里进行一个总结。

什么是OpenGL ES

OpenGL(Open Graphics Library)定义了一个跨编程语言、跨平台编程的专业图形程序接口。可用于二维或三维图像的处理和渲染,它是一个功能强大、调用方便的底层图形库。对于嵌入式设备,其提供了OpenGL ES(OpenGL for Embeddled Systems)版本,该版本是针对手机、Pad等嵌入式设备而设计的,是OpenGL的一个子集。

OpenGL 渲染流程

纹理-opengl2.PNG

主要流程可概括为:

1、创建定点数组

2、写顶点着色器和片元着色器

3、gl初始化相关操作

4、将java声明的顶点数组 颜色数组 通过类似于jni接口传递给glsl语言的变量

GLSL(OpenGL Shading Language)着色器语言

开发人员利用这种语言编写程序运行在GPU(Graphic Processor Unit,图形图像处理单元,可以理解为是一种高并发的运算器)上以进行图像的处理和渲染。GLSL着色器代码分为两个部分,即Vertex Shader(顶点着色器)与Fragment Shade(片元着色器)两部分,分别完成各自在OpenGL渲染管线中的功能。

OpenGL 坐标系

OpenGL中有6种坐标系:

-- World Coordinates(世界坐标系)

-- Object Coordinates(对象坐标系、模型坐标系、局部坐标系或当前绘图坐标系)

-- Eye Coordinates(眼坐标系或照相机坐标系)

-- Clip Coordinates(裁剪坐标系)

-- Normalized Device Coordinates (NDC) (归一化设备坐标系)

-- Window Coordinates (Screen Coordinates)(屏幕坐标)

世界坐标系-三维笛卡尔坐标系.PNG

如上图所示是OpenGL里的世界坐标系,世界坐标系始终是固定不变的。OpenGL使用右手坐标,这里有一个形象的方法:使用右手定则

X 是你的拇指

Y 是你的食指

Z 是你的中指

如果你把你的拇指指向右边,食指指向天空,那么中指将指向你的背后。观察方向是Z轴负半轴的方向。

世界坐标系又称全局坐标系或宇宙坐标系。

当前绘图坐标系:是绘制物体时的坐标系。程序刚初始化时,世界坐标系和当前绘图坐标系是重合的。对当前绘图坐标系进行平移、伸缩、旋转变换之后,世界坐标系和当前绘图坐标系不再重合。

透视投影

透视投影与正交投影.PNG

左图是透视投影,右图是正交投影。

透视投影:视景体--平截体、近大远小、适合3D图像渲染

正交投影:正方形/长方形、不存在近大远小、适合平面图形/2D图形渲染

相机-视平面-物体.jpg

视点、视平面关系如上图所示。

Android使用OpenGL ES绘制3D图像或者加载3D模型时,为了达到立体效果往往需要设置视见转换矩阵和投影转换矩阵。

Matrix.setLookAtM
/**
* Defines a viewing transformation in terms of an eye point, a center of
* view, and an up vector.
*
* @param rm returns the result
* @param rmOffset index into rm where the result matrix starts
* @param eyeX eye point X
* @param eyeY eye point Y
* @param eyeZ eye point Z
* @param centerX center of view X
* @param centerY center of view Y
* @param centerZ center of view Z
* @param upX up vector X
* @param upY up vector Y
* @param upZ up vector Z
*/
public static void setLookAtM(float[] rm,
int rmOffset,
float eyeX, float eyeY, float eyeZ,
float centerX, float centerY, float centerZ,
float upX, float upY,float upZ)

eyeX, eyeY, eyeZ是摄像机的位置,及观察者眼睛的位置。centerX, centerY, centerZ为目标物的中心坐标,如果都为0,则设置到原点。upX、upY、upZ为摄像机顶部的方向,相机旋转up方向就会改变。

摄像机位置及目标物位置坐标,通常要结合Matrix.frustumM()的near、far参数才能呈现具体效果。

摄像机up方向:

摄像机up方向.png

例1:设置up为y轴正方向,upx = 0,upy = 1,upz = 0。这时相机正对着目标图像:

正方向成像图.png

例2:设置up方向为x轴正方向,upx = 1,upy = 0,upz = 0。则成像如下:

x轴正向成像png.png

Matrix.frustumM
/**
* Defines a projection matrix in terms of six clip planes.
*
* @param m the float array that holds the output perspective matrix
* @param offset the offset into float array m where the perspective
* matrix data is written
* @param left
* @param right
* @param bottom
* @param top
* @param near
* @param far
*/
public static void frustumM(float[] m, int offset,
float left, float right, float bottom, float top,
float near, float far)

近截面-远截面示意图.jpg

设视点E位于原点,视平面P垂直于Z轴,且四边分别平行于x轴和y轴,如上图所示,将该模型称为透视投影的标准模型,其中视椎体的近截面离视点的距离为n,远截面离视点的距离为f,且一般取近截面为视平面。

参考前面的相机-视平面-物体位置关系图

float left, //near面的left
float right, //near面的right
float bottom, //near面的bottom
float top, //near面的top
float near, //near面距离
float far //far面距离
left,right和bottom,top,这4个参数会影响图像左右和上下缩放比。
float ratio = (float) width/height;
//设置透视投影
Matrix.frustumM(mProjectMatrix,0,-ratio,ratio,-1,1,3,20);

一般计算ratio=width/height,然后left、right分别做如上设置,然后bottome、top分别取-1、1。near和far分别代表近截面距离和远截面距离。结合setLookAtM,摄像机位置取值应在near、far之间才能看到图像。

整个矩阵变换流程如下

矩阵变换流程.png

局部坐标是对象相对于原点的坐标,也是物体的起始坐标。

下一步将局部坐标转化为世界空间坐标,世界空间坐标是一个处于更大空间范围内的。这些坐标相对于世界的全局原点,它们会和其他物体一起相对于世界原点进行摆放。

接下来将世界坐标转化为观测坐标,使得每个坐标都是从摄像机或者说观察者角度进行观察的。

坐标到达观测空间后,我们需要将其投影到裁剪坐标。裁剪坐标会被处理到−1.0到1.0范围内,并判断哪些点将会出现在屏幕上。

最后将裁剪坐标变换为屏幕坐标,使用一视口变换(Viewport Transform)。视口变换将位于−1.0到1.0范围的坐标变换到由glViewport函数所定义的坐标范围内。最后变换出来的坐标将会送到光栅器,将其转化为片段。

基本图元单位是三角形

三角图元绘制方式

grDrawArrays与glDrawElements区别:

区别在于:glDrawArrays 是直接绘制真实的顶点数据,而 glDrawElements 是按照指定的索引顺序取出真实数据再绘制。

于是对于顶点存在共享的场景时,使用 glDrawElements 对于重复的顶点数据只需要传输一份数据,绘制时通过索引反复的获取其值,最终降低内存占用和内存带宽需求。

三角形绘制方式.PNG

GL_TRIANGLES:通过顶点数组可以组成三角形的数目为数组长度/3。

GL_TRIANGLE_STRIP:每个小组的三个临近的顶点组成一个三角形,通过顶点数组可以组成三角形的数目为数组长度-2。

纹理坐标

2D纹理坐标系

纹理坐标系.png

2D纹理坐标在x和y轴(也叫u,v)上,范围为0.0到1.0之间。

OpenGL 坐标系

OpenGL坐标系(XY平面).png

而OpenGL坐标系中x坐标、y坐标的取值范围都是(-1,1),所以要在范围为(0,1)的纹理坐标系中找到对应的纹理坐标点。

纹理坐标在纹理图像中指定与要为其指定顶点的点相对应的点。纹理映射时只需要为物体的顶点指定纹理坐标即可,其余部分由片元着色器插值完成。