GAMES202 作业1-part1

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

Two Pass Shadowmap

主要实现硬阴影,在shadowmap作业中需要修改的地方有两个

DirectionalLight.js中CalcLightMVP()函数

MVP函数的参数签名如下

CalcLightMVP(translate, scale){}

首先需要做的是根据translate和scale进行model transform

1
2
3
4
5
6
7
// 主要使用的两个函数
// scale中a表示变换完之后存储的地方,b表示原矩阵,c表示变换
mat4.scale(a, b, c);
// 示例
mat4.scale(modelMatrix, modelMatrix, scale);
// translate同理
mat4.translate(a, b, c);

接着是view transform,这里是根据提供的lightPos,focalPoint和lightUp进行lookat矩阵的构造

1
2
3
4
5
6
// lookAt函数
// a - 存储结果
// b - light position
// c - focal point
// d - light up
mat4.lookAt(a,b,c,d);

最后是投影矩阵,根据作业提示推荐使用了正交投影

1
2
3
4
5
6
// 投影矩阵设置
// a - 存储结果
// l, r - 控制矩阵左右
// b, t - 控制上下
// n, f - 控制远近
mat4.ortho(a,l,r,b,t,n,f);

phongFragment.glsl中useShadowMap()函数

首先通过shadowCoord获取坐标并通过texture2D()进行采样

vec4 depth_raw =texture2D(shadowMap,shadowCoord.xy);

接着通过unpack函数对depth进行decode

float depth_decode =unpack(depth_raw);

然后通过跟shadowCoord.z的值进行深度比较得到阴影

if(depth_decode > shadowCoord.z)

在main中对坐标进行NDC操作并传入函数,得到结果

1
2
3
4
5
 	// NDC
vec3 projCoords = vPositionFromLight.xyz / vPositionFromLight.w;
// 范围从[-1,1]转到[0,1]
vec3 shadowCoord = projCoords * 0.5 + 0.5;
visibility = useShadowMap(uShadowMap, vec4(shadowCoord, 1.0));

出现如下错误原因是model transform顺序设置问题,本来操作应该是先缩放,再旋转,最后平移。但是这里是先translate,再scale(原因是将光源当作相机生成深度图,但是变换的时候本来思路是从原点变换到光源位置,但是在view transform的思路是逆变换,因此需要反过来) — 这里可能理解有误,mark一下,因为和朋友直接手写变换矩阵的时候按照SRT的顺序是对的

修改后如下

另一个需要优化的地方是阴影周围的锯齿,通过添加bias的方法,可以让整个阴影更加平滑。

1
2
3
4
5
6
7
8
9
float getBias(){
// 解决自遮挡问题 -- 主要由shadow map精度导致
// 第一个pass在渲染shadow map的时候会将场景离散化,但是shadow map精度有限因此记录不会很准去,
// 在第二个pass进行判断的时候,就可能会有多个fragment对应到shadow map的同一个位置
vec3 lightDir = normalize(uLightPos);
vec3 normal = normalize(vNormal);
float bias = max( 0.003 *(1.0 - dot(normal, lightDir)), 0.0003);
return bias;
}