OpenGL阴影采样器


  在 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。如果要使用阴影采样器,以下是产生世界坐标下深度值必须要注意的三件事:

  • 用光源的 projection 矩阵和 view 矩阵乘上世界坐标。
  • 手动进行透视除法,除以 w 分量。
  • 要将 CVV 坐标转换到 [0, 1] 范围内。因为 OpenGL 乘 MVP 矩阵后的空间是属于 [-1, 1] 空间中的。如果使用了 glDepthRange() 函数设定范围,则自行调整。

  为了避免在 shader 中反复线性变换到 [0, 1] 范围内,其实可以使用 MVP 矩阵乘上一个变换矩阵,直接生成 [0, 1] 范围内的坐标。因为光源的 MVP 矩阵乘上世界坐标后不会经过 gl_Position,也就不需要担心兼容问题。所以光源的 MVP 矩阵可以变成

$$\\displaystyle L=BPVM $$
  其中,$$B$$ 等于

$$\\displaystyle \\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}$$


  最后,将采样结果输出,可以得到下面的图。

shadow sampler


转载请带上本文永久固定链接:http://www.gleam.graphics/shadow-sampler.html

Tags :

About the Author

说点什么

您将是第一位评论人!

avatar