所有 demo 和代码可以在 www.shadertoy.com/view/X3sBR7 查看
这段图像只用了不到 20 行的代码就完成了,原理就是使用到了纹理映射的方法。本篇将介绍纹理映射的基本概念,在下一篇中将具体介绍常见的纹理映射的常见方法
纹理映射是什么
让我们用地球仪来解释计算机图形中的纹理映射概念。想象一下,你有一个地球仪,它的表面是光滑的,并且覆盖着一张有各种国家、海洋和大陆图案的世界地图。这个地球仪就是我们的3D模型,而地图就是纹理。纹理映射是将2D图像(纹理)应用到3D模型(如地球仪)表面的过程。这就像是给地球仪“穿上”地图一样。
步骤1:理解UV坐标
首先,我们需要一种方法来确定地图上的哪些部分应该贴到地球仪的哪个位置。在计算机图形中,我们使用UV坐标来做到这一点。UV坐标类似于2D图像中的像素坐标,它们定义了纹理图像上的位置。
想象一下,我们把地图平铺在桌面上,然后给地图的每个角落和边缘分配UV坐标,比如:
- U=0, V=0(左下角)
- U=1, V=0(右下角)
- U=0, V=1(左上角)
- U=1, V=1(右上角)
步骤2:将纹理映射到地球仪
接下来,我们将地图“包裹”到地球仪上。这个过程就像是把一张纸包裹在一个球体上,纸的边缘可能会重叠或者拉伸。
-
平面投影:最简单的方法是将地球仪“展开”成一个平面,然后把地图贴到这个平面上。这就像是把地球仪的表面“压平”,然后在上面贴上地图。但这种方法在地球仪的两极和赤道附近可能会出现扭曲。
-
球面投影:为了更好地处理这种扭曲,我们可以使用球面投影。这种方法考虑了地球仪的曲率,将地图更自然地包裹在地球仪上。但即使如此,纹理的某些部分仍然可能会拉伸或压缩。
属性介绍
在 ShaderToy 中,ichan0, ichan1, ichan2, 和 ichan3 是用于访问纹理通道的变量。每个 ichan 可以对应一个纹理输入,通常用于将外部图像或纹理传递给当前的着色器程序。
可以看到对于每一个纹理有以上的几个配置。 在其他的引擎例如 three.js 也可以看到类似的配置。 其含义是
vflip
vflip 是一种翻转纹理在垂直方向上的处理方式。具体来说,这意味着将纹理的 y 坐标取反,从而使得纹理的内容上下翻转。在 ShaderToy 中,可以通过对纹理坐标进行计算来实现垂直翻转。
例如,如果你有一个纹理坐标 uv,翻转的操作将是:
uv.y = 1.0 - uv.y;
这样做可以确保在采样纹理时,从图像的底部开始采样,而不是从顶部开始。
wrap
在 three.js 也有 wraps和 wrapt. st表示 xy两个方向,定定义了纹理坐标超出[0,1]区间时的行为。通常有以下几种选项:
clamp:纹理坐标会被夹到最近的边缘。如下图 repeat:纹理坐标会重复。
Filter
在 ShaderToy 中,纹理的过滤(
texture.filter)配置主要有以下几种:
-
Nearest (最邻近过滤):
- 特点:这种过滤方式是直接选择离当前采样位置最近的纹理像素(texel)。如果采样位置在两个像素之间,直接选择其中一个。
- 适用场景:适用于像素化、马赛克效果或任何需要保持锐利边缘的效果。例如上面的图片
-
Linear (线性过滤):
- 特点:这种方式对包围采样位置的四个纹理像素进行线性插值,计算出一个平滑的颜色值。这样可以减少锯齿状的边缘,得到更柔和的效果。
- 适用场景:适用于需要平滑效果的图像,比如模糊、阴影等场合。
-
Mipmaps (多级渐远纹理):
- 特点:当使用多级渐远纹理时,随着纹理的缩小,ShaderToy会自动选择适当的纹理级别,通常结合线性过滤。这让远处的对象不会因为纹理加载不当而出现模糊或锯齿。
- 适用场景:适用于需要动态距离变化的纹理使用,比如3D场景中的素材。