Thinhole类说白了就是在眼睛处,放一个放大镜。就像我们平时用放大镜观察物体一样。这样实现的效果的是,周围会模糊。原理书上都说的很清楚了,我把算法截图下来了。这个应用我猜测是在竞技游戏比如csgo中,狙击开镜后效果。具体等之后开发游戏时,再测试一下。如下:
类声明:
#pragma once #ifndef __THINLENS_HEADER__ #define __THINLENS_HEADER__ #include "camera.h" class Sampler; class Thinlens :public Camera { public: Thinlens(); ~Thinlens(); Thinlens(const Thinlens& tl); void set_view_distance(const ldouble a); void set_focal_distance(const ldouble a);//这个是放大镜的系数,我默认是取0.8,因为我用的物体是1个像素,比较小。 void set_lens_radius(const ldouble rad);//放大镜的半径 void set_zoom(const ldouble factor);//缩放 void set_angle(const ldouble deg);//旋转角 void set_sampler(Sampler* const sampler);//随机采样数组,实现模糊效果 Vector3 ray_direction(const Point3& pixel_point, const Point3& lens_point) const; virtual Camera* clone() const; virtual void render_scene(World& w); Thinlens& operator=(const Thinlens& tl); private: ldouble lens_radius, d, f, zoom; Sampler* sampler; }; #endif
类实现
#include "pch.h" #include "thinlens.h" #include "../utilities/world.h" #include "../utilities/viewplane.h" #include "../samplers/sampler.h" #include "../tracers/tracer.h" Thinlens::Thinlens() :Camera(), lens_radius(0.5), f(0.8), d(1), zoom(1), sampler(nullptr) {} Thinlens::~Thinlens() { if (sampler) delete sampler; } Thinlens::Thinlens(const Thinlens& tl) :Camera(tl), lens_radius(tl.lens_radius), f(tl.f), d(tl.d) , zoom(tl.zoom), sampler(tl.sampler) {} void Thinlens::set_view_distance(const ldouble a) { d = a; } void Thinlens::set_focal_distance(const ldouble a) { f = a; } void Thinlens::set_lens_radius(const ldouble rad) { lens_radius = rad; } void Thinlens::set_zoom(const ldouble factor) { zoom = factor; } void Thinlens::set_angle(const ldouble deg) { ldouble rad = radian(deg); up = Point3(std::cos(rad) * up.x - std::sin(rad) * up.y, std::sin(rad) * up.x + std::cos(rad) * up.y, up.z); } void Thinlens::set_sampler(Sampler* const sam) { if (sampler) { delete sampler; sampler = nullptr; } sampler = sam; sampler->map_to_unit_disk(); } Vector3 Thinlens::ray_direction(const Point3& pixel_point, const Point3& lens_point) const { Point3 p; p.x = pixel_point.x * d * f; p.y = pixel_point.y * d * f; Vector3 dir = (p.x - lens_point.x) * u + (p.y - lens_point.y) * v - f * w; dir.normalize(); return dir; } Camera* Thinlens::clone() const { return new Thinlens(*this); } void Thinlens::render_scene(World& w) { Ray ray; ViewPlane vp(w.vp); integer depth = 0; Point3 sp, pp, lp; w.open_window(vp.hres, vp.vres); vp.s = 1 / (vp.s * zoom); for (integer r = vp.vres - 1; r >= 0; r--)//render from left-corner to right-corner for (integer c = 0; c < vp.hres; c++) { RGBColor color; for (integer p = 0; p < vp.nsamples; p++) { sp = vp.sampler->sample_unit_square(); pp.x = (c - 0.5 * vp.hres + sp.x) * vp.s; pp.y = (r - 0.5 * vp.vres + sp.y) * vp.s; lp = sampler->sample_unit_square() * lens_radius; ray.o = eye + lp.x * u + lp.y * v; ray.d = ray_direction(pp, lp); color += w.tracer_ptr->trace_ray(ray); } color /= vp.nsamples; color *= exposure_time; w.display_pixel(r, c, color); } } Thinlens& Thinlens::operator=(const Thinlens& tl) { if (this == &tl) return *this; Camera::operator= (tl); lens_radius = tl.lens_radius; d = tl.d; f = tl.f; zoom = tl.zoom; sampler = tl.sampler; return *this; }
需要修改的World类:
void World::build() { vp.set_hres(200); vp.set_vres(100); vp.set_sampler(new Hammersley()); vp.sampler->map_to_sphere(); tracer_ptr = new MultiSphere(this); Geometrics* obj = new Sphere(0, 0.5); obj->set_color(RGBColor(1, 0, 0)); add_object(obj); obj = new Sphere(Point3(0, -100.5, 0), 100); obj->set_color(RGBColor(0, 0, 1)); add_object(obj); Thinlens* thinlens = new Thinlens(); thinlens->set_eye(Point3(0, 0, 1)); thinlens->set_lookat(Point3(0)); thinlens->set_view_distance(1.5); thinlens->set_sampler(new MultiJittered());//书上是采用多重采样,可以替换为其他采样。不过这个采样效果是比较好的。 thinlens->set_angle(-45); //thinlens->set_zoom(2.0); thinlens->compute_uvw(); set_camera(thinlens); }
测试效果图(蓝色和黑色部分已经模糊了,算法测试成功!):