0

我一直在尝试减少我编写的 Android 游戏中纹理的内存占用,但没有取得太大的成功。根据我所做的研究,似乎一个好方法是使用 ETC1 压缩我的纹理,因为这是 Android 设备最广泛支持的格式。

我可以使用 Mali ARM 从我的 PNG 创建必要的 PKM - 没有问题。我也可以使用 ETC1Utils 很好地渲染这些 PKM - 到目前为止也没有问题。

问题在于尝试处理 alpha。我使用 Mali 为我的 PNG 创建了一个单独的 alpha 文件,即“xxx.png”被压缩为“xxx.pkm”和“xxx_alpha.pkm”。在我提出的另一个问题中向我建议的一种方法是使用多重纹理来组合这两个纹理,因为我不能在 OpenGL ES 1.1 中使用片段着色器。

这就是我卡住的地方。我对这些东西不太熟悉,也没有太多进展。基本上,只要我尝试与我的 alpha 纹理相结合,一切都会呈现为白色。

这是我的代码片段:

public class Texture {

    GLGraphics glGraphics;
    FileIO fileIO;
    String fileName;
    int textureId;
    int minFilter;
    int magFilter;

    public int width;
    public int height;

    private boolean loaded = false;

    public Texture(GLGame glGame, String fileName) {
        this.glGraphics = glGame.getGLGraphics();
        this.fileIO = glGame.getFileIO();
        this.fileName = fileName;
        load();
    }

    public void load() {
        GL10 gl = glGraphics.getGL();
        int[] textureIds = new int[2];
        gl.glGenTextures(2, textureIds, 0);
        textureId = textureIds[0];

        InputStream inputStream = null;

        try {
            inputStream = fileIO.readAsset(fileName + ".pkm");

            int rgbTexture = textureId;

            gl.glActiveTexture(GLES10.GL_TEXTURE0);
            gl.glBindTexture(GLES11.GL_TEXTURE_2D, rgbTexture);
            gl.glTexEnvf(GLES11.GL_TEXTURE_ENV, GLES11.GL_TEXTURE_ENV_MODE, GLES11.GL_MODULATE);

            ETC1Texture etcTexture = ETC1Util.createTexture(inputStream);
            ETC1Util.loadTexture(GLES11.GL_TEXTURE_2D, 0, 0, GLES11.GL_RGB, GLES11.GL_UNSIGNED_SHORT_5_6_5, etcTexture);

            int alphaTexture = textureId[1];

            gl.glActiveTexture(GLES11.GL_TEXTURE1);
            gl.glBindTexture(GLES11.GL_TEXTURE_2D, alphaTexture);
            gl.glTexEnvf(GLES11.GL_TEXTURE_ENV, GLES11.GL_TEXTURE_ENV_MODE, GLES11.GL_COMBINE);
            gl.glTexEnvf(GLES11.GL_TEXTURE_ENV, GLES11.GL_COMBINE_RGB, GLES11.GL_REPLACE);
            gl.glTexEnvf(GLES11.GL_TEXTURE_ENV, GLES11.GL_SRC0_RGB, GLES11.GL_PREVIOUS);
            gl.glTexEnvf(GLES11.GL_TEXTURE_ENV, GLES11.GL_OPERAND0_RGB, GLES11.GL_SRC_COLOR);
            gl.glTexEnvf(GLES11.GL_TEXTURE_ENV, GLES11.GL_COMBINE_ALPHA, GLES11.GL_MODULATE);
            gl.glTexEnvf(GLES11.GL_TEXTURE_ENV, GLES11.GL_SRC0_ALPHA, GLES11.GL_TEXTURE);
            gl.glTexEnvf(GLES11.GL_TEXTURE_ENV, GLES11.GL_OPERAND0_ALPHA, GLES11.GL_SRC_ALPHA);
            gl.glTexEnvf(GLES11.GL_TEXTURE_ENV, GLES11.GL_SRC1_ALPHA, GLES11.GL_PREVIOUS);
            gl.glTexEnvf(GLES11.GL_TEXTURE_ENV, GLES11.GL_OPERAND1_ALPHA, GLES11.GL_SRC_ALPHA);

            InputStream inputStreamAlpha = fileIO.readAsset(fileName + "_alpha.pkm");
            ETC1Texture etcAlphaTexture = ETC1Util.createTexture(inputStreamAlpha);
            ETC1Util.loadTexture(GLES11.GL_TEXTURE_2D, 0, 0, GLES11.GL_RGB, GLES11.GL_UNSIGNED_SHORT_5_6_5, etcAlphaTexture);

            setFilters(GL10.GL_NEAREST, GL10.GL_NEAREST);
            gl.glBindTexture(GL10.GL_TEXTURE_2D, 0);

            width = etcTexture.getWidth();
            height = etcTexture.getHeight();
        } catch (IOException e) {
            throw new RuntimeException("Couldn't load texture '" + fileName + "'", e);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    // do nothing
                }
            }
        }

        loaded = true;
    }

    public void reload() {
        load();
        bind();
        setFilters(minFilter, magFilter);
        glGraphics.getGL().glBindTexture(GL10.GL_TEXTURE_2D, 0);
    }

    public void setFilters(int minFilter, int magFilter) {
        this.minFilter = minFilter;
        this.magFilter = magFilter;

        GL10 gl = glGraphics.getGL();
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, minFilter);
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, magFilter);
    }

    public void bind() {
        GL10 gl = glGraphics.getGL();
        gl.glBindTexture(GL10.GL_TEXTURE_2D, textureId);
    }

    public void dispose() {
        loaded = false;

        GL10 gl = glGraphics.getGL();
        gl.glBindTexture(GL10.GL_TEXTURE_2D, textureId);
        int[] textureIds = { textureId };
        gl.glDeleteTextures(1, textureIds, 0);
        gl.glBindTexture(GL10.GL_TEXTURE_2D, 0);
    }

    public boolean isLoaded() {
        return loaded;
    }

    public void setLoaded(boolean loaded) {
        this.loaded = loaded;
    }
}

我主要关心的是 load() 方法。这段代码是通过我在网上找到的片段组合在一起的,再加上我对多纹理缺乏了解,我显然在某个地方出错了。另请注意,当我渲染纹理时,我会调用:

GL10 gl = glGraphics.getGL();
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
gl.glEnable(GL10.GL_TEXTURE_2D);        

camera.setViewportAndMatrices();
gl.glEnable(GL10.GL_BLEND);
gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);

// call some objects that do my rendering stuff here

gl.glDisable(GL10.GL_BLEND);
gl.glDisable(GL10.GL_TEXTURE_2D);

当我渲染纹理时,我调用 Texture 类的 bind() 方法。如您所见,这绑定到我的全局 textureId 变量,该变量在加载时用作 RGB PKMs ID。我什至不确定这是否正确。我应该绑定到 RGB 的 ID 还是 alpha 的 ID?或者这甚至还没有走上正确的轨道?我的问题也可能与我如何使用 ETC1Utils 加载阿尔法有关——我不知道这种方法是否正确。

我真的很困惑,所以任何帮助指出我出错的地方以及关于如何实现多纹理以结合 ETC1 alpha 和 RGB 的某种解释真的很棒。

4

1 回答 1

0

我不确定这对于 OpenGL ES 1.1 中的固定管道是否可行,但是这里有一个关于如何为 1.1 和 2.0 组合纹理的很好的总结

此外,PowerVR SDK为 1.1 提供了一个很好的示例,称为 OGLESMultitexture.cpp。

于 2014-05-30T01:18:25.910 回答