OpenGL ES 2.0与3.0的关键差异
1. 设备支持
OpenGL ES 1.x主要为初代iPhone和Android设备设计,而OpenGL ES 2.0则扩展至Android 2.2及更高版本,覆盖iPad、iPhone 3GS及以上版本,以及iPod Touch 3代以上。自Android 4.3起,OpenGL ES 3.0得到支持,适用于iPhone 5s、iPad Air及后续型号。
2. 兼容性与版本声明
OpenGL ES 3.0兼容2.0,意味着2.0程序可在3.0环境中无缝运行。在3.0中,顶点和片段着色器的编译需明确版本声明,这一要求在2.0中并非强制,通常默认为#version 100 es。
3. 着色器与精度
在3.0中,顶点和片段着色器的精度声明更为明确。引入了'in'、'out'、'inout'关键字,替代了attribute和varying。移除gl_FragColor和gl_FragData,允许直接在片段着色器中声明输出字段,提高了编程的灵活性和效率。
4. 缓冲区对象与VAO(顶点数组对象)
VAO在OpenGL ES 3.0中引入,简化了顶点数据的管理。在绘制前需绑定VAO,否则可能导致错误。不再支持直接传入数组,顶点数据需先存入顶点缓冲区对象(VBO)。
5. PBO(像素缓冲区对象)的支持
PBO在OpenGL 3.0中引入,用于高效地在CPU和GPU之间传输数据。这种方法比glReadPixels更高效,特别是在双PBO交换读取时。
概览与资源
以上是OpenGL ES 2.0与3.0的主要差异。为了更深入了解,建议查阅猿说编程发布的相关文章。在选择程序设计时,需考虑设备是否支持OpenGL ES 2.0或1.1,或者两者均支持。相较于OpenGL ES 1.0,OpenGL ES 2.0功能更强大,性能更佳,允许更清晰的顶点和片段计算。OpenGL ES 1.1提供了一个标准的固定渲染管线,为3D程序提供了参考。在新iOS设备上,使用OpenGL ES 2.0能发挥强大的图形渲染能力。关于坐标变换和坐标系的概念,在OpenGL ES中至关重要。物体坐标需要经过多个转换步骤,最终变为屏幕坐标。这个过程涉及到几个关键的坐标系,包括局部空间、世界空间、观察空间、裁剪空间和屏幕空间。为了将坐标从一个坐标系变换到另一个坐标系,需要使用模型、观察和投影等变换矩阵。了解这些概念和变换过程对于OpenGL ES的开发至关重要。局部坐标系空间是指物体在其原始位置或初始状态下的坐标系。例如,在建模软件中创建的立方体,它的原点可能位于(0, 0, 0),即使它在程序中移动到了完全不同的位置。所有创建的模型都以(0, 0, 0)作为初始位置,但最终会被放置在世界空间的不同位置。模型的每个顶点都是在局部坐标系中定义的,相对于物体而言都是局部的。
当将多个物体导入程序时,它们可能会聚集在世界坐标系的原点(0, 0, 0),这并不是我们想要的结果。理想情况下,应该为每个物体定义一个位置,以便在更大的世界中放置它们。世界坐标系中的点表示的是顶点相对于整个世界的坐标。物体的坐标会从局部坐标系变换到世界坐标系,这一过程通常由模型矩阵来完成。模型矩阵是一种变换矩阵,可以通过位移、缩放和旋转操作将物体放置在其应有的位置或方向上。
观察坐标系空间有时被称为OpenGL ES的摄像机视角,也称为摄像机坐标系或视觉坐标系。它是将世界坐标系中的坐标转化为用户视野前方的坐标的结果。观察坐标系空间是从摄像机的视角观察到的空间,通常通过一系列的位移和旋转组合来完成,以将特定场景变换到摄像机前方。这些组合变换通常存储在一个观察矩阵里,用于将世界坐标变换为观察空间坐标。
在OpenGL ES中,顶点着色器运行的最后阶段,所有坐标都需要落在一个特定范围内,任何超出这个范围的点都会被裁剪掉。被裁剪的坐标将被忽略,剩下的坐标将变为屏幕上可见的片段。这就是裁剪坐标系名字的由来。
由于将所有可见的坐标指定在-1.0到1.0的范围内并不直观,因此会定义自己的坐标集并将其变换回标准化设备坐标系,就像OpenGL ES所期望的那样。为了将顶点坐标从观察坐标系空间变换到裁剪坐标系空间,需要定义一个投影矩阵,它指定了一个坐标范围,例如在每个维度上的-1000到1000。投影矩阵会将在这个指定范围内的坐标变换为标准化设备坐标的范围(-1.0, 1.0)。所有在这个范围外的坐标不会被映射到-1.0到1.0之间,因此会被裁剪掉。
如果只是一个图元(例如三角形)的一部分超出了裁剪体积,OpenGL ES会重新构建这个图元为一个或多个三角形以适应裁剪范围。由投影矩阵创建的观察箱被称为平截头体,每个出现在平截头体范围内的坐标最终都会出现在用户的屏幕上。将特定范围内的坐标转化为标准化设备坐标系的过程被称为投影,因为使用投影矩阵能将3D坐标投影到易于映射到2D的标准化设备坐标系中。
一旦所有顶点被变换到裁剪空间,最终的操作——透视除法将会执行。在这个过程中,位置向量的x、y、z分量分别除以向量的齐次w分量。透视除法是将4D裁剪空间坐标变换为3D标准化设备坐标的过程。这一阶段会在每一个顶点着色器运行的最后被自动执行。之后,最终的坐标将被映射到屏幕空间中(使用glViewport中的设置),并变换成片段。
投影矩阵可以为两种不同的形式:正射投影矩阵和透视投影矩阵,每种形式都定义了不同的平截头体。正射投影矩阵定义了一个类似立方体的平截头箱,定义了一个裁剪空间,在此空间之外的顶点都会被裁剪掉。创建一个正射投影矩阵需要指定可见平截头体的宽、高和长度。在使用正射投影矩阵变换至裁剪空间后处于这个平截头体内的所有坐标将不会被裁剪掉。其平截头体像一个容器一样直接将内部的坐标映射为标准化设备坐标。如果想要创建一个正射投影矩阵,可以使用android.opengl.Matrix下的内置函数orthoM()。其映射原理是将剪裁空间中的所有x、y和z分量线性映射到NDC(归一化设备坐标系)。只需要将矩形体积缩放到立方体并将观察坐标系的原点移动到标准化设备坐标原点即可得到最终结果。正射投影矩阵直接将坐标映射到2D平面即屏幕上但实际上会产生不真实的结果因为没有考虑透视效果因此需要透视投影矩阵来解决这个问题。透视投影要模仿肉眼近大远小的视觉效果使用透视投影矩阵来完成这个模仿效果这个透视投影矩阵还将给定的平截头体范围映射到裁剪空间并且修改了每个顶点坐标的w值从而使得离观察者越远的顶点坐标w分量越大。在android.opengl.Matrix中可以这样创建一个透视投影矩阵使用perspectiveM()函数创建透视投影矩阵其参数定义了可视空间的大平截头体任何在这个平截头体以外的东西最后都不会出现在裁剪空间体积内并且将会被裁剪掉透视投影映射到标准化设备坐标的原理是截断的金字塔形状的平截头体中的三维点被映射成立方体中的点这个过程涉及到复杂的数学计算包括对坐标的截断和转换以确保最终呈现的图像是正确的这个过程需要深入理解计算机图形学和计算机视觉的原理才能完全掌握。三维空间中的图形变换与渲染
在计算机图形学中,每一个步骤都构建了一个变换的矩阵系统,包括模型矩阵、观察矩阵和投影矩阵。这些矩阵的运算,将顶点坐标从局部坐标系转换到裁剪坐标系,最终在屏幕上呈现三维物体。
矩阵系统的建立与作用
创建一个模型矩阵。这个矩阵包含了位移、缩放与旋转等操作,它作用于所有物体的顶点,将其变换到全局的世界空间。这个过程中,一个顶点的坐标会通过与模型矩阵相乘,被转换到世界坐标系中,呈现出如地面平面的效果。
接着,需要创建一个观察矩阵。这个矩阵的作用是以相反于摄像机移动的方向移动整个场景,给予我们一种场景往后移动的感觉。在OpenGL ES的右手坐标系中,我们需要沿着z轴的负方向平移来实现这一效果。
然后是投影矩阵的设定。在场景中使用透视投影,这样就能够声明一个相应的投影矩阵。
着色器中的矩阵运算
现在,已经创建了这些变换矩阵,接下来要将它们传入着色器中。在顶点着色器中,需要声明三个uniform变换矩阵,然后将它们与顶点坐标相乘。这个过程通常在每次的渲染迭代中进行,因为变换矩阵可能会经常变动。
实现三维效果与深度测试
在操作过顶点坐标后,它们已经使用了模型、观察和投影矩阵进行了变换。目前虽然是在三维空间中操作,但依然是对二维平面进行着处理。接下来将讨论如何实现三维效果,比如渲染一个立方体。需要36个顶点来构成一个立方体,每个面由两个三角形组成,每个三角形又有三个顶点。
OpenGL ES在渲染过程中会进行深度测试。它通过Z缓冲(深度缓冲)来存储深度信息,比较片段的深度值与z缓冲中的值,决定是否覆盖像素。如果想要启用深度测试,需要调用GLES30.glEnable()函数并指定GLES30.GL_DEPTH_TEST。在每次渲染迭代之前要清除深度缓冲,可以通过glClear()函数中指定DEPTH_BUFFER_BIT位来实现。
多物体渲染
当想要在屏幕上显示多个物体时,比如4个立方体,只需要改变每个对象的模型矩阵来将立方体变换到世界坐标系中。为每个立方体定义一个位移向量来指定它在世界空间的位置,并在渲染循环中传入不同的模型矩阵到顶点着色器中。这样就可以在游戏循环中用不同的模型矩阵渲染出多个物体。
效果呈现与问题解决
经过上述步骤的操作后,顶点的位置和方向都得到了正确的变换。但在渲染过程中可能会出现一些被遮挡的面错误地显示在前面的问题。这是由于OpenGL ES是以三角形为单位来绘制物体的,有时前面的三角形会覆盖本应显示在后面但位置更近的三角形。为解决这一问题,要确保深度测试功能正确开启并运行,确保渲染出的图像深度层次分明。