关于opengl的纹理和调色板问题
来源:互联网 发布:app软件市场分析报告 编辑:程序博客网 时间:2024/04/28 13:17
最近碰到了一点问题,关于图片载入和显示方面的。
自己的引擎显示方面是基于opengl来实现的。显示图片也就是画一个矩形,然后贴上纹理。并且采用了批量绘图方法,将顶点数据存入显存里。用到了glsl。不知道的可以百度一下。
那在大量载入图片成为纹理并存入显存就有问题出现。本地文件先不说,载入到显存后的显存占用就成了问题。网上百度了一番了一些解决方法:
1.压缩纹理
很简单,具体怎么做百度一下你就知道。这里简单说一下,这分2个部分,内部压缩和,载入压缩纹理。
简单讲一下,内部压缩就是,源文件并不是压缩后的文件,所以opengl需要通过第三方库来加载文件,生成的unsigned char数组,这个数组大小是:unsigned char的大小也就是1Byte * 图片长 * 图片宽 * 通道数,然后使用glTexImage2D这类命令将数组传到内存中并绑定一个数字便于使用这个纹理。在这个过程中进行压缩,压缩后的现存占用最大可降低8倍。当然压缩也是占用时间的。也会失去一些画质。压缩级别分3档可以看需要压缩。
我载入了1000张图片,大小都是350x350,四个通道,占用了700mb左右的显存(不知道为什么比计算的要大)。1/8压缩后就成了:87.5mb,非常爽到!
载入压缩纹理,就是事先压缩好文件成一个dds文件,可以压的很小。怎么做dds文件找度娘吧。很多游戏都使用这个文件。opengl可以直接读取这个文件的数据到显存,不需要第三方库,直接用读取txt文件那样的方法就可以,不需要压缩解压,耗时非常少。
如果你的游戏有大量的纹理,不妨压缩一下可以占用更小的资源,也可以使载入速度更快。
2.进一步降低内存占用
前面说到降低占用,那么可不可以进一步降低占用呢?答案是可以的,以前的游戏为什么可以容量那么低。我估计他们用的是256色的图片,也就是16位的图片。也就是说一张图片顶多拥有256种颜色。每种颜色用3个unsigned char来存,图片的大小就是256 * 3 + 图片长*宽 Byte。
所以这样的图片文件分成2部分,颜色调色板palette和颜色索引color index。
调色板部分就是之前所说的256个颜色,256*3 Byte。
颜色索引就对应图片上的每个像素,不过他不用3个或4个unsigned char来存,他只用1个,就是 长 * 宽 byte。存的都是0-255,对应调色板上的颜色。比24位图片小了3倍左右,比32位图片笑了4倍左右。
我猜测那些游戏的图片全部保存成颜色索引。一个人物,几百张图片,共用一个调色板。这样就可以给人物切调色板不必重新加载一下几百张图片。而且内存占用也可以非常小。
3.调色板
我发现以前很多游戏,比如格斗游戏都可以选择2p角色颜色,也就是可以变色。而且这些游戏占用又非常小。估计是进入游戏后才把需要的图片载入到内存中。然后使用上面所说的256色贴图方法。就可以切换颜色,甚至在游戏中实时切换颜色。
那么opengl要如何做到呢。
opengl的颜色扩展里就可以做到。具体可以百度glColorTableEXT,GL_COLOR_TABLE,GL_SHARED_TEXTURE_PALETTE_EXT。使用的时候可能会发生程序崩溃,原因是这个函数指针是空的。首先检测一下计算机支不支持opengl颜色扩展。具体可百度GL_ARB_imaging。
反正我的机子是不行,不支持这个东西。
有人问,那通过glgetteximage拷贝出纹理的数据,通过替换像素来改变颜色再更新纹理行不行?
答案是可行,但这不是真正的调色板功能,而且效率低下。
举一个例子,一个角色的衣服和裤子都是黑色的,虽然都是黑色,但在调色板里不是一个颜色。这样就能载入不同的调色板让2p角色的衣服和裤子变成不同的颜色。如果按照刚才说的替换颜色的方法来的话,就无法做到这一点。除非把2个黑色弄得接近但不是同一个颜色。
况且2个相同的角色在画面上,用的是同一个纹理,那么把2p的颜色替换了,1p也会被替换。除非2p复制一套新的相同的纹理,再把颜色都替换掉。似乎不是很有效率。
结果只能依靠glsl了。
以下是glsl代码供参考。
uniform sampler1D Palette; // 一个调色板有256个颜色uniform sampler2D IndexedColorTexture; // 一个纹理中存的是颜色索引varying vec2 TexCoord0; // UVsvoid main(){ vec4 index = texture2D(IndexedColorTexture, TexCoord0);//提取颜色索引 vec4 texel = texture1D(Palette, index.x);//通过索引从调色板里得到实际的颜色。 gl_FragColor = texel; //显示出来}
用
glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, pal);
载入调色板给Palette。
这里用了GL_RGBA,也就是说比文件里的RGB调色板多了一个通道,所以data要分配256*4的大小。当然不想要alpha通道也可以。
用
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, m_Width, m_Height, 0, GL_RED, GL_UNSIGNED_BYTE, colorindex);
载入索引给IndexedColorTexture。
和一般载入图片不一样,这里只用了一个GL_RED通道,因为我们每个像素只需要存0-255的数据就行了。
想要更新调色板的话,用更新纹理一个方法。
这样一个纹理对应一个调色板。就可以现实图片了。至于效率怎么样,虽然我还没测试过,应该比用循环来替换颜色要快多了吧。
因为我都是自学的,可能说得不够好,哪里说的不对或者有什么要补充的欢迎告诉我。
完。
- 关于opengl的纹理和调色板问题
- OpenGL关于纹理和基本图形的混合问题
- 关于openGL纹理贴图的一些函数
- 关于OpenGL纹理映射的一点体会
- opengl 关于纹理贴图
- OpenGL中调色板的使用
- OpenGL纹理绘制时色偏的问题
- opengl es 纹理无法显示的问题
- OpenGL 有时候纹理映射的部分问题
- OPENGL 的世界坐标和 纹理坐标
- OPENGL 的世界坐标和 纹理坐标
- 关于调色板的理解
- 关于调色板的记录
- 关于纹理炫目的问题
- GL和DX中关于纹理操作(包括多重纹理)与混合的问题
- CPalette调色板的问题
- 调色板的原理和调色板显示模式
- OPENGL的纹理(转)
- PIE在IE下阴影问题
- H264头解析
- bzoj1526: [POI2005]ban- Bankomat
- Android--广播的类型及拦截有序广播案例
- Ubuntu16.04下安装WPS小结
- 关于opengl的纹理和调色板问题
- 旋转字符串
- HDU 2091 该死的格式 要注意细节
- 唯品会求职面试经过(含面试题)
- eclipse常用设置总结
- ELF文件-符号表
- 选择单条曲线偏置选择参考点
- tensorflow学习之路(2-1):tf.variable_scope(), tf.name_scope(), tf.get_variable()的认识
- 硬件姿态解算