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

  

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

Thinhole类声明和实现的更多相关文章

  1. EC笔记,第二部分:7.为多态基类声明虚析构函数

    7.为多态基类声明虚析构函数 1.为多态基类声明虚析构函数 code1: class A{ public: int* a; A():a(new int(5)) {} ~A(){ delete a; } ...

  2. C++ 中的模板类声明头文件和实现文件分离后,如何能实现正常编译?

    C++ 中的模板类声明头文件和实现文件分离后,如何能实现正常编译? 这个feature叫做Export Template,即外名模板,它的作用在于使得模板代码可依照C/C++语言习惯,将模板声明和实现 ...

  3. [Effective C++ --007]为多态基类声明virtual析构函数

    引言: 我们都知道类的一个很明显的特性是多态,比如我们声明一个水果的基类: class Fruit { public: Fruit() {}; ~Fruit(){}; } 那么我们根据这个Fruit基 ...

  4. c++,基类声明的指针变量和引用类型变量可以指向派 生类的对象

    基类声明的指针变量和引用类型变量可以指向派生类的对象,而反过来派生类的指针却不能指向基类变量. 这与基类和派生类之间,被允许的赋值方向是相反的. 但是从逻辑上很容易推敲其合理性.

  5. error C2248: “CObject::operator =”: 不可访问 private 员(于“CObject”类声明)

    MFC如果编码错误: 演出:error C2248: "CObject::operator =": 不可访问 private 员(于"CObject"类声明) ...

  6. 类声明、类作用域、前向声明、this指针、嵌套类、PIMPL 技法 等

    一.类声明 //类是一种用户自定义类型,声明形式: class 类名称 {    public:              公有成员(外部接口)    private:              私有 ...

  7. C++模板类内友元(友元函数,友元类)声明的三种情况

    根据<C++ Primer>第三版16.4节的叙述,C++类模板友元分为以下几种情况 1.非模板友元类或友元函数. 书上给了一个例子: class Foo{     void bar(); ...

  8. Pinhole类声明和实现

    针孔相机,带旋转,移动等功能. 类声明: #pragma once #ifndef __PINHOLE_HEADER__ #define __PINHOLE_HEADER__ #include &qu ...

  9. 07——为多态基类声明为virtual析构函数

    当基类确定被继承的时候,析构函数声明为virtual是必须的 当返回的派生类的指针或引用的时候,调用析构函数容易发生内存泄漏 当基类作为抽象类使用,声明pure virtual析构函数 析构函数的顺序 ...

随机推荐

  1. 144_Power Pivot贷款之等额本息与等额本金

    博客:www.jiaopengzi.com 焦棚子的文章目录 请点击下载附件 一.背景 买房贷款的时候会遇到等额本息与等额本金的问题,今天做了一个两者对比,看看如何选择,来一张对比图. 等额本息的前期 ...

  2. JavaSE_关键字 接口 代码块 枚举

    1 Java中的关键字 1.1 static关键字 static特点 : 静态成员被所在类的所有对象共享 随着类的加载而加载 , 优先于对象存在 可以通过对象调用 , 也可以通过类名调用 , 建议使用 ...

  3. 羿网通WT2100网络测试仪端口开关功能应用案例

    端口开关是羿网通WT2100具备的一项全局性的功能,使用客户端软件Packlark连接WT2100后无需进入具体功能即可使用.该功能是通过控制设备上的以太网开关实现快速.便捷地切换网口通断状态的目标, ...

  4. 修改mysql数据库存储路径

    最近一段比较忙,所以一直没有及时的更新总结一下测试路上遇到的问题,今天先来分享一下如何修改mysql存储路径(场景:在自己电脑上搭建的服务器上安装mysql,二.在公司自己的服务器上搭建mysql数据 ...

  5. QT 基于QScrollArea的界面嵌套移动

    在实际的应用场景中,经常会出现软件界面战场图大于实际窗体大小,利用QScrollArea可以为widget窗体添加滚动条,可以实现小窗体利用滚动条显示大界面需求.实现如下: QT创建一个qWidget ...

  6. 开发工具-Base64编码/解码

    更新日志 2022年6月10日 新增链接. https://toolb.cn/base64

  7. 使用Node.js还可以发邮件

    前言 今天,我们给大家开发一个小效果.篇幅比较短,主要给大家展示效果.实战 首先我们初始化一个Node项目 npm init -y 创建一个app.js文件 'use strict'; const n ...

  8. RPA应用场景-自动轮询汇总报表

    场景概述 自动轮询汇总报表 所涉系统名称 券商披露网站 人工操作(时间/次) 36小时 所涉人工数量 1 操作频率 每月 场景流程 1.每月初机器人自动登录网站轮询36家券商披露的财务报告,并下载 2 ...

  9. jQuery获取市、区县、乡镇、村

    效果图: 首先根据自己方法把地区树状结构json字符串拿到 html下拉框和js写法如下: <select class="form-control" style=" ...

  10. 解决github.com 的响应时间过长以及hosts配置不能保存的问题

    github.com 的响应时间过长 1 获取github可以使用的DNS域名 DNS查询 选择TTL值最小的 2 修改hosts配置 打开之后在最后加上如下内容,保存即可 3 出现hosts不能保存 ...