我对使用OpenGL有非常基本的了解,尤其是在Android上。我正在开发一个使用OpenGL的应用程序,以便在全屏图像之间快速切换(因为使用普通的Android框架太慢)。
我发现,为了加载纹理,我需要做这样的事情。
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(vertices.length * 4);
byteBuffer.order(ByteOrder.nativeOrder());
vertexBuffer = byteBuffer.asFloatBuffer();
vertexBuffer.put(vertices);
vertexBuffer.position(0);
byteBuffer = ByteBuffer.allocateDirect(texture.length * 4);
byteBuffer.order(ByteOrder.nativeOrder());
textureBuffer = byteBuffer.asFloatBuffer();
textureBuffer.put(texture);
textureBuffer.position(0);
_gl = gl;
final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), _imageResourceId);
gl.glGenTextures(1, textures, 0);
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle();
现在,由于这些图片是要全屏显示的(而且它们相当大--1024x1024),这需要一些时间,特别是我需要同时加载5张图片。
所以我需要问一些关于改进代码的技巧的问题,特别是关于高效加载的问题(如果可能的话,还要使用更少的内存)。
如果我通过使用RGB_565格式,将位图解码为没有透明像素,会不会提高加载图像到OpenGL(或解码阶段)的速度?
输入的位图的宽度和高度是否必须是2的幂,或者我可以让OpenGL只取它想要的部分,这将有这个规则?我是说,也许我可以让texImage2D
命令只取位图的一部分?
也许我甚至可以从头开始只解码这一部分(所以如果我有一个10000x10000的巨大图像,我可以只解码其中1024x1024的部分,并将其交给OpenGL)?
有没有可能只加载并显示第一张图片,然后在后台加载其他的图片?我听说你不能在一个不是处理它的线程中向OpenGL发送位图。在GlRenderer
的onDrawFrame
方法上加载它们,比如说,在它第二次被调用时,这样做有意义吗?
我记得我听说过一个小窍门,就是把多个图像合并成一个图像(一个接一个,从左到右),这样在解码阶段可能会有一些速度提升。不知道这个技术的名字是什么。对于安卓上的OpenGL ES来说,这还可能吗?
是否有可能避免创建一个Bitmap实例,而让解码以更原生的方式完成(NDK,也许)?根据我的测试,在模拟器上解码一个1024x1024大小的PNG文件大约需要400ms-700ms,然而将其发送到OpenGL大约需要50ms-70ms。
在使用Procrank时,我发现OpenGL会占用大量的内存。有没有可能让它使用更少的内存?也许使用更好的纹理类型?
既然安卓系统可以在多种设备上运行,是否可以在清单中加入应用运行需要多少内存的要求,这样内存太小的人就无法安装?
那么,这样解码并将其发送到OpenGL就足够了,还是在发送到OpenGL时我还应该设置一些特殊的东西?
有没有这样的命令来获取位图的部分内容?
我的意思是,我能否只对文件的部分内容进行解码,将其存储在位图中,而不是所有的位图?
所以我唯一能做的就是在开始时加载所有的东西,然后全部使用?这怎么可能呢?游戏是如何处理的?我的意思是,他们确实显示了一个又一个的阶段,甚至有一些看起来像OpenGL生成的进度条。这是很有问题的。
我所描述的东西在网络上也是可用的。例如,网页不是加载多个微小的图像,而是包含一个单一的图像,并映射它的哪一部分应该显示在哪里。它的另一个名字是sprites.例子here .
我明白了。我想我也应该在看到不再使用时调用glDeleteTextures,对吗?
我怎么做呢?我应该在代码中改变什么?
当我使用大量的内存时会发生什么?当没有空闲内存时,是否有虚拟内存(也许使用内部存储)这种东西?我在谷歌IO视频上听说过,但似乎他们对答案也不确定。链接here.他们只是说,当这种事情发生时,要期待更多的崩溃。
这可能有用。你的意思是,我建立一个新的线程来加载位图,然后将结果送回OpenGL线程,后者将把纹理绑定到位图上?也许我可以使用类似于asyncTask的方法,并使用publishprogress。
这也是一件好事。你有什么链接可以让我阅读吗?或者是在我的代码中修改一个片段?
所以我认为使用ETC1是最简单的事情。然而,它根本不支持透明度,所以根据this link我需要使用另一种纹理,但我找不到这方面的样本。
我可以假设我可以使用的可用内存是多少?例如,我可以假设所有的安卓设备都能为我提供200MB的视频内存,我可以使用OpenGL吗?