光线追踪12 - Defocus Blur(虚焦模糊)

    现在我们的最后一个特性是虚化模糊。注意,摄影师通常称之为景深,所以请确保在光线追踪的朋友中只使用虚化模糊这个术语。
真实相机具有虚化模糊是因为它们需要一个大孔(而不仅仅是针孔)来收集光线。一个大孔会导致所有物体失去焦点,但是如果我们在胶片/传感器前放置一块透镜,就会出现一定距离上所有物体都能够聚焦的情况。放置在该距离上的物体将呈现出清晰,而距离该距离越远的物体将呈现出线性模糊。您可以这样理解透镜:所有来自焦点距离上特定点的光线,当碰到透镜时将被折回到图像传感器上的一个点。
我们将摄像机中心与一切都处于完美聚焦状态的平面之间的距离称为焦距。请注意,焦距通常与焦距长度不同-焦距长度是摄像机中心与图像平面之间的距离。然而,在我们的模型中,这两个值将相等,因为我们将将像素网格放在焦平面上,距离摄像机中心焦距远。
在实体相机中,焦距由镜头与胶片/传感器之间的距离控制。这就是为什么当您改变对焦物体时,镜头会相对于相机移动的原因(您手机相机可能也会出现这种情况,但是传感器移动)。"光圈"是控制镜头有效大小的孔洞。对于真实相机,如果需要更多光线,可以使光圈更大,并且远离焦距的物体将产生更多的模糊效果。对于我们的虚拟相机,我们可以拥有完美的传感器并且从不需要更多光线,因此只在需要虚化模糊时使用光圈。
13.1 A Thin Lens Approximation
一台真实的相机配备有复杂的复合镜头。对于我们的代码,我们可以按顺序模拟传感器、透镜和光圈的工作方式。然后我们可以确定光线的传播路径,并在计算完成后翻转图像(图像在底片上是上下颠倒的)。而图形专家通常使用薄透镜近似:

Figure 21: Camera lens model

为了渲染相机外部的图像,我们不需要模拟相机内部的任何部分,这将增加不必要的复杂性。相反,我通常从一个无限薄的圆形“lens”(镜头)开始发射光线,将它们发送到焦平面上感兴趣的像素位置(focal_length away from the lens 距离镜头焦距的位置),在那个平面上,3D世界中的所有物体都是完全聚焦的。
实际上,我们通过将视口放置在这个平面上来实现这一点。将所有内容整合起来:
焦平面垂直于相机视角方向。
焦距是相机中心与焦平面之间的距离。
视口位于焦平面上,以相机视角方向向量为中心。
像素位置的网格位于视口内部(位于3D世界中)。
随机图像样本位置从当前像素位置周围的区域选择。
相机从镜头上的随机点通过当前图像样本位置发射光线。

Figure 22: Camera focus plane


13.2 Generating Sample Rays

    没有虚化模糊时,所有场景光线都起源于相机中心(或lookfrom)。为了实现虚化模糊,我们构建一个以相机中心为中心的圆盘。半径越大,虚化模糊越明显。你可以将我们原始的相机看作具有半径为零的虚化圆盘(完全没有模糊),因此所有光线起源于圆盘中心(lookfrom)。
那么,虚化圆盘应该有多大?由于此圆盘的大小控制了我们获得的虚化模糊程度,这应该是相机类的一个参数。我们可以将圆盘的半径作为相机参数,但模糊程度将取决于投影距离。一个稍微简单一点的参数是指定以视口中心为顶点、以相机中心为底(虚化圆盘)的圆锥体的角度。这样,在变化焦距的情况下,可以获得更一致的结果。
由于我们将从虚化圆盘中选择随机点,因此需要一个函数来实现:random_in_unit_disk()。这个函数使用与random_in_unit_sphere()相同类型的方法,只是在二维平面上使用。

inline vec3 unit_vector(vec3 u) {
return v / v.length();
}inline vec3 random_in_unit_disk() {
while (true) {auto p = vec3(random_double(-1,1), random_double(-1,1), 0);if (p.length_squared() < 1)return p;}
}

Listing 79: [vec3.h] Generate random point inside unit disk


现在让我们更新相机,使光线起源于虚化圆盘:

class camera {public:
double aspect_ratio      = 1.0;  // Ratio of image width over height
int    image_width       = 100;  // Rendered image width in pixel count
int    samples_per_pixel = 10;   // Count of random samples for each pixel
int    max_depth         = 10;   // Maximum number of ray bounces into scene
double vfov     = 90;              // Vertical view angle (field of view)
point3 lookfrom = point3(0,0,-1);  // Point camera is looking from
point3 lookat   = point3(0,0,0);   // Point camera is looking at
vec3   vup      = vec3(0,1,0);     // Camera-relative "up" directiondouble defocus_angle = 0;  // Variation angle of rays through each pixel
double focus_dist = 10;// Distance from camera lookfrom point to plane of perfect focus...
private:int    image_height;    // Rendered image height
point3 center;          // Camera centerpoint3 pixel00_loc;     // Location of pixel 0, 0vec3   pixel_delta_u;   // Offset to pixel to the rightvec3   pixel_delta_v;   // Offset to pixel belowvec3   u, v, w;         // Camera frame basis vectorsvec3   defocus_disk_u;  // Defocus disk horizontal radiusvec3   defocus_disk_v;  // Defocus disk vertical radiusvoid initialize() {image_height = static_cast<int>(image_width / aspect_ratio);image_height = (image_height < 1) ? 1 : image_height;center = lookfrom;// Determine viewport dimensions.auto focal_length = (lookfrom - lookat).length();auto theta = degrees_to_radians(vfov);auto h = tan(theta/2);auto viewport_height = 2 * h * focus_dist;auto viewport_width = viewport_height * (static_cast<double>(image_width)/image_height);        // Calculate the u,v,w unit basis vectors for the camera coordinate frame.w = unit_vector(lookfrom - lookat);u = unit_vector(cross(vup, w));v = cross(w, u);        // Calculate the vectors across the horizontal and down the vertical viewport edges.vec3 viewport_u = viewport_width * u;    // Vector across viewport horizontal edgevec3 viewport_v = viewport_height * -v;  // Vector down viewport vertical edge// Calculate the horizontal and vertical delta vectors to the next pixel.pixel_delta_u = viewport_u / image_width;pixel_delta_v = viewport_v / image_height;// Calculate the location of the upper left pixel.auto viewport_upper_left = center - (focus_dist * w) - viewport_u/2 - viewport_v/2;pixel00_loc = viewport_upper_left + 0.5 * (pixel_delta_u + pixel_delta_v);// Calculate the camera defocus disk basis vectors.auto defocus_radius = focus_dist * tan(degrees_to_radians(defocus_angle / 2));defocus_disk_u = u * defocus_radius;defocus_disk_v = v * defocus_radius;
}ray get_ray(int i, int j) const {
// Get a randomly-sampled camera ray for the pixel at location i,j, originating from
// the camera defocus disk.auto pixel_center = pixel00_loc + (i * pixel_delta_u) + (j * pixel_delta_v);auto pixel_sample = pixel_center + pixel_sample_square();auto ray_origin = (defocus_angle <= 0) ? center : defocus_disk_sample();auto ray_direction = pixel_sample - ray_origin;return ray(ray_origin, ray_direction);
}...
point3 defocus_disk_sample() const {// Returns a random point in the camera defocus disk.auto p = random_in_unit_disk();return center + (p[0] * defocus_disk_u) + (p[1] * defocus_disk_v);
}color ray_color(const ray& r, int depth, const hittable& world) const {...
};

Listing 80: [camera.h] Camera with adjustable depth-of-field (dof)

使用大光圈:

int main() {
...
camera cam;
cam.aspect_ratio      = 16.0 / 9.0;
cam.image_width       = 400;
cam.samples_per_pixel = 100;
cam.max_depth         = 50;
cam.vfov     = 20;
cam.lookfrom = point3(-2,2,1);
cam.lookat   = point3(0,0,-1);
cam.vup      = vec3(0,1,0);cam.defocus_angle = 10.0;cam.focus_dist    = 3.4;
cam.render(world);
}

得到:


Image 22: Spheres with depth-of-field

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/729058.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

社交媒体革新者:揭秘Facebook对在线互动的影响

1. Facebook的兴起与发展 Facebook由马克扎克伯格在哈佛大学宿舍创建&#xff0c;最初只是服务于哈佛大学学生的社交网络。然而&#xff0c;其后快速扩张到其他大学和全球&#xff0c;成为了全球最大的社交媒体平台之一。其发展历程不仅是数字时代的典范&#xff0c;也是创业成…

CrySiS勒索病毒最新变种来袭,加密后缀为kharma

CrySiS勒索病毒&#xff0c;又称Dharma&#xff0c;首次出现是在2016年&#xff0c;2017年5月此勒索病毒万能密钥被公布之后&#xff0c;之前的样本可以解密&#xff0c;导致此勒索病毒曾消失了一段时间&#xff0c;不过随后又马上出现了它的一款最新的变种样本&#xff0c;加密…

101 向一个不存在的路径发送请求, get 得到 404, post 得到 405

前言 这是 最近碰到的一个问题, 大概是在 2022.05.30 前端这边 发送了一个业务请求过来, 这个请求路径是服务端这边不存在的 但是 奇怪的一点就是, 如果是以 get 请求发送过来, 服务端响应的是正确的 404 "Not Found", 但是 如果是以 post 请求发送过来, 服务端这边…

Springboot整合rabbitmq(二)

spring boot&#xff0c;为了简化rabbitMQ的使用&#xff0c;它在这里面给咱们提供了一个模板对象。 这个模板对象是什么&#xff1f; 这个模板对象叫RabbitTemplate对象。说白了其实是用来简化rabbitMQ的操作 也就是说之后我们可以通过这个模板对象直接去向rabbitMQ中发送消息…

1分钟做的AI利润表分析报告,效果怎样?

各位数据的朋友&#xff0c;大家好&#xff0c;我是老周道数据&#xff0c;和你一起&#xff0c;用常人思维数据分析&#xff0c;通过数据讲故事&#xff01; 自从去年年初ChatGPT3.5推出以来&#xff0c;AI大模型的话题就一直非常热了。相比于AI聊天、生成图片&#xff0c;亦…

STL空间配置器

参考《STL源码剖析-侯捷》一书 (SGI版本STL) 前置 六大组件 空间配置器实现 SGI版本的空间配置器有两个&#xff0c;一个名为allocator&#xff0c;一个名为alloc。前者符合部分标准&#xff0c;但效率不好&#xff0c;只是对operator new和operator delete进行了封装&#…

工业互联网平台的专题报告

文 | BFT机器人 前言&#xff1a; 现在是工业时代&#xff0c;也是数字化时代。随着信息技术的快速发展&#xff0c;工业不得不依托数字化转型升级。当前数字化转型已经成为企业提升竞争力的关键手段。 工业互联网平台作为数字化转型的重要支撑&#xff0c;能够帮助企业实现生…

(day 2)JavaScript学习笔记(基础之变量、常量和注释)

概述 这是我的学习笔记&#xff0c;记录了JavaScript的学习过程&#xff0c;我是有一些Python基础的&#xff0c;因此在学习的过程中不自觉的把JavaScript的代码跟Python代码做对比&#xff0c;以便加深印象。我本人学习软件开发纯属个人兴趣&#xff0c;大学所学的专业也非软件…

Linux系统编程(六)高级IO

目录 1. 阻塞和非阻塞 IO 2. IO 多路转接&#xff08;select、poll、epoll&#xff09; 3. 存储映射 IO&#xff08;mmap&#xff09; 4. 文件锁&#xff08;fcntl、lockf、flock&#xff09; 5. 管道实例 - 池类算法 1. 阻塞和非阻塞 IO 阻塞 IO&#xff1a;会等待操作的…

猫咪挑食怎么办?预防猫咪挑食的生骨肉冻干分享

在现今社会&#xff0c;养猫的人越来越多&#xff0c;大家都把自家的小猫当作宝贝来宠爱。然而&#xff0c;这种宠爱有时也会导致猫咪养成挑食的不良习惯。那么&#xff0c;猫咪挑食怎么办呢&#xff1f; 今天&#xff0c;我要分享一个既能确保猫咪不受苦&#xff0c;又能有效…

嵌入式学习第二十六天!(网络传输:TCP编程)

TCP通信&#xff1a; 1. TCP发端&#xff1a; socket -> connect -> send -> recv -> close 2. TCP收端&#xff1a; socket -> bind -> listen -> accept -> recv -> send -> close 3. TCP需要用到的函数&#xff1a; 1. co…

MySQL--索引底层数据结构详解

索引是什么&#xff1f; 索引是帮助MySQL高效获取数据的排好序的数据结构&#xff0c;因此可知索引是数据结构。 概念很抽象&#xff0c;但是类比生活中的例子就很容易理解&#xff0c;比如一本厚厚的书&#xff0c;我们想取找某一小节&#xff0c;我们可以根据目录去快速找到…

Python实现快速排序算法

Python实现快速排序算法 下面是使用 Python 实现的快速排序算法的示例代码&#xff1a; def quick_sort(arr):if len(arr) < 1:return arrelse:pivot arr[0]less_than_pivot [x for x in arr[1:] if x < pivot]greater_than_pivot [x for x in arr[1:] if x > pi…

Spring Boot中Excel数据导入导出的高效实现

&#x1f31f; 前言 欢迎来到我的技术小宇宙&#xff01;&#x1f30c; 这里不仅是我记录技术点滴的后花园&#xff0c;也是我分享学习心得和项目经验的乐园。&#x1f4da; 无论你是技术小白还是资深大牛&#xff0c;这里总有一些内容能触动你的好奇心。&#x1f50d; &#x…

基于SpringBoot+MYSQL的大学生租房平台

目录 1、 前言介绍 2、主要技术 3、系统流程 3.1、操作流程 3.2、登录流程 3.3、删除信息流程 3.4、添加信息流程 4、功能需求 5、系统设计 5.1、功能结构设计 5.1、数据库概念设计 6、运行截图(部分) 6.1、管理员功能实现 6.1.1、房东管理 6.1.2、信息审批管理 …

Redis 配置文件详解

Units 单位 配置大小单位&#xff0c;开头定义了一些基本的度量单位&#xff0c;只支持bytes&#xff0c;不支持bit&#xff0c;大小写不敏感。 # Redis configuration file example. # # Note that in order to read the configuration file, Redis must be # started with …

聚观早报 | 腾讯QQ测试AI对话功能;哪吒L官宣4月交付

聚观早报每日整理最值得关注的行业重点事件&#xff0c;帮助大家及时了解最新行业动态&#xff0c;每日读报&#xff0c;就读聚观365资讯简报。 整理丨Cutie 3月8日消息 腾讯QQ测试AI对话功能 哪吒L官宣4月交付 中国对瑞士等6国试行免签 Redmi K70至尊版细节曝光 Meta正…

IDEA自定义Maven仓库

Maven 是一款广泛应用于 Java 开发的工具&#xff0c;其作用类似于一个全自动的 JAR 包管理器&#xff0c;能够方便地导入开发所需的相关 JAR 包。在使用 Maven 进行 Java 程序开发时&#xff0c;开发者能够极大地提高开发效率。以下是关于如何安装 Maven 以及在 IDEA 中配置自…

基于LSTM实现春联上联对下联

按照阿光的项目做出了学习笔记&#xff0c;pytorch深度学习实战项目100例 基于LSTM实现春联上联对下联 基于LSTM&#xff08;长短期记忆网络&#xff09;实现春联上联对下联是一种有趣且具有挑战性的任务&#xff0c;它涉及到自然语言处理&#xff08;NLP&#xff09;中的序列…

【Jemter】安装

1.准备前提工作 2.安装和卸载jdk 1&#xff09;安装双击jdk 2&#xff09;添加环境变量 此电脑–属性–高级系统设置–环境变量–系统变量–path删除/新建 C:\Program Files\Java\jdk-1.8\bin C:\Program Files\Java\jdk-1.8\jre 3&#xff09;验证 以防万一要卸载&#xff…