总览
本轮作业中,我们需要在一个光源为方向光,材质为漫反射 (Diffuse) 的场景中,完成屏幕空间下的全局光照效果(两次反射)。
为了在作业框架中实现上述效果,基于我们需要的信息不同我们会分三阶段着色,每个阶段都有相对应的任务。
- 第一次着色负责计算 Shadow Map 所需的深度值并保存到贴图中。
- 第二次着色负责计算屏幕空间中,每个像素对应的世界坐标系下位置、世界坐标系下法线、漫反射反射率和可见性信息并最终保存到对应贴图中。
- 第三次着色基于之前得到的场景几何信息 (像素对应的位置,法线),场景与光源的遮挡信息 (光源坐标系的深度值),场景的材质信息 (漫反射反射率),来计算两次反射的全局光照结果。
流程
对于本次实验,有如下三个任务点需要依次完成:
- 实现对场景直接光照的着色 (考虑阴影)。
- 实现屏幕空间下光线的求交 (SSR)。
- 实现对场景间接光照的着色。
如果你能确保每一步完成正确,最终我们可以得到质量不错的光照效果!
直接光照
熟悉如何使用提供的函数,以及GBuffer信息。
你需要实现位于 shaders/ssrShader/ssrFragment.glsl 文件中的 EvalDiffuse(wi, wo, uv) 和 EvalDirectionalLight(uv) 函数,并在 main 函数中实现直接光照的效果。
- 以下的 uv 表示着色点的屏幕空间坐标,即值域为 [0, 1]2。
- EvalDiffuse(wi, wo, uv) 函数的返回值为 BSDF1 的值。参数 wi 和 wo 为世界坐标系中的值,分别代表入射方向和出射方向,需要注意的是,这两个方向的起点都为着色点。在这一步中你会需要: 漫反射率和法线信息。我们提供了 GetGBufferDiffuse(uv) 和 GetGBufferNormalWorld(uv) 来获取漫反射率和法线。这里需要注意,GetGBufferDiffuse(uv) 返回的值是在线性空间的,GetGBufferNormalWorld(uv) 得到的法线是在世界坐标系的。为了获取屏幕空间的坐标,我们提供了 GetScreenCoordinate(posWorld) 函数,它的参数为世界坐标系中的位置。

BRDF = F G D / 4 (n,i) (n,o)
菲涅尔项、法线分布项、几何(遮蔽)项
输入:入射方向wi、出射方向wo、屏幕空间像素uv
菲涅尔项
有多少能量被反射取决于入射光的角度,如果入射角接近掠角grazing angle(入射方向和法线几乎垂直),这种情况下反射是最多的。
BRDF和光线传播都是可逆的。 入射和出射可以互换。菲涅尔项与PBR本身的性质有关(dielectric绝缘体和conductor导体) 菲涅尔项告诉我们有百分之多少的能量会被反射掉。
在物理上有非常复杂的表示,会考虑光线的s极化、p极化 考虑从空气到介质的折射率、考虑入射角。

vec3 F0 = GetGBufferDiffuse(uv);
vec3 h = normalize(wi + wo);
vec3 v = wi;
vec3 Fresnel_term = F0 + (vec3(1.0) - F0) * pow((vec3(1.0) - (h * v)),vec3(5.0));
发现有些vec3运算不需要强制设置vec3类型
简化后
vec3 F0 = GetGBufferDiffuse(uv);
vec3 h = normalize(wi + wo);
vec3 v = wi;
vec3 Fresnel_term = F0 + (1.0 - F0) * pow((1.0 - (h * v)),vec3(5.0));
法线分布项
如果微表面的法线分布集中,就说明微表面法线变化不明显,也就说明法线都差不多,也就是表面比较平坦。可以得出近似glossy,如果非常集中,就是specular。
如果把微表面的高度场拉大,等于所有面都被拉得倾斜了,使得normal的分布变化越来越明显。
vec3 alpha = F0;
vec3 n = GetGBufferNormalWorld(uv);
vec3 NDF_div = pow(pow(n * h,vec3(2.0)) * (pow(alpha,vec3(2.0)) - 1.0) + 1.0, vec3(2.0));
vec3 NDF_GGXTR = pow(alpha,vec3(2.0)) / (M_PI * NDF_div);
几何遮蔽项
解决微表面之间自遮挡的问题。 从光线出发,被遮挡叫shadowing;从眼睛(微表面)出发,被遮挡叫masking
经过自遮挡,微表面被遮挡的部分肯定不能那么亮,这一项就是为了进行变暗的操作。从上往下看基本不需要做这个操作,在grazing angle要让它变暗很多。
alpha = pow(( alpha + 1.0 ) * 0.5, vec3(2.0));
vec3 k = alpha * 0.5;
vec3 G1L = (n * wo) / ( (n * wo) * (1.0 - k) + k);
vec3 G1V = (n * wi) / ( (n * wi) * (1.0 - k) + k);
vec3 Graphic_term = G1L * G1V;
BRDF结果
BRDF = F G D / 4 (n,i) (n,o)
vec3 EvalDiffuse(vec3 wi, vec3 wo, vec2 uv) {
vec3 L = vec3(0.0);
// 菲涅尔项
vec3 F0 = GetGBufferDiffuse(uv);
vec3 h = normalize(wi + wo);
vec3 v = wi;
vec3 Fresnel_term = F0 + (1.0 - F0) * pow((1.0 - (h * v)),vec3(5.0));
// 法线分布项
vec3 alpha = F0;
vec3 n = GetGBufferNormalWorld(uv);
vec3 NDF_div = pow(pow(n * h,vec3(2.0)) * (pow(alpha,vec3



最低0.47元/天 解锁文章
1140

被折叠的 条评论
为什么被折叠?



