android opengl 紋理壓縮 使用帶透明通道的etc1

etc1網上資料很多,而帶透明通道,也就是alpha通道的方法其實就是mask摳圖,先看未處理時的紋理樣子

再來看處理完的樣子

帶透明通道的etc1其實就是高度加了一倍,在下面加上一個mask來進行摳圖,根據這個原理jpg我們也可以自己加上透明通道

說完原理來說代碼

關於etc1的處理代碼都在android.opengl.ETC1Util內

讀取etc1數據用的是ETC1Util.createTexture()方法,而Android對etc1的支持只能是PKM格式,查看createTexture的源碼你會發現它會把非PKM格式的數據給過濾掉了

public static ETC1Texture createTexture(InputStream input) throws IOException {
        int width = 0;
        int height = 0;
        byte[] ioBuffer = new byte[4096];
        {
            if (input.read(ioBuffer, 0, ETC1.ETC_PKM_HEADER_SIZE) != ETC1.ETC_PKM_HEADER_SIZE) {
                throw new IOException("Unable to read PKM file header.");
            }
            ByteBuffer headerBuffer = ByteBuffer.allocateDirect(ETC1.ETC_PKM_HEADER_SIZE)
                .order(ByteOrder.nativeOrder());
            headerBuffer.put(ioBuffer, 0, ETC1.ETC_PKM_HEADER_SIZE).position(0);
            if (!ETC1.isValid(headerBuffer)) {
                throw new IOException("Not a PKM file.");
            }
            width = ETC1.getWidth(headerBuffer);
            height = ETC1.getHeight(headerBuffer);
        }
        int encodedSize = ETC1.getEncodedDataSize(width, height);
        ByteBuffer dataBuffer = ByteBuffer.allocateDirect(encodedSize).order(ByteOrder.nativeOrder());
        for (int i = 0; i < encodedSize; ) {
            int chunkSize = Math.min(ioBuffer.length, encodedSize - i);
            if (input.read(ioBuffer, 0, chunkSize) != chunkSize) {
                throw new IOException("Unable to read PKM file data.");
            }
            dataBuffer.put(ioBuffer, 0, chunkSize);
            i += chunkSize;
        }
        dataBuffer.position(0);
        return new ETC1Texture(width, height, dataBuffer);
    }

通過ETC1Util.createTexture()獲取到ETC1Util.ETC1Texture,再通過ETC1Util.loadTexture()把ETC1Util.ETC1Texture的數據傳給opengl,由於添加了透明通道所以在處理的時候要對高度除以2,比如顯示的時候int height = texture.getHeight()/2;

在shader內進行處理的時候

vertexShader

attribute vec4 aPosition;
attribute vec2 aTexCoord;
varying vec2 vTexCoord;
void main() {
  vTexCoord = aTexCoord * vec2(1.0, 0.5);
  gl_Position = aPosition;
}

fragmentShader

varying highp vec2 vTexCoord;
uniform sampler2D sTexture;
void main() {
    highp vec4 color = texture2D(sTexture, vec2(vTexCoord.x,0.5 - vTexCoord.y));
    gl_FragColor = mix(vec4(0.0),color,texture2D(sTexture,vec2(vTexCoord.x,1.0 - vTexCoord.y)).r);
}

最後的就是mask摳圖代碼,因爲陰影部分要摳出半透明效果,所以要用mix,根據下半部分的mask混合透明和紋理

TestETC1

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章