我有一款2d Android游戏,目前导致某些设备内存不足。我在不同时间使用了许多png文件(总计约10mb)。在游戏的某些时候,这些内容中的大多数需要同时显示。
我试过降低图像的分辨率,但我对这样做后的质量不满意。
我读过一些关于如何解决这些内存问题的帖子,据我所知,纹理压缩是最好的方法(如果我错了,请随时纠正我)。我也看过这篇文章,介绍了如何确定设备上支持哪种纹理压缩格式,我理解这部分内容:
我的问题有两个:
-
我的大多数纹理需要alpha。我知道默认情况下ETC1不支持alpha,但我也知道当使用ETC1时,您可以创建一个单独的alpha压缩,如下所述:http://sbcgamesdev.blogspot.com/2013/06/etc1-textures-loading-and-alpha.html。该链接展示了如何使用NDK应用alpha。我正在努力理解如何使用标准的OpenGL ES Java包装器来做到这一点。下面是我目前如何处理纹理(即没有纹理压缩)。我如何将其转换为处理压缩纹理,我需要分别加载alpha ?
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[1]; gl.glGenTextures(1, textureIds, 0); textureId = textureIds[0]; InputStream inputStream = null; try { inputStream = fileIO.readAsset(fileName); Bitmap bitmap = BitmapFactory.decodeStream(inputStream); gl.glBindTexture(GL10.GL_TEXTURE_2D, textureId); GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0); setFilters(GL10.GL_NEAREST, GL10.GL_NEAREST); gl.glBindTexture(GL10.GL_TEXTURE_2D, 0); width = bitmap.getWidth(); height = bitmap.getHeight(); bitmap.recycle(); } 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; }
-
我的理解是,我必须为我的每个图像提供4个压缩纹理(每种格式一个)和一个未压缩的PNG,以支持广泛的设备。我担心的是这将导致所需的磁盘大小增加。有什么解决办法吗?例如,使用压缩纹理,以降低我的游戏的内存使用,而不会导致游戏的磁盘大小爆炸?
与其以4种不同的压缩格式提供alpha纹理,不如将alpha从图像中分离出来,并使用ETC1来处理图像的颜色,甚至可能使用alpha部分。棘手的部分是,你必须将每个图像的alpha分离到单独的纹理文件中,然后为OpenGL ES编写一个片段着色器,使用两个采样器从这些纹理对中采样并重新组合它们。着色器代码应该是这样的:
uniform sampler2D sampler_color;
uniform sampler2D sampler_alpha;
varying vec2 texCoord;
void main()
{
vec3 vColor = texture2D(sampler_color, texCoord);
float fAlpha = texture2D(sampler_alpha, texCoord);
gl_FragColor = vec4(vColor, fAlpha);
}
这将在超过99%的Android设备上工作,并允许所有的alpha纹理被压缩,这不仅使它们更小,而且它们也会加载得更快。