为什么需要无缝纹理?
当我们需要一张无限大或近似无限大的平面或一个无限大或近似无限大的空间时,我们可以选择使用分形的方法将一个简单的单元进行复制和拼接以完成扩展。
当这个单元具有一定的纹理时,就需要保证这个纹理是无缝(seamless)的,这样才能保证两个相邻的单元在拼接处不会出现明显接缝。
如何实现无缝
介绍这个问题之前首先需要了解Perlin Noise的生成原理,已经了解的读者可以自行跳过下面这一小节。
Perlin Noise 的原理
在Perlin Noise的生成过程中,我们引入晶格和梯度向量这两个概念
上面的左图可以很好地描述晶格和梯度向量的关系。晶格就是由横纵直线交织形成的网格,其上的每个交点处都有一个属性,此处的属性即每个顶点所代表的梯度向量。
当我们在初始化这个晶格的时候,可以逐交点地为每个点随机指定一个向量,即该交点所代表的梯度向量。通常地,为了保证最终计算的像素颜色在
[
0
,
1
]
[0,1]
[0,1]这个范围内,我们会控制这个梯度向量在单位圆内;为了减少最终产生的纹理中的“污点”(如下图),我们常用沿轴的向量作为梯度向量(二维的话就有四个,三维的话就有六个)。
上图演示的是使用随机向量产生的噪声纹理,可以看到这样计算的结果有明显的网格感;但如果使用沿轴线的向量作为梯度向量(方向随机但沿轴,长度为
1
1
1),则产生如下效果:
总而言之,我们按照一定的标准随机选取梯度向量,然后根据晶格及其包含的梯度向量计算每个像素的颜色。
具体怎么计算呢?
首先确定这个像素的位置位于晶格中的哪一块内(二维就是正方形,三维就是立方块),然后再获取其所在块的顶点(二维就是正方形的四个顶点,三维就是正方体的八个顶点)。让这一像素的坐标分别与其所在块的各顶点的坐标做差即得到由顶点到该像素的向量,再将该向量与对应顶点的梯度向量进行点积,两个顶点得到的点积依据它们的轴关系进行缓和曲线插值,最终得到该像素的颜色。
Perlin Noise的原理至此介绍完成!
让Perlin Noise变得无缝
说了上面这么多,总之就是一件事,噪声纹理中的每个像素是什么颜色只与与之相邻的晶格点有关!所以保证晶格的无缝特性即可让生成的噪声纹理具有无缝的特性。
晶格中的点所具有的梯度向量完全是随机的,所以不需要考虑它们之间的关系,那么只要保证晶格上界的梯度向量与晶格下界的梯度向量相同,晶格左界的梯度向量与晶格右界的梯度向量相同即可。
所以我们在随机的时候空出最后一行和最后一列,然后将首行和首列直接粘过来就好啦!
for (int u = 0; u < LatticeSize; u++)
{
grad[u] = new Vector2[LatticeSize + 1];
for (int v = 0; v < LatticeSize; v++)
grad[u][v] = g_base[Random.Range(0, 3)];
grad[u][LatticeSize] = grad[u][0];
}
grad[LatticeSize] = new Vector2[LatticeSize + 1];
for (int i = 0; i <= LatticeSize; i++) grad[LatticeSize][i] = grad[0][i];
这样就获得了边界具有无缝性质的晶格,那么我们以这个晶格为基础进行噪声纹理的计算就可以得到无缝的噪声了!
下面是计算得出的Perlin Noise纹理在进行了fbm之后产生的烟雾效果,使用上面方法产生的无缝纹理再通过fbm处理得到的纹理依然是无缝的!
到此为止这篇文章就结束了,喜欢的话就请点个赞吧!