OpenGL-纹理(下)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenGL-纹理(下)相关的知识,希望对你有一定的参考价值。
参考技术A mipmap一词出自Lance Willianms 的论文<<Pyramidal Parametrics>>--1983年, mip -> multum in parvo "在一个小城区的很多种东西"。mipmap技术使用了一些聪明的做法将图像数据打包到内存中。OpenGL 在使用 mipmap时会自动判断当前使用的纹理贴图是那个层级,这是基于被映射物体的尺寸( 以像素为单位 )决定的,通过这种做法,我们可以根据纹理贴图的细节层次(level of detail),找到当前会知道屏幕的最合适图像,如果物体变得更小,那么纹理贴图层次也会的尺寸也会减小,mipmap需要一些额外的计算和纹理存储的区域。如果我们不使用mipmap的话,纹理被映射到较小的物体上之后可能会出现闪烁现象。
在介绍OpenGL mipmap的时候,并没有讨论纹素尺寸之间的缩放参数,此外还假设mipmap的所有参数都使用了默认值。
mipmap简单来说就是一些列的纹理图像,后一个纹理图像是前一个纹理图像的1/4,知道最后一个图的像素是1*1d的时候停止。多级渐远背后的原理就是:观察者距离物体超过一定的阈值,OpenGL会使用不同的多级渐远纹理,即最适合物体的距离的那个。由于距离远,解析度不高也不会被用户注意到。
下图就是简单展示了一下渐远纹理的样子:
图中1,2,3区域距离观察者越来越远。
这两个问题看似可以使用同样样式的更小的纹理来解决,但是当观察者与物体距离靠近的时候,物体表面就会被渲染得更大,这样就会导致纹理不得不拉伸,从而形成了视觉模糊或者斑驳状纹理的现象;
我们虽然可以通过设置GL_TEXTURE_BASE_LEVEL和GL_TEXTURE_MAX_LEVEL来设置那些mip层被加载到屏幕上,但是我们仍然需要使用GL_TEXTURE_MIN_LOAD 和 GL_TEXTURE_MAX_LOAD来限制已经加载的mip层的使用范围。
只有minFilter等于下面四种模式的时候才可以生成mip贴图:
当我们给一个几何图形纹理贴图的时候,如果它的观察视角刚好垂直于这个几何面,那么这个纹理贴图的过程是最完美的。
确保释放 OpenGL 纹理内存
【中文标题】确保释放 OpenGL 纹理内存【英文标题】:Ensuring OpenGL Texture Memory is Released 【发布时间】:2011-03-14 18:33:21 【问题描述】:我的应用程序在两个活动之间切换时内存不足。第一个活动正在运行 OpenGL 场景,第二个活动不是。我想确保释放 OpenGL 场景使用的所有纹理。
我现在正在使用这种方法
getNativeHeapAllocatedSize()
跟踪纹理使用的相对内存量。如果我分配纹理,这个数字会增加大约 4 兆。然而,它似乎永远不会再次下降。
在我的第一个活动“OnPause”中,我有以下代码:
SurfaceView.onPause();
mTexture = null;
然后,在第二个活动中,我多次调用 getNativeHeapAllocatedSize()。即使在 GC 运行之后,内存仍然没有下降。
编辑:
经过更多研究,它似乎与加载数据的代码有关。我已经从方程中删除了 OpenGL,内存仍然没有被释放。
try
InputStream is = null;
AssetManager am = MyActivity.getAssetMgr();
is = am.open( fileName );
Bitmap b = BitmapFactory.decodeStream( is );
if( b != null )
mResX = b.getWidth();
mResY = b.getHeight();
Bitmap.Config bc = b.getConfig();
if( bc == Bitmap.Config.ARGB_8888 )
mBPP = 4;
else
mBPP = 2;
mImageData = ByteBuffer.allocateDirect( mResX * mResY * mBPP );
mImageData.order( ByteOrder.nativeOrder() );
b.copyPixelsToBuffer( mImageData );
mImageData.position( 0 );
return true;
catch (IOException e)
e.printStackTrace();
catch (Exception e)
e.printStackTrace();
return false;
编辑2:
我确实添加了你所有的想法。然而,这似乎是我的问题......
ByteBuffer not releasing memory
【问题讨论】:
【参考方案1】:我假设您的意思是通过 gl.glTexImage* 或任何其他辅助方法加载到 GPU 的纹理。在那种情况下,GC 不会帮助你,它不会清理纹理使用的内部内存
您是否尝试过通过 gl.glDeleteTextures 手动删除纹理?
根据新代码编辑:
您的代码中有几个漏洞:
关闭输入流 将数据复制到 ByteBuffer 后回收位图 我猜你使用带有图像数据的 byteBuffer 将纹理上传到 GPU,确保在上传数据后不要存储对这些缓冲区的引用。我在此代码中没有看到任何其他问题,如果在此修复后它仍然无法正常工作,那么请仔细查看您的应用中的任何位图用法。
【讨论】:
我只是指传递给 OpenGL 的数据。由于我之前发布过,我已经从等式中删除了 OpenGL,所以它必须与我的 ByteBuffer 或 Bitmap 处理有关。附带说明一下,当使用 Surface 视图时,您会调用 glDeleteTextures 吗?调用 onPause 时有一个函数可以覆盖,现在我说的是每个纹理中的 GL10 对象,但它似乎有点 hacky。 关于 glDeleteTextures - 通常你不应该删除它们,android 会为你做。我只是不确定它是否会关闭应用程序或活动暂停。但无论如何,GPU 中使用的内存不应该影响您的第二个屏幕 -关闭输入流-检查-将数据复制到 ByteBuffer 后回收位图-检查-我猜你使用带有图像数据的 byteBuffer 将纹理上传到 GPU,确保不存储上传数据后对这些缓冲区的引用。 - 所以在我通过glTexImage2D传递字节缓冲区之后,释放ByteBuffer就可以了吗?我会试一试。以上是关于OpenGL-纹理(下)的主要内容,如果未能解决你的问题,请参考以下文章