在 glsl 版本 1.30 之前,没有能与 sampler2DShadow 配合的纹理采样函数。在 1.40 版本开始,可以使用 texture 系的函数对阴影采样器进行采样,输入参数为 CVV 空间的三维坐标。
要使用 sampler2DShadow,需要做两件事。第一,需要开启比较模式,否则会行为未定义。有 sampler 或者 texture 属性 GL_TEXTURE_COMPARE_MODE = GL_COMPARE_REF_TO_TEXTURE,还需要设定比较方式,与深度测试设置参数方法相同。第二,texture 函数采样输入值为三维变量,前面两个值与纹理坐标无异,第三个坐标为待比较的深度值。
对 sampler2DShadow 使用 texture 后返回的值在 0.0 和 1.0 之间。如果设定的采样滤波为 nearest,则比较测试通过返回 1.0,否则返回 0.0;如果设定的采样滤波为 linear,则会选取采样点最近的四个像素,分别进行深度比较,可能返回 0.0、0.25、0.50、0.75、1.0 等值,表示通过测试和总像素数的比值。
其实使用线性滤波时, sampler2DShadow 比通常的 sampler2D 可以达到更好的抗锯齿效果。因为,sampler2DShadow 表示四个点的比值,而 sampler2D 只能得到一个单一的平均深度和一个布尔型,这对阴影锯齿来说并不理想。
阴影采样器的一个常用场景就是 shadow map。如果要使用阴影采样器,以下是产生世界坐标下深度值必须要注意的三件事:
为了避免在 shader 中反复线性变换到 [0, 1] 范围内,其实可以使用 MVP 矩阵乘上一个变换矩阵,直接生成 [0, 1] 范围内的坐标。因为光源的 MVP 矩阵乘上世界坐标后不会经过 gl_Position,也就不需要担心兼容问题。所以光源的 MVP 矩阵可以变成\displaystyle L=BPVM 其中,B 等于
\begin{bmatrix}
0.5&0&0&0.5 \\
0&0.5&0&0.5 \\
0&0.5&0&0.5 \\
0&0&0.5&1.0
\end{bmatrix}
最后,将采样结果输出,可以得到下面的图。