WebGL/OpenGL ES texture贴图纹理压缩

1,425 阅读5分钟

www.jiazhengblog.com/blog/2017/0…

主流GPU纹理格式_jaccen的专栏-CSDN博客

GPU分类

1.1 Imagination Technologies的PowerVR SGX系列

  • 代表型号:PowerVR SGX 535、PowerVR SGX 540、PowerVR SGX 543MP、PowerVR SGX 554MP等
  • 代表产品:Apple iPhone全系、iPad全系,三星I9000、P3100等 1.2 Qualcomm(高通)的Adreno系列
  • 代表型号:Adreno 200、Adreno 205、Adreno 220、Adreno 320等
  • 代表产品 :HTC G10、G14,SamSung Glaxg S4,SE xperia、WP8、小米1、2等 1.3 ARM的Mali系列
  • 代表型号:Mali-400、Mali-T604等
  • 代表产品 :三星Galaxy SII、Galaxy SIII、Galaxy Note1、Galaxy Note2(亚版)等 1.4 NVIDIA(英伟达)的Tegra/GeForce系列
  • 代表型号:nVIDIA Tegra2、nVIDIA Tegra3等
  • 代表产品 :moto、Google Nexus 7,HTC One X、xiaomi3 、Tagra4等

压缩纹理格式

  • 常用的图像文件格式有:BMP、JPG、PNG、TGA等
    • 文件格式是图像为了存储而使用的编码格式,这些存储格式都是在硬盘保存的特殊编码格式,需要CPU读入,通过特定解码格式获得数据,然后传给GPU使用。
  • 常用的纹理格式有:RGB-565、RGBA-4444、RGBA-5551、RGB-888、RGBA-8888等
    • 纹理格式是能够被GPU识别的像素格式,能够被快速寻址采样。

OpengGL ES 所支持的纹理格式

  • OpenGL ES 2.0支持以上提到的R5G6B5,A4R4G4B4,A1R5G5B5,R8G8B8,A8R8G8B8等纹理格式,
    • R5G6B5,A4R4G4B4,A1R5G5B5每个像素占用2个字节(BYTE),
    • R8G8B8每个像素占用3个字节,
    • A8R8G8B8每个像素占用 4个字节。 image.png
  • 512x512的纹理的话,R5G6B5格式(2个字节)的文件512x512x2需要占用512KB的容量
  • 512x512的纹理的话,A8R8G8B8格式(4个字节)的文件1024x1024x4需要占用1MB的容量

常见的纹理压缩格式

  • 对于减小纹理的数据容量有明显作用,相应在显存带宽上也有明显优势,从而提高游戏的运行效率
  • S3TC(S3 texture compression)/DXTn/BCn:
    • 桌面计算机常见的压缩格式。名字虽然有不同叫法,但都是指同一种压缩方式。通常以DDS文件格式保存。
    • 也被称为DXTC,在PC上广泛被使用,但是在移动设备上还是属于新鲜事物。支持的GPU为NVIDIA Tegra系列。
    • OpenGL ES扩展名为:GL_EXT_texture_compression_dxt1和GL_EXT_texture_compression_s3tc。
    • 当加载压缩纹理时,internal format的参数有如下几种格式:
      • GL_COMPRESSED_RGB_S3TC_DXT1 (RGB,每个像素0.5个字节)
      • GL_COMPRESSED_RGBA_S3TC_DXT1 (RGBA,每个像素0.5个字节)
      • GL_COMPRESSED_RGBA_S3TC_DXT3 (RGBA,每个像素1个字节)
      • GL_COMPRESSED_RGBA_S3TC_DXT5 (RGBA,每个像素1个字节)
  • PVRTC/PVRTC2(PowerVR texture compression):
    • 支持的GPU为Imagination Technologies的PowerVR SGX系列。
    • iOS设备上使用的压缩纹式。
    • OpenGL ES的扩展名为: GL_IMG_texture_compression_pvrtc。
    • internal format
      • GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG (RGB,每个像素0.5个字节)
      • GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG (RGB,每个像素0.25个字节)
      • GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG (RGBA,每个像素0.5个字节)
      • GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG (RGBA,每个像素0.25个字节)
  • ETC/ETC2(Ericsson texture compression):
    • 随着OpenGL ES 2.0 出现,不支持半透明。
    • ETC1格式是OpenGL ES图形标准的一部分,并且被所有的Android设备所支持。
    • 扩展名称:GL_OES_compressed_ETC1_RGB8_texture
    • internal format 参数为 GL_ETC1_RGB8_OES
  • ASTC:2012年出现的一种新压缩格式。
  • ATC(ATI texture compression)
    • 支持的GPU为Qualcomm的Adreno系列。
    • 支持的OpenGL ES扩展名为: GL_ATI_texture_compression_atitc。
    • internal format
      • GL_ATC_RGB_AMD (RGB,每个像素0.5个字节)
      • GL_ATC_RGBA_EXPLICIT_ALPHA_AMD (RGBA,每个像素1个字节)
      • GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD (RGBA,每个像素1个字节)

压缩的意义

  • 浏览器从服务端加载这样一张图片时,其格式通常为JPEG,文件尺寸只有166KB
  • WebGL中texImage2D接口处理图片,GPU中按照位图处理,1024x1024x8x3x1.333,接近4M
  • 未使用纹理压缩,一张纹理的数据储存
    • image.png
  • 使用了纹理压缩,一张纹理的数据储存
    • image.png

查看WebGL所提供的扩展

    var availableExtensions = gl.getSupportedExtensions();
    for (var i = 0; i < availableExtensions.length; i++) {
        if (availableExtensions[i].indexOf('texture') >= 0
            && availableExtensions[i].indexOf('compressed') >= 0) {
            // show in console
            console.log(availableExtensions[i]);
        }
    }

查看WebGL所支持的扩展

  • formats是一个数组,可以看到里面有四个数值:[33776, 33777, 33778, 33779]
  • extension会打印如下信息
    • COMPRESSED_RGB_S3TC_DXT1_EXT 33776 0x83f0
    • COMPRESSED_RGBA_S3TC_DXT1_EXT 33777 0x83f1
    • COMPRESSED_RGBA_S3TC_DXT3_EXT 33778 0x83f2
    • COMPRESSED_RGBA_S3TC_DXT5_EXT 33779 0x83f3
       var compressedTextureType = ['s3tc', 'etc1', 'pvrtc'];
       var currentCompressedTextureType = null;
    
       function getSupportedCompressedTextureType() {
           var availableExtensions = gl.getSupportedExtensions();
           for (var i = 0; i < availableExtensions.length; i++) {
               for (var j = 0; j < compressedTextureType.length; j++) {
                   if (availableExtensions[i].indexOf(compressedTextureType[j]) > 0) {
                       var extension = gl.getExtension(availableExtensions[i]);
                       // 下面这句话必须在getExtension之后调用
                       var formats = gl.getParameter(gl.COMPRESSED_TEXTURE_FORMATS);
                       console.log(formats);
                       for (var key in extension) {
                           console.log(key, extension[key], '0x' + extension[key].toString(16));
                       }
                       return {
                           type: compressedTextureType[j],
                           extension: extension,
                           formats: formats
                       };
                   }
               }
           }
       }
    
  • gl.compressedTexImage2D 替换 gl.texImage2D
    • type 是前面通过extension获取到的那些常量
    • source就是压缩纹理的数据
    •   gl.compressedTexImage2D(gl.TEXTURE_2D, 0, type, width, height, 0, source);
      

OpenGL中相关API

  • 1) 获得GPU的型号
    glGetString(GL_RENDERER)
    
  • 2) 获得GPU的生产厂商
    glGetString(GL_VENDOR);
    
  • 3) 获取GPU支持哪些压缩纹理
    string extensions = (const char*)glGetString(GL_EXTENSIONS);
    
    a. 判断是否支持ETC1格式的压缩纹理
    return (extensions.find("GL_OES_compressed_ETC1_RGB8_texture")!= string::npos);
    
    b. 判断是否支持DXT格式的压缩纹理
    return (extensions.find("GL_EXT_texture_compression_dxt1")!= string::npos ||
            extensions.find("GL_EXT_texture_compression_s3tc")!= string::npos);
    
    c. 判断是否支持PVRTC格式的压缩纹理
    return (extensions.find("GL_IMG_texture_compression_pvrtc")!= string::npos);
    
    d. 判断是否支持ATITC格式的压缩纹理
    return (extensions.find("GL_AMD_compressed_ATC_texture")!= string::npos ||
            extensions.find("GL_ATI_texture_compression_atitc")!= string::npos);
    

4) 填充压缩纹理数据

void glCompressedTexImage2D (
     GLenum target,
     GLint level,
     GLenum internalformat,
     GLsizei width,
     GLsizei height,
     GLint border,
     GLsizei imageSize,
     const GLvoid * data);

压缩纹理工具的使用