1.镜面-镜面光线传输计算
只涉及主光线计算而渲染出来的图像无法真实表现现实中的光线照射,通过增加能够反射光线的材质,进行空间中具有反射材质的对象之间的反射光线的追踪,可以更好地体现真实感。
2.光线镜面反射的计算
当光线与包含反射材质的物体进行碰撞后,计算反射方向,追踪计算得到的反射光线即可,因为光线可能在空间中无限的反射下去,为了避免这种情况,一般定义一个最大的追踪深度。根据反射光线与空间的交互可能存在的四种情况,分别返回相应的结果:
- 反射光线没有碰撞到任何物体,直接返回背景颜色
- 反射光线碰撞到漫反射材质对象,则返回漫反射材质对象上该点处的颜色
- 反射光线碰撞到镜面反射材质对象,则继续追踪碰撞点产生的光线,将追踪的结果返回
- 光线与光源碰撞,直接返回光源的颜色
3.一个典型的渲染结果
在场景中,一个水平面上放置两个球体,红色球体拥有镜面反射材质,另一个则为漫反射材质,渲染结果如图所示:
镜面反射着色代码:
Color Reflective::Shade(const ShadeRecord& shade_rec) const
{
Color color(Phong::Shade(shade_rec));
Vector3f in_dir;
Vector3f out_dir = -shade_rec.ray_.dir_;
HitRecord hit_rec = shade_rec.hit_rec_;
Color refl_color = refl_func_.SampleF(shade_rec.hit_rec_, in_dir, out_dir);
Ray refl_ray(shade_rec.hit_rec_.p_hit_, in_dir);
color += refl_color * shade_rec.world_.tracer_->TraceRay(shade_rec.world_, refl_ray, hit_rec.depth_ + 1)
* Dot(in_dir, shade_rec.hit_rec_.n_hit_);
return color;
}
场景设置代码:
std::shared_ptr<World> Build()
{
std::shared_ptr<World> world = std::make_shared<World>(std::make_shared<RayCast>());
world->AddLight(std::make_shared<PointLight>(Point3f(400, 400, -200), 3.0));
world->AddSurface(std::make_shared<Sphere>(Point3f(50, 0, -500), 50,
std::make_shared<Reflective>(Color(256.0 / 256.0, 20.0 / 256.0, 20.0 / 256.0),
0.4, 0.6, 20, 0.2)));
world->AddSurface(std::make_shared<Sphere>(Point3f(0, -20, -400), 30, Color(25.0 / 256.0, 25.0 / 256.0, 112.0 / 256.0)));
world->AddSurface(std::make_shared<Plane>(Point3f(0, -50, 0), Normal3f(0, 1, 0), Color(0.3, 0.3, 0.3)));
return world;
}