虚拟贴图理论篇之Texture Filtering

Texture Filtering,通常我们会在引擎或者是图形API中根据具体的需求设置,但是对于虚拟贴图,由于每一个物理Page的地址不连续。导致硬件的Filtering无法使用,因此我们需要特殊处理,搞清楚Texture Filtering的原理基本上就知道该怎么处理这些问题了。

Texture Filtering有四种:

1.点采样

2.线性采样/双线性采样

3.三线性采样

4.各向异性采样

点采样

点采样又叫邻近过滤,顾名思义就是选取离uv坐标最近的纹素点。因为我们的uv坐标是连续0-1区间,而纹理贴图则是一个离散的点集合如下图:

十字符号代表uv坐标,记住最近距离是指离纹素中心,而不是纹素块的四个角。因此上图选择了浅蓝色而不是深蓝色。虚拟贴图的indirect texture的采样就应该使用点采样,直接传入虚拟UV就可以正确的索引信息。

纹理放大和纹理缩小

纹理的纹素和屏幕的像素很少是一一对应的,如果一个纹素对应多个像素,那么这个纹素就被放大了,或者说屏幕上很多像素对应同一个纹素,这样就会丢失很多贴图的细节,最常见的效果就是锯齿。为了解决纹素放大,通常我们会取纹素周边的一些像素进行加权混合,比如双线性过滤及各向异性过滤都是用来解决纹理放大问题的。如果多个纹素对应一个像素,那么这些纹素就会被缩小,也就是说一个像素一会是纹素A一会是纹素B,这样就会造成闪烁。为了解决纹理缩放,我们引入Mipmap技术,Mipmap是一系列降采样的贴图,上层的mipmap贴图使用四个纹素混合生成下层的mipmap。

线性采样

线性采样是各向同性过滤,因为它在uv方向上的采样步长一致,也就是使用一个正方形区间进行混合。线性过滤会采样4个像素,分别是采样坐标左右两个像素,以及上下两个像素,左右像素加权混合后再与上下两个像素混合的结果混合。

上图展示了点采样和线性采样的对比图,可以看到线性采样没有锯齿感,但是很模糊。现在的gpu都有专门针对线性采样的硬件加速,线性采样和点采样一样都是原子操作。换句话说能够使用硬件采样,尽量不要在PS中多次采样自己混合,现在显卡计算不是瓶颈,读取带宽才是瓶颈。虚拟贴图由于page的边界不连续,两个相邻的page可能存储的是不相关的图贴。这样在使用线性采样的时候,在page的边界处就会造成采样过界。为了解决这个问题通常物理缓存中的page都会预留1个像素的边框来包裹贴图,比如虚拟page是127*127分辨率,物理page就是128*128。这样物理缓存就可以正常的使用线性过滤了。

三线性过滤

线性过滤有一个问题就是在mipmap切换的地方会突变如下图:

为了解决mipmap切换导致的突变问题,引入了三线性过滤,三线性过滤就是在两层mipmap中分别使用线性过滤采样两个点,然后这两个点再进行混合。其实这里描述的不是很准确,在图形API中,可以控制是否使用mipmap,如果使用mipmap,每一层的采样可以是点采样,线性采样,各向异性采样。了解了三线性过滤的原理,很明显就会发现虚拟贴图实现三线性过滤的问题。我们的物理缓存中只存有一层mipmap。如果让虚拟贴图支持三线性过滤,有两种实现方法:

1.物理缓存生成一层mipmap,这样就可以进行混合了。这里有一个问题为什么只生成一层mipmap就可以了?因为物理缓存中每一个page存储的已经是不同的mipmap了,这里是为了支持硬件三线性过滤所以降采样生成了一张低级别的mipmap。这个方案首先增大了内存和显存,其实如果使用压缩格式可能会有问题,比如为了支持各向异性过滤我们使用4个像素包裹贴图,4个像素刚好可以进行块压缩,但是如果进行降采样生成mipmap,mipmap的边界处就会和包裹像素进行块压缩,这可能会照成显示上的错误。

2.在物理缓存中存储多个层次的mipmap,然后在PS自己进行混合,这种方案增加了采样的次数。

各向异性过滤

如上图各向异性过滤开的越大图像越清晰,各向异性过滤很重要,是可以大大提升图像表现效果的技术。我们先来感性的认识一下各向异性过滤。之前说线性过滤是各项同性,与之相对的就是各向异性。屏幕的xy轴和贴图的uv轴通常是不平行的,也就是说x轴移动一个像素,uv轴移动纹素的个数是不一致的。比如我们看一个箱子的正面,面对你的面就是各项同性,所以贴图很清晰。但是箱子的顶部,这个面的法线和视线的夹角越大,图像越模糊,极端情况下这个面就会变成一条直线,这时候贴图的采样就会丢失一个维度。各向异性过滤就是为了解决这个问题。

如上图一个屏幕像素它覆盖的区域并不是一个正方形,而是一个不规则的四边形。正确的过滤应该是把覆盖的像素都取出来加权平均。可以看到S和T轴跨越的纹素个数不同(各项异性)。各项异性实现的算法不统一,我就挑重点来说。首先各项异性采样点的数量是动态变化的,不是说开了8x每次都采样8个。因为带宽的限制,算法一般都会根据每个轴的偏微分,动态决策采样多少纹素。

Px和Py分别代表uv坐标在x方向的偏微分,说人话就是x移动一个像素,uv坐标移动多远的距离。N就是采样的次数可以看到它是根据Px和Py动态变化的。确定N和lod层,就可以使用如下公式进行混合了:

这里只有这个偏微分需要解释一下,我们在PS中如何求解偏微分?使用ddx和ddy函数即可,我发现国内网站基本上对这两个函数的理解都是错误的。。。

首先我们在PS中传入并非是一个像素而是四个像素,因此我们就可以使用右边的像素减去左边的像素获得x方向上的微分。用下面的像素减去上面的像素获得y方向的微分。这里大家理解的都是正确的,关键是这个函数的参数传入的是什么,有的人解释是PS输入参数,比如uv坐标,法线,颜色等等。ddx就是取相邻像素的uv坐标或者法线等属性的差。这个理解是错误的。这里的参数可以是任何表达式,任何变量。gpu每次会并行计算四个像素的ps代码,比如在调用ddx函数之前你调用了uv' = uv * 2,然后调用ddx(uv'),这个时候每一个像素都会计算uv'然后取其差,这个在并行计算中是很容易理解的,我们之前写的代码都是串行所以可能会理解错误。

各项异性过滤很重要也很耗资源,通常我们希望使用硬件加速处理。虚拟贴图为了支持各向异性采样将边界像素扩充到4,然后使用硬件采样。由于不同的硬件支持的情况不同,可能会有一些特殊的设备需要我们自己在ps中处理各项异性。这个就只能具体问题具体分析了。

最后如果我们使用硬件虚拟贴图,那么这个采样问题就不是问题了。图形工作就是这样,软件驱动硬件的发展,硬件发展了,之前很多软件的工作都不需要做了(其实是显卡和图形API的工程师它们做了哈哈)。但是随着效果的提升,又会出现很多算法去弥补硬件的不足,图形工程师就是要活到老学到老。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值