Shadow Mapping
Shadow Mapping是上古时期提出的阴影计算的方式.
不过多介绍,LearnOpengl中提到的阴影.
PCF
percentage-closer filtering
1 | float shadow = 0.0; |
PCF的滤波半径决定了阴影边缘的柔和程度,一般来说滤波半径越大则柔和,相反阴影边缘越锐利.
由此启发了PCSS(Percentage Close Soft Shadow)软阴影算法的核心原理,对于那些我们需要实现软阴影的边缘用更大的滤波半径进行滤波,而对于那些不需要太过柔和阴影边缘的地方,则采用更小的滤波半径,这是一种自适应滤波半径的机制。
PCSS
PCSS的全称是Percentage Closer Soft Shadows,其灵感来源于PCF。从PCF的结果可以看出,我们在减少阴影锯齿的同时,产生了一种软阴影的效果。实际上在现实生活中,由于绝大部分的光源是面光源,我们见到的更多都是软阴影.
PCSS的本质,概括起来就是自适应PCF滤波半径的阴影贴图算法。其关键核心在于如何制定自适应滤波半径的机制。
step1
Blocker search: find the average blocker depth
个人理解:随机生成采样点,通过光源等确定一个滤波器大小.对这些点进行采样,然后平均.如果都在阴影,则返回0,如果都不在阴影就是1(没有阴影).其实就是看看是否在半影(Penumbra)内.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 poissonDiskSamples(projCoords.xy); //sampled from poisson distribution
float sampleStride = u_LightSize/2.5;
float dBlocker = 0.0;
float sampleSize = 1.0 / u_TextureSize * sampleStride;
int blockerNumSample = BLOCKER_SEARCH_NUM_SAMPLES;
float border = sampleStride / u_TextureSize;
// just cut out the no padding area according to the sarched area size
if (projCoords.x <= border || projCoords.x >= 0.99f - border) {
return 1.0;
}
if (projCoords.y <= border || projCoords.y >= 0.99f - border) {
return 1.0;
}
int count = 0;
for (int i = 0; i < blockerNumSample; ++i) {
vec2 sampleCoord = poissonDisk[i] * sampleSize + projCoords.xy;
float closestDepth = texture(u_DepthMap, sampleCoord).r;
//Only compute average depth of blocker! not the average of the whole filter's area!
if (closestDepth < currentDepth) {
dBlocker += closestDepth;
count++;
}
}
step2 Penumbra estimation
估计半影大小,已确定最后滤波大小
1 | // estimation the filter size to control the softness |
step3 Percentage Closer Filtering (PCF)
VSM
方差阴影映射(Variance Shadow Maps)
vsm 使用二阶距来判断深度差,由于使用Chebyshev,会出现light leaking光泄漏问题.就是因为维度不够,所以Moment Shadow Maps使用更高阶可以避免.
Chebyshev’s Inequality
e.g.
单边切比雪夫不等式
e.g.
e.g.
SAVSM
Summed Area Variance Shadow Maps
vsm直接使用了一个像素的depth和depth*depth,或者在加上blur..而savsm便是算真正的算积分.
SA见Summed Area Tables文章.
改进的也有在savsm上使用pcss的方法,也就是Penumbra.