cocos creator 纹理压缩

890 阅读3分钟

creator 2.4.10的支持情况 image.png

webgl支持的纹理格式已经比较全面了

image.png

支持的参数

PVRTexToolCLI.exe

Usage -f [format],, Example -f PVRTC1_2,UBN,lRGB

-Valid Formats: PVRTC1_2, PVRTC1_4, PVRTC1_2_RGB, PVRTC1_4_RGB, PVRTC2_2, PVRTC2_4, ETC1, BC1, BC2, BC3,UYVY, YUY2, 1BPP, RGBE9995, RGBG8888, GRGB8888, ETC2_RGB, ETC2_RGBA, ETC2_RGB_A1, EAC_R11, EAC_RG11, ASTC_4x4, ASTC_5x4, ASTC_5x5, ASTC_6x5, ASTC_6x6, ASTC_8x5, ASTC_8x6, ASTC_8x8, ASTC_10x5, ASTC_10x6, ASTC_10x8, ASTC_10x10, ASTC_12x10, ASTC_12x12, ASTC_3x3x3, ASTC_4x3x3, ASTC_4x4x3, ASTC_4x4x4, ASTC_5x4x4, ASTC_5x5x4, ASTC_5x5x5, ASTC_6x5x5, ASTC_6x6x5, ASTC_6x6x6

engine

cc.gfx.deviceManager.gfxDevice.memoryStatus.textureSize    

etc1: 不支持alpha通道,所以只能应用在jpeg上,基本上现在很少用了

每个 4x4 像素块被压缩成一个 64 位的数据块,也就是8字节

image.png

130*166*4

etc2:支持alpha通道,兼容性没有etc1好,但是目前主流设备已经慢慢支持了

3.1 ETC1

ETC1把4*4的像素块压缩成固定的64位编码(8个字节),4*4像素块是16个像素,每个像素4字节,一共占64个字节,所以压缩比是 64/8=8。但是ETC1只能存储RGB信息,不适用带透明度的纹理,为解决这个问题,Creator在ETC1文件中额外写入了透明度信息,即ETC1+A格式,它的压缩比是 64/16=4。
ETC1/ETC1+A需要OpenGL ES 2.0(对应WebGL 1.0)环境,目前几乎所有Android手机都支持ETC1,但是iOS不支持。
ETC1/ETC1+A纹理的长宽可以不相等,但要求是2的幂次方。

3.2 ETC2

ETC2是ETC1的扩展,压缩比率一样,但压缩质量更高,而且支持透明通道,能完整存储RGBA信息。
ETC2需要OpenGL ES 3.0(对应WebGL 2.0)环境,目前还有不少低端Android手机不兼容,iOS方面从 iPhone5S 开始都支持OpenGL ES 3.0。
ETC2和ETC1一样,长宽可以不相等,但要求是2的幂次方。

3.3 PVRTC

Creator中常用的是PVRTC4+A,压缩比和ETC一样,iOS全系列支持,但是Android不支持。另外PVR要求纹理长宽相等(正方形)且是2的幂次方,例如1280*720的PNG图片,转换后变成2048*2048,这一点会大大增加内存消耗。在实测中还发现转换后的图片质量不如ETC1,存在模糊、毛边现象,对画面要求高的游戏不适合。

creator3.x

image.png

如果开启压缩纹理,就会自动压缩指定的格式,并且压缩参数,大家都是一致的,无法针对单个png进行设置,

image.png

不同格式的纹理加载

WebGL: INVALID_VALUE: texImage2D: bad image data
gl.texImage2D(
    gl.TEXTURE_2D,    // target
    0,                // level
    gl.RGBA,          // internalformat
    gl.RGBA,          // format
    gl.UNSIGNED_BYTE, // type
    img               // ImageData
);
  • engine 的逻辑
 _setImage(glFmt, options) {
    let gl = this._device._gl;
    let flipY = options.flipY;
    let premultiplyAlpha = options.premultiplyAlpha;
    let faceIndex = options.faceIndex;
    let img = options.image;

    if (flipY === undefined) {
      gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
    } else {
      gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
    }

    if (premultiplyAlpha === undefined) {
      gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
    } else {
      gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, premultiplyAlpha);
    }
    if (img && !ArrayBuffer.isView(img) && !(img instanceof ArrayBuffer)) {
      gl.texImage2D(
        gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex,
        options.level,
        glFmt.internalFormat,
        glFmt.format,
        glFmt.pixelType,
        img
      );
    } else {
      if (this._compressed) {
        gl.compressedTexImage2D(
          gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex,
          options.level,
          glFmt.internalFormat,
          options.width,
          options.height,
          0,
          img
        );
      } else {
        gl.texImage2D(
          gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex,
          options.level,
          glFmt.internalFormat,
          options.width,
          options.height,
          0,
          glFmt.format,
          glFmt.pixelType,
          img
        );
      }
    }
  }    

纹理预览

在ios 和安卓那边。纹理图片常常会转换为pvr格式。 pvr 格式须要特定的显卡支持才行。所以在windows 下查看须要借用工具

支持下面格式。

//ios PVR TC 4BPP 
//android PVR RGBA4
//dds png jpg 等

ios PVR TC 4BPP  格式是ios下才支持的。 本软件直接用软解码的方式解析, 不依赖于显卡。

  • vscode-prv-viewer 自己参照pvr.cpp转换成js代码,实际测试发现,游戏pvr格式支持的并不是很好,无法显示

image.png

github.com/davidlsun/v…

image.png

  • Tacent View: c++实现的pvr, pkm查器

image.png

github.com/bluescan/ta…