设想一个超大地表,而地表的贴图精度也要求非常大,如4096,8192,如果将这种精度的纹理加载进内存,显然是会造成严重的内存问题或者在移动端也会产生兼容性问题。
虚拟纹理是为了解决此类问题相处的一套方案。
这篇文章基于我个人对于虚拟纹理的理解整理了部分实现上的细节。
1、将地表从XZ视角拆成n个tile,每个tile大小为TW,TH,行TR个,列TC个。、
2、定义虚拟纹理是由m个block组成,每个block大小为BW,BH,行BR个,列BC个。
3、我们实际上要做的就是将相机里地块(tile)映射到虚拟纹理中。
4、实践中,还需要根据不同tile离相机的远近,会需要计算不同tile的mipmap level,这样可以减少采样率问题造成的效果失真等问题。
5、基于上述4点,从有了虚拟纹理后如何渲染地表反向推导数据结构与实践会容易理解些。
设想在渲染时,frag的世界坐标PosW相对来说容易获取。在得到PosW后,根据其x与z分量计算得到tileIndex同时可以计算得到该坐标再tile下的uv,接着如果能知道该tile对应再虚拟纹理中的block,那么通过简单的+与*就可以得到其实际的uv再做采样即可,接下来我就逐句拆解实现方式:
1、根据其x与z分量计算得到tileIndex:考虑x(z类似做法),tileIndexX=x/TW.
2、同时可以计算得到该坐标再tile下的uv(tile):考虑x(z类似做法)u(tile) = (x%TW)/TW.
3、接着如果能知道该tile对应再虚拟纹理中的block:这里排除掉渲染时怎样剔除tile,我默认有一个tile列表(tile1,tile2...tilei). 那么再获取这个列表后,我们需要将地表贴图这些tile填充到虚拟纹理中(涉及到怎样设置RT,然后只渲染一个rect等就不多说了)就可以得到一个对应block列表(block1,block2...blocki) (m的数量大于n,保证地表所有块都能正常显示).
4、那么通过简单的+与*就可以得到其实际的uv再做采样即可: 这里实际上会涉及到怎样将3中的映射做存储mapi(tileIndex,blockIndex),创建一大小为n的数组,索引代表tileIndex,值代表blockIndex。这样在利用pos算出tileIndex后,即可得到blockIndex,在利用BW,BH,就可以算出实际在虚拟纹理中的uv(vt):u(vt)=(blockIndex * BW + u(tile) * BW)(BW*BR)。
总结:虚拟纹理虽然能让在地表上支持大分辨率贴图,但块剔除与数据的组织在CPU实际上也有一些开销,对于cpubounds的情况要注意衡量带来的负面影响。