1.理解纹理

OpenGL中的纹理可以用来表示图像,照片,甚至由一个数学算法生成的分形数据。每个二维的纹理都由许多小的纹理元素组成,它们是小块的数据,类似于我们前面讨论过的片段和像素。要使用纹理,最常用的方式是直接从一个图像文件加载数据。

每个二维纹理都有其自己的坐标空间,其范围是从一个拐角的(0,0)到另一个拐角的(1,1)。按照惯例,一个维度叫做S,而另一个称为T。当我们想要把一个纹理应用于一个三角形或一组三角形的时候,我们要为每个顶点指定一组ST纹理坐标,以便OpenGL知道需要用那个纹理的哪个部分画到每个三角形上。这些纹理坐标有时也会被称为UV纹理坐标。如图:

图1 OpenGL二维纹理坐标

对一个OpenGL纹理来说,它没有内在的方向性,因此我们可以使用不同的坐标把它定向到任何我们喜欢的方向上。然而,大多数计算机图像都有一个默认的方向,它们通常被规定为Y轴向下,Y的值随着向图像的底部移动而增加。只要我们记住,如果想用正确的方向观察图像,那纹理坐标就必须要考虑这点,这就不会给我们带来任何麻烦。

在标准OpenGL ES 2.0中,纹理不必是正方形,但是每个维度都应该是2的幂(POT)。这就意味着每个维度都是这样的一个数字,如128,256,512等。这样规定的原因在于非POT纹理可以被使用的场合非常有限,而POT纹理使用于各种情况。

纹理的尺寸也有一个最大值,它根据不同的实现而变化,但是通常都比较大,比如2048*2048。

2.理解纹理过滤

当纹理的大小被扩大或者缩小时,我们还需要使用纹理过滤明确说明会发生什么。当我们在渲染表面上绘制一个纹理时,那个纹理的纹理元素可能无法精确地映射到OpenGL生成的片段上。有两种情况:缩小和放大。当我们尽力把几个纹理元素挤进一个片段时,缩小就发生了;当我们把一个纹理元素扩展到许多片段时,方法就发生了。针对每一种情况,我们可以配置OpenGL使用一个纹理过滤器。

首先,讲述两个基本的过滤模式:最近邻过滤和双线性插值。还有其他的过滤模式,以后的博文会讲解。我们会使用下面的图像阐述每一种过滤模式。

最近邻过滤

这个方式为每个片段选择最近的纹理元素。当我们放大纹理时,它的锯齿效果看起来相当明显,如下图所示。

每个纹理单元都清楚的显示为一个小方块。

当我们缩小纹理时,因为没有足够的片段用来绘制所有的纹理单元,许多细节将会丢失。

双线性过滤

双线性过滤使用双线性插值平滑像素之间的过渡,而不是为每个片段使用最近的纹理元素,OpenGL会使用四个邻接的纹理元素,并在它们之间用一个线性插值算法做插值,这个算法与前面所讲的平滑坐在着色一样。我们之所以称它为双线性插值,是因为它是沿着两个维度插值的。下面是使用双线性差值放大后的图像,它采用的纹理与前面的相同。

这个纹理现在看起来比以前平滑多了。但还是有些锯齿显现出来,因为我们把这个纹理扩展得太多,但是锯齿不像使用最近邻过滤那么明显。

MIP贴图

尽管双线性过滤很适合处理放大,但是对于缩小到超过一定的大小时,它就不好用了。一个纹理在渲染表面所占大小减少得越多,就会有越多的纹理元素拥挤到每一个片段上。因为OpenGL的双线性过滤只给每个片段使用四个纹理元素,我们将会丢失很多细节。因为每一帧都要选择不同的纹理元素,这还会引起噪音以及移动中的物体闪烁。

为了克服这些缺陷,可以使用MIP贴图技术,它可以用来生成一组优化过的不同大小的纹理。当生成这组纹理的时候,OpenGL会使用所有的纹理元素生成每个级别的纹理,当过滤纹理时,还要确保所有的纹理元素都能被使用。在渲染时,OpenGL会根据每个片段的纹理元素数量为每个片段选择最合适的级别。

下图是一组MIP贴图的纹理,把它们合并在一当个图上是为了方便对比。

图2 MIP贴图的纹理

使用MIP贴图,会占用更多的内存,但是渲染也会更快,这是因为较小级别的纹理在GPU的纹理缓存中占用较少的空间。

为了更好地理解MIP贴图是如何提高缩小情况下的质量,我们比较一下那个可爱的机器人,使用双线性过滤把纹理元素尺寸缩小到其原来的12.5%,如下图:

图3 使用双线性过滤缩小

就这种质量,可能还不如最近邻过滤。看一下当我们加入MIP贴图时会得到什么。如下图:

图4 使用MIP贴图缩小

随着MIP贴图的使用,OpenGL将选择最合适的纹理级别,然后用优化过的纹理做双线性插值。每个级别的纹理都是用来自所有纹理元素的信息构建的,因此得到的图形看起来更好些,保留了更多的细节。

三线性过滤

如果OpenGL在不同的MIP贴图级别之间来回切换,当我们用双线性插值来使用MIP贴图时,在其渲染的场景中,在不同级别的MIP贴图切换时,我们有时候能看到明显的跳跃或者线条。我们可以切换到三线性插值,这样,每个片段总共要使用8个纹理元素插值。这有助于消除每个MIP贴图级别之间的过渡,并且得到一个更平滑的图像。

3.程序中纹理参数表

方法GLES20.glTextParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAX_FILTER,“纹理过滤模式”);第二个参数指放大的情况。

方法GLES20.glTextParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,“纹理过滤模式”);第二个参数指缩小的情况。

第一个参数是告诉OpenGL这应该被作为一个二维纹理对待。

表1 OpenGL纹理过滤模式

GL_NEAREST

最近邻过滤

GL_NEAREST_MIPMAP_NEAREST

使用MIP贴图的最近邻过滤

GL_NEAREST_MIPMAP_LINEAR

使用MIP贴图级别之间插值的最近邻过滤

GL_LINEAR

双线性插值

GL_LINEAR_MIPMAP_NEAREST

使用MIP贴图的双线性插值

GL_LINEAR_MIPMAP_LINEAR

三线性插值(使用MIP贴图级别之间插值的双线性过滤)

表2 每种情况允许的纹理过滤模式

缩小

GL_NEAREST

GL_NEAREST_MIPMAP_NEAREST

GL_NEAREST_MIPMAP_LINEAR

GL_LINEAR

GL_LINEAR_MIPMAP_NEAREST

GL_LINEAR_MIPMAP_LINEAR

放大

GL_NEAREST

GL_LINEAR

下一篇纹理的应用效果图如下:

android纹理缓存,Android OpenGLES(七) 理解纹理与纹理过滤相关推荐

  1. android 根目录缓存,Android系统中内部存储和外部存储(公有目录、私有目录、缓存目录)详解...

    首先,明确一个概念,Android内部存储和外部存储并非所谓的手机自带内存是内部存储,SD卡是外部存储云云. Android对内部存储和外部存储不是在物理上区分的,而是在逻辑上区分的.git 1.概念 ...

  2. android sp缓存,Android sharedPreference设置缓存时间

    不废话,需求:缓存登录时的token,超过设置的存储时间就无效,怎么做? 使用ACache也可以设置缓存时间,但ACache在清缓存的时候会被清空. SharedPreferences存储默认都是无时 ...

  3. android 根目录缓存,Android 文件目录存储介绍 缓存目录 | 私有目录 | 系统根目录 | 用户可见目录...

    先简要介绍一下Android系统的文件系统吧,本文基于原生Android M系统: 我们都知道Android系统内核就是个Linux.所以我们的文件系统与Linux也是基本一致的,最顶部的目录是 &q ...

  4. android cache缓存,Android缓存Cache学习

    Android缓存Cache学习 java 项目中须要用到缓存,我使用的是文件缓存,这里简单总结下:android 主要思路是封装一个缓存对象,将每一个界面须要缓存的数据做为缓存对象的属性,将缓存对象 ...

  5. android 根目录缓存,Android缓存策略和目录

    2016.12.22 在使用图片加载库Glide时,要让磁盘缓存到指定的目录用 DiskLruCacheFactory: 由此展开的 Android 缓存策略和目录. 一.缓存: 通俗的说就是把一些经 ...

  6. android olhttp 缓存,android okhttp 缓存设置

    缓存第一步就是要保存 response 数据到缓存文件中,oktthp 用的是 DiskLruCache 会缓存到文件中. cache.png // 缓存路径- app 缓存目录 File file ...

  7. android texturevideoview 缓存,Android TextureView与VideoView性能

    Because a SurfaceView's content does not live in the application's window, it cannot be transformed ...

  8. android vitamio 缓存,Android如何集成Vitamio

    一.Vitamio的简介 Vitamio 是一款 Android 与 iOS 平台上的全能多媒体开发框架,全面支持硬件解码与 GPU 渲染.VItamio除了支持常规的格式之外,还支持流媒体格式,M3 ...

  9. android对象缓存,Android简单实现 缓存数据

    前言 1.每一种要缓存的数据都是有对应的versionCode,通过versionCode请求网络获取是否需要更新 2.提前将要缓存的数据放入assets文件夹中,打包上线. 缓存设计 代码实现 /* ...

最新文章

  1. ABP入门系列(7)——分页实现
  2. 【控制】传递函数拉氏变化如何与时间域结合使用举例
  3. C语言图形化编程 【二】
  4. ubuntu开启客户端nfs服务_LINUX系统使用NFS文件共享
  5. 华为P50 Pro最新渲染图曝光:后置造型有点奇怪
  6. Java二叉排序树(转)
  7. UNITY服务器登录验证设计,Unity游戏登录模块流程(需验证)
  8. 达内java考试_达内第一次JAVA考试题
  9. CAD地形图等高线标高批量取整工具,解决等高线标高出现小数的问题,等高线高程批量取整,在指定限差内将等高线标高修改为最接近的整数
  10. IOS开发 百度语音实现播报及IOS12.1后的播报功能问题与实现
  11. vmware workstation 12 永久激活码
  12. STM32F103 与 STM32F207/407编程的区别自我总结
  13. 互联网晚报 | 7月16日 星期六 |抖音回应“外卖功能上线”;上半年国内生产总值同比增长2.5%;雷军8月将携小米工程样车亮相...
  14. matlab雨中行走代码,雨中行走数学建模雨中行走数学建模.doc
  15. 后台数据不清理android,android 后台被数据清理后切换到前台数据丢失问题
  16. 电话会议炸出了同事里的隐形富豪
  17. c#利用log4记录日志
  18. MES系统读取MySQL数据_MES系统数据库
  19. vue用户没有头像用姓名首字母做头像
  20. 排列组合思维导图_思维模型10 - Permutations and Combinations | 排列组合

热门文章

  1. SDWebImage源码阅读(三)UIImage+GIF
  2. 修改openwrt 编译 image的大小
  3. Python学习笔记:SMTP服务器
  4. 关于fseek不能定位大于2G文件的问题
  5. TSS描述符表的作用
  6. Compiling Fortran
  7. Java中resource文件夹
  8. 通信工程专业的一些小知识点
  9. ”语义分割”中的“语义”
  10. leetcode_longest substring without repeating characters