即使是制作2d游戏,在移动设备上也往往使用opengl es绘图接口,来达到较高的绘制效率。这里记录一下我学习opengl es 2d绘图过程中逐渐明白的一些原理与技巧。

opengl 3d贴图的基本流程是:

a.使用3d坐标指定一些描述物体空间位置的顶点(例如一个立方体,或者平面上的一个三角形,指定它们的顶点)

b.给每一个位置坐标指定一个纹理坐标,表示纹理图上的哪个点对应这个位置坐标

c.位置坐标和纹理坐标都提交后,opengl根据这些信息,使用插值、缩放等方式,将纹理图贴到物体上

如果是2d游戏贴图,上述流程不变,只是3d位置坐标变为2d位置坐标,并且2d位置坐标描述的平面图像往往是两个三角形拼成的正方形。这个正方形的四个顶点,再对应到一张矩形的2d游戏素材图片的四个角上。

基本的流程清楚了,剩下的就是一些细节,以及一些2d图形操作技巧在opengl上的对应实现方法。目前我想到的有以下几点

1、坐标系转换 2、贴图问题 3、颜色表 4、缓冲区操作

1、坐标系转换

这个坐标系转换指的是如何从opengl坐标系转换到2d游戏常用的左上角为原点的坐标系
opengl从提交位置顶点到在窗口上渲染出像素,使用的坐标系有:物体坐标、视点坐标、裁剪坐标、正规化设备坐标、窗口坐标
  
  a.提交顶点时,使用的是物体坐标。
  b.使用glTranslate\glRotate等函数,可以对物体进行平移和旋转,从物体坐标转换为视点坐标。(2d游戏不涉及旋转的部分,常常直接给物体设置世界坐标,可以说跳过了这一步)。
  c.使用glOrtho\glFrustum等投影变换函数时,从坐标系变换上来说,先根据这两个函数规定的剪切区域及透视方法,进行了剪切透视变换,将3d世界变换到一个矩形管道观察体内。然后再进行正规化,使坐标在3个轴内的范围是(-1,1)
  d.使用glViewPort函数进行视口变换。这步变换中,上一步的正规化坐标(Xn、Yn、Zn),其中Xn、Yn根据glViewPort的参数,可以得到一个相应的屏幕坐标(Xw、Yw)(这个屏幕坐标,opengl规定原点在左下角,向上向右为正方向),Zn坐标则用来进行深度检测相关操作。
  详细来看一下glViewPort函数
void glViewport( GLint   x,
  GLint   y,
  GLsizei   width,
  GLsizei   height);

这个函数的数学表达式为

Xw = (Xn + 1) * width/2 + x

Yw = (Yn + 1) * height 2 + y

  从这个表达上可以看出,如果x、y取为0,width、height取为窗口宽高,规范化设备坐标(-1,-1)会被转换到(0,0)点,即窗口左下角。规范化坐标(1,1)会被转换到(width,height),即窗口右上角(注意原点为左下角,y向上为正)。换句话说,这样的设置,就是规范化矩形被平行的映射到窗口上去了。
  这里还有一个细节,就是规范化坐标和我们提交顶点时使用的坐标是什么关系。如何保证我们惯用的2d绘图坐标(原点在左上角),在使用opengl绘图接口时保持正常?
  那就需要详细看一下投影变换函数glOrtho
void glOrtho(GLdouble  left, GLdouble  right, GLdouble  bottom, GLdouble  top, GLdouble  nearVal, GLdouble  farVal);
  我们只要把这个函数的参数bottom设为窗口高度height,参数top设为0,即可正常使用惯用的2d坐标系了(原点在左上角)。从bottom和top的字面意义上来讲,要想使绘图坐标的y轴向下为正,确实应该这样设置(反之,设置bottom=0,top=height,就是opengl窗口坐标那样的y轴向上坐标系了)。从原理上讲,这个函数只是设置了一个坐标变换矩形,这个变换矩形的各个系数是根据我们调用glOrtho函数时设置的参数算出的。感兴趣的同学可以去看看opengl关于这个函数的官方文档,自己计算一下。
http://www.opengl.org/sdk/docs/man/xhtml/glOrtho.xml
关于坐标变换,opengl官网网站的一个faq网页解释的比较清楚
http://www.opengl.org/archives/resources/faq/technical/transformations.htm

2、纹理贴图细节

a.图像出现白边或者图像移动时产生闪烁

  如果使用缩放操作的话,一定要注意纹理环绕的设置。因为缩放操作导致屏幕上的像素点和纹理图片不是一一对应,就需要opengl来进行过滤采样。在纹理过滤不是临近点过滤时,对纹理边缘的过滤就可能包含纹理图像外的点。纹理环绕决定了图像外部点如何取值,像GL_CLAMP就会采用一种可设置的固定边界颜色。GL_CLAMP_TO_EDGE则忽略图像外部点。如果采用CL_CLAMP,在拼接纹理时,容易产生黑边。详细的解释可以见这篇文章http://www.linuxgraphics.cn/opengl/texture_fix_seam.html
  但因为2d游戏纹理坐标经常和像素一一对应,如果不进行放大和缩放的话,就不会出现这种现象。
  另外一种贴图时产生缝隙的原因,是opengl习惯使用宽高是2的幂的纹理图片,如果引擎对不符合要求的图片进行了自动补齐的话,补足的像素如果没有正确初始化,也会在放大缩小的边界线性过滤时产生缝隙,而且这时是与纹理环绕模式无关的。

我还碰到过图像闪烁的问题。那是在移动一副图片并对图片进行缩放时发生的。我猜测原因是图片位置发生变化后,因为位置变化量和缩放倍数不一致(例如放大两倍,但是一个像素一个像素的移动图片),缩放过程中采样点也相应变化。图像上某些像素点一会采样到纹理图上的亮点,一会采样到暗点,导致闪烁。

b.纹理压缩
  同样规模的2d游戏,使用的图片量要远大于3d游戏(想象一个滚动的球体,2d的话需要球体滚动过程中每一帧的图片,3d的话给一张球体整体纹理图就好了)。一个效果出众的移动设备游戏,内存往往容易拙荆见肘。这时可以采用低色深图片,例如从RGBA8888转为RGBA4444,图片内存使用量轻松减了一半,效果上其实看不太出来区别。
  如果想进一步榨取内存,使用opengl的硬件纹理压缩是个好方法。这样不仅可以减低内存使用,还可以加快渲染速度。如果是opengl完全版,只要提交纹理时,glTexImage2D的第三个参数internalformat使用GL_COMPRESSED_RGBA即可,opengl会负责在载入时压缩纹理。这样可以立刻看到压缩的效果(在我的一个已使用RGBA4444图片的项目中,100m的内存消耗,使用纹理压缩后变为40m)。可惜的是,opengl es不支持载入时压缩。关于预压缩为PVR等纹理格式,Apple网站上有详细介绍。

3.颜色表

  2d游戏中经常使用索引色图片,运行时动态改变调色版,来达到一些色彩变幻的效果。在opengl里,这些效果应该如何实现?
a.glColor*方法
glColor实际设置的是顶点的颜色,而顶点颜色决定几何图形颜色。一般采取的opengl纹理设置,是纹理颜色会与几何图形颜色相调制(即相乘)。用这种方法,可以达到动态减弱纹理中某个颜色通道(R\G\B\A)的效果。
b.颜色映射
颜色映射,可以将某个颜色映射为另外一种颜色。用于颜色缓冲区和外部图像数据转移时使用,即在glDrawPixels/glReadPixels/glTexImage等API调用时发生。可以采用表格的方式,也可以采用color*scale+bias的计算公式。但是这种方式在进行映射时似乎只能是通道独立的,,并不能将R\G\B结合起来映射
c.颜色矩阵和颜色表
属于图像子集(opengl es不支持)。用于图像处理管线的各个过程中。颜色矩阵(glMatrixMode(GL_COLOR))即是RGBA色彩空间的矩阵运算,颜色表(glColorTable)类似上面的颜色映射
d.索引色纹理图
Paletted textures,属于一个扩展,这个应该就是指让opengl在非索引色模式下支持索引色纹理图。新硬件一般已经不支持。可以通过shaders达到同样的功能。

4.缓冲区操作

未完待续

使用opengl es编写2d游戏的一些说明和技巧相关推荐

  1. 《OpenGL ES 3.x游戏开发(上卷)》一1.5 Android应用程序运行的机制

    本节书摘来异步社区<OpenGL ES 3.x游戏开发(上卷)>一书中的第1章,第1.5节,作者: 吴亚峰 责编: 张涛,更多章节内容可以访问云栖社区"异步社区"公众号 ...

  2. 《OpenGL ES 2.0游戏开发(上卷):基础技术和典型案例》一6.6 本章小结

    本节书摘来异步社区<OpenGL ES 2.0游戏开发(上卷):基础技术和典型案例>一书中的第6章,第6.6节,作者: 吴亚峰 责编: 张涛,更多章节内容可以访问云栖社区"异步社 ...

  3. 《OpenGL ES 3.x游戏开发(下卷)》一1.2 顶点数组对象

    本节书摘来异步社区<OpenGL ES 3.x游戏开发(下卷)>一书中的第1章,第1.2节,作者: 吴亚峰 责编: 张涛,更多章节内容可以访问云栖社区"异步社区"公众号 ...

  4. 《OpenGL ES 2.0游戏开发(上卷):基础技术和典型案例》——6.5节光照的每顶点计算与每片元计算...

    本节书摘来自异步社区<OpenGL ES 2.0游戏开发(上卷):基础技术和典型案例>一书中的第6章,第6.5节光照的每顶点计算与每片元计算,作者 吴亚峰,更多章节内容可以访问云栖社区&q ...

  5. 《OpenGL ES 2.0游戏开发(上卷):基础技术和典型案例》一第6章 让场景更逼真——光照效果...

    本节书摘来异步社区<OpenGL ES 2.0游戏开发(上卷):基础技术和典型案例>一书中的第6章,第6.1节,作者: 吴亚峰 责编: 张涛,更多章节内容可以访问云栖社区"异步社 ...

  6. 《OpenGL ES 3.x游戏开发(上卷)》一2.4 文件I/O

    本节书摘来异步社区<OpenGL ES 3.x游戏开发(上卷)>一书中的第2章,第2.4节,作者: 吴亚峰 责编: 张涛,更多章节内容可以访问云栖社区"异步社区"公众号 ...

  7. 《OpenGL ES 3.x游戏开发(下卷)》一2.4 展翅飞翔的雄鹰

    本节书摘来异步社区<OpenGL ES 3.x游戏开发(下卷)>一书中的第2章,第2.4节,作者: 吴亚峰 责编: 张涛,更多章节内容可以访问云栖社区"异步社区"公众号 ...

  8. Unity2D--关于2D游戏的切图小技巧

    在Unity2D游戏中,在制作过程中有时会使用一些游戏素材来增加游戏的趣性 但在一些裁剪游戏素材的过程中我们会发现,当我们裁剪完之后为他添后Animation后,游戏素材可能会出现上下浮动的现象.举个 ...

  9. iPhone的OpenGL ES的资源- 18,你必须知道 !

    iPhone的OpenGL ES的资源- 18,你必须知道 ! OpenGL ES是编程的iPhone使用的图形API. 如果要创建自己的游戏引擎,从头开始设计一个游戏,或者创造一些其他图形密集型应用 ...

最新文章

  1. 2.抽取代码(BaseActivity)
  2. 一文读懂支持向量机SVM(附实现代码、公式)
  3. Django后台定制
  4. html图片上下左右滑动,一个支持任意尺寸的图片上下左右滑动效果
  5. Kafka日志清理之Log Deletion
  6. Please ensure that adb is correctly located at……问题解决方案
  7. Java面向对象(5)--类的成员构造器(构造方法)
  8. jquery 操作日期、星期、元素的追加
  9. QT新建项目显示项目未配置的原因与解决方案
  10. 了解Base64编码的原理(js核对)
  11. ajax中设置请求头和自定义请求头
  12. python 3维图形库_Python 绘制 3 维以上的高维图
  13. java语言代码大全_java语言代码大全解析
  14. 秒杀系统的设计思维导图
  15. c语言实现fft原理,新手小白一看就会,FFT算法的原理详解
  16. 苹果搜索广告ASA开户教程
  17. SSRS 锁定标题栏
  18. 高德地图插件的简单使用
  19. QQ音乐sign,jsvmp算法推导
  20. (USB:VCP+HID复合设备与系统配置)

热门文章

  1. 更换服务器IP有哪些步骤,如何操作。
  2. ArcGIS 实验理论基础十五 空间查询
  3. Unity打包报错 com.android.buil.gradle.internal.tasks.workers$ActionFacade
  4. 运放参数详细解释与分析
  5. Android 第三方桌面,怎么请求Widget的android.permission.BIND_APPWIDGET
  6. 工商银行提前还房贷流程
  7. 高通平台ITS:sensor_fusion test_sensor_fusion.py Fail
  8. How to Write a Spelling Corrector代码注释
  9. 五险一金重要吗?还是趁年轻多赚钱比较重要?
  10. 驱动程序如何手动卸载与更新