本文介绍了什么是压缩纹理,以及加载压缩纹理的核心步骤 。并在 Android OpenGLES 平台上实现了压缩纹理的显示 。一、压缩纹理概念传统的图片文件格式有 PNG 、 JPEG 等,这种类型的图片格式无法直接被 GPU 读取,需要先经过 CPU 解码后再上传到 GPU 使用,解码后的数据以 RGB(A) 形式存储 , 无压缩 。
纹理压缩顾名思义是一种压缩的纹理格式,它通常会将纹理划分为固定大小的块(block)或者瓦片(tile) , 每个块单独进行压缩,整体显存占用更低,并且能直接被 GPU 读取和渲染(无需 CPU 解码) 。
纹理压缩支持随机访问 , 随机访问是很重要的特性,因为纹理访问的模式高度随机,只有在渲染时被用到的部分才需要访问到,且无法提前预知其顺序 。而且在场景中相邻的像素在纹理中不一定是相邻的 ,因此图形渲染性能高度依赖于纹理访问的效率 。综上,相比普通格式图片 , 纹理压缩可以节省大量显存和 CPU 解码时间 , 且对 GPU 友好 。
二、OpenGL 接口想要使用 OpenGL 加载压缩纹理,只需要了解一个接口:
glCompressedTexImage2D
。1.
glCompressedTexImage2D
接口声明如下,注释里说明了各参数的含义:void glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, // 格式 GLsizei width, // 纹理宽度 GLsizei height, // 纹理高度 GLint border, GLsizei imageSize, // 纹理数据大小 const void *data) // 纹理数据所以加载一个压缩纹理,主要有以下几个要点:
- 获取到压缩纹理存储格式
- 获取压缩纹理的大小
- 获取压缩纹理的图像大小
std::string extensions = (const char*)glGetString(GL_EXTENSIONS);if (extensions.find("GL_OES_compressed_ETC1_RGB8_texture")!= string::npos) { // 支持 ETC1 纹理}if (extensions.find("GL_OES_texture_compression_astc") != std::string::npos) { // 支持 ASTC 纹理}三、压缩纹理加载为了方便描述,定义了一个压缩纹理的结构体:
// 压缩纹理相关信息struct CompressedTextureInfo { bool is_valid; // 是否为一个有效的压缩纹理信息 GLsizei width; GLsizei height; GLsizei size; GLenum internal_format; GLvoid *data;};下面介绍ETC1、ETC2和ASTC格式的压缩纹理如何解析成
CompressedTextureInfo
对象 。1.ETC1【Android 使用压缩纹理】ETC1格式是OpenGL ES图形标准的一部分,并且被所有的Android设备所支持 。扩展名为: GL_OES_compressed_ETC1_RGB8_texture,不支持透明通道,所以仅能用于不透明纹理 。且要求大小是2次幂 。当加载压缩纹理时 , 参数支持如下格式: GL_ETC1_RGB8_OES(RGB,每个像素0.5个字节)ETC1 压缩纹理的加载,主要参考了Android源码:etc1.cpp解析 ETC1 纹理:
// 解析 ETC1 纹理static const CompressedTextureInfo ParseETC1Texture(unsigned char* data) { CompressedTextureInfo textureInfo; textureInfo.is_valid = false; const etc1::etc1_byte *header = data; if (!etc1::etc1_pkm_is_valid(header)) { LogE("LoadTexture: etc1_pkm is not valid"); return textureInfo; } unsigned int width = etc1::etc1_pkm_get_width(header); unsigned int height = etc1::etc1_pkm_get_height(header); GLuint size = 8 * ((width + 3) >> 2) * ((height + 3) >> 2); GLvoid *texture_data = data + ETC1_PKM_HEADER_SIZE; textureInfo.is_valid = true; textureInfo.width = width; textureInfo.height = height; textureInfo.size = size; textureInfo.internal_format = GL_ETC1_RGB8_OES; textureInfo.data = texture_data; return textureInfo;}
推荐阅读
- 手把手教你玩转 Gitea|使用 Docker 安装 Gitea
- 26 《吐血整理》高级系列教程-吃透Fiddler抓包教程-Fiddler如何抓取Android7.0以上的Https包-上篇
- 苹果手机怎么使用超级截屏(苹果手机超级截屏在哪里)
- DirectX 使用 Vortice 从零开始控制台创建 Direct2D1 窗口修改颜色
- 为什么阿里Java开发手册不推荐使用Timestamp
- VMware安装Win11+WSA子系统和使用教程
- 支付宝取消自动续费怎么取消? 支付宝取消自动续费怎么取消
- 宝马3系320Li的使用日记 宝马3系320li价格
- 晚上避光使用了果酸面霜,为什么脸色还是变黑了
- 手镯变黑怎么恢复 银手镯变黑怎么清洗变亮