【简介与代码】
本文将实现景深的效果,也即给相机定义一个焦距,在这个焦距范围外的就模糊,在这个焦距处就清晰。
效果如下:
代码使用VS2015编译从如下下载:
链接:https://pan.baidu.com/s/1807dLqlfisxJO3Q9mNNdBQ
提取码:xwbw
【实现原理】
首先一改之前的由eye发出射线精准求交的方式:
这样求出来的光线非常准确。那么我们对光线的生成模拟相机的操作改成如下形式:
这里要好好的解释一下,对于一个像素实施光线追踪,为了反走样随机生成了100条光线然后求平均(在main函数里定义的100条光线),最终和到一个像素的值。那么这100条光线的走点我们让它随机分布在一个直径为aperture的圆上,聚焦点在离光线起点dist_to_focus的面上。那么我们可以得到如上图一样的结果,所以的光线在成像平面处交于一点。假如物体在呈像平面处,则会很精晰,假如靠前或靠后,都会模糊,因为100条光线与物体交的五花八门,而不是精确于一点了。假如物体在焦距处,则就是精确于一点的。这一点好好理解才能理解景深的光线生成代码:
ray get_ray(float s, float t)
{
vec3 rd = lens_radius * random_in_unit_disk();
vec3 offset = u*rd.x() + v*rd.y();
return ray(origin+offset, unit_vector(lower_left_corner + s*horizontal + t*vertical - origin-offset));
}
这里是关键,假如无法理解,可以在下方留言。
随着dist_to_focus焦距的拉长,我们生成画面的范围也在扩大,这是在定义视域范围的时候定义的:
camera(vec3 lookfrom, vec3 lookat, vec3 vup, float vfov, float aspect, float aperture, float focus_dist)
{
//光圈半径
lens_radius = aperture / 2;
float theta = float(vfov * M_PI / 180);
float half_height = tan(theta / 2);
float half_width = aspect * half_height;
origin = lookfrom;
w = unit_vector(lookfrom - lookat);
u = unit_vector(cross(vup, w));
v = cross(w, u);
lower_left_corner = origin - half_width *focus_dist* u - half_height*focus_dist * v - focus_dist*w;
horizontal = 2 * half_width*focus_dist*u;
vertical = 2 * half_height*focus_dist*v;
}
注意lower_left_color的生成方式,长宽都乘了个focus_dist。