GAMES202 作业1-part2

应老师要求不会直接放上作业答案,会记录整体思路和核心代码

PCF

主要步骤

  1. 获取shadow map和对应的坐标
  2. 设置filter和随机采样的数目
  3. 使用泊松分布采样
  4. 判断每个采样点的shadow map值
  5. 进行累加求平均
1
2
3
4
5
// 修改了老师给的函数的签名,新增了一个参数,其实按照pdf的说明,加了这个参数才比较合理
float PCF(sampler2D shadowMap, vec4 coords, float filter_size)

// filter_size是根据图片大小来的,这里是1.0/2048.0,可以根据实际需求乘以2.0-10.0
// 随机采样的样本数目是通过glsl文件开头的NUM_SAMPLES进行修改的

接着使用泊松分布

1
2
// 泊松分布采样,采样输出的范围会很大很可能覆盖整张图
poissonDiskSamples(coords.xy);

然后通过每个对采样点进行判断累加结果

1
2
3
4
5
6
7
8
9
for(int i = 0;i < PCF_NUM_SAMPLES; i++){
// 因为shadowmap和归一化之后的坐标都是在[0,1]之前,因此需要filter_size对泊松分布的输出进行 // 缩小,不然会出现全屏黑点的效果
vec2 temp = poissonDisk[i] * filter_size + coords.xy;
float depth_decode = (unpack(texture2D(shadowMap, temp)));
if(depth_decode>coords.z - bias)
depth_sum += 1.0;
else
depth_sum += 0.0;
}

得到效果如下

PCSS

PCSS主要步骤:

  1. blocker search
    1. 进行泊松分布采样
    2. 和当前uv的深度进行对比、
    3. 判断是否有遮挡
  2. 计算比值
  3. 通过PCF创建软阴影
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// blocker search核心的思路
for(int i=0;i<NUM_SAMPLES; i ++){
vec2 simpleUV = uv +poissonDisk[i] * (zReceiver-0.01)/zReceiver;
float shadowMapDepth = unpack(texture2D(uShadowMap,simpleUV));
if(zReceiver > (shadowMapDepth+EPS)){
average_depth += shadowMapDepth;
count +=1;
}
}
//没有遮挡,但是想让效果看着柔和些
if(count == 0){
return 0.3;
}

average_depth /= float(count);
1
2
3
4
5
6
7
8
9
// PCSS函数
float PCSS(sampler2D shadowMap, vec4 coords){
// STEP 1: avgblocker depth
float blocker_depth = findBlocker(shadowMap, coords.xy, coords.z);
// STEP 2: penumbra size
float penumbra = (coords.z-blocker_depth)*LIGHT_WIDTH/blocker_depth;
// STEP 3: filtering
return PCF(shadowMap, coords, 1.0/2048.0 * 5.0 * penumbra);
}

优化效果

开始的时候PCF和PCSS效果如下,可以看得出特别糊

通过修改NUM_SAMPLES进行优化,从20调到了60