• Thinhole类声明和实现


    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);
    }
    

      

    测试效果图(蓝色和黑色部分已经模糊了,算法测试成功!):

  • 相关阅读:
    彻底弄懂类设计原则之 单一职责原则
    CF1592F1 Alice and Recoloring 1
    CF1592E Bored Bakry
    AT1218 たのしい家庭菜園
    CF1479A Searching Local Minimum
    P3295 [SCOI2016]萌萌哒
    CF1572B Xor of 3
    项目开发和管理需要弄清楚的6个问题
    PowerDesigner中如何生成主键和自增列Oracle版本
    js获取下拉框的选中值和文本值,后台获取用Request["XXXX"]即可
  • 原文地址:https://www.cnblogs.com/dalgleish/p/12650968.html
Copyright © 2020-2023  润新知