当前位置: 首页 > news >正文

一个简单的光线追踪渲染器

前言

本文参照自raytracing in one weekend教程,地址为:https://raytracing.github.io/books/RayTracingInOneWeekend.html

什么是光线追踪?

光线追踪模拟现实中的成像原理,通过模拟一条条直线在场景内反射折射,最终获知物体表面的颜色。现实世界中,光线最终射向相机,获得成像,光线追踪则是从相机出发,向场景中反向发射光线,从而推出相机“底片”中每个像素的颜色。

现实中的相机很发杂,包括多组透镜,在成像时不是光线直接射入相机,需要经过多次折射。我们这里的光线追踪更类似于在模拟小孔成像(只不过小孔成像获得的图像是反置的,我们直接得到正向的结果,相当于对反置图像做了反置),我们在小孔的位置放置相机。

在这里插入图片描述

光线追踪和光栅化是两种不同的渲染方式,光栅化相当于把物体表面直接反射或发射的颜色返回给相机“底片”,场景中的各种阴影、遮蔽等效果都是通过预计算等方法得出的,而光线追踪会考虑物体表面光线多次反射或折射的结果,直接可以得到场景中的阴影、遮蔽等细节效果。

在具体实现的过程中,我们会在相机的正前方设置一个虚拟画布,相当于相机的底片(正常来说相机底片应当是在相机背面的,不过为了直观以及便于确定每条光线的方向,直接在相机前方设置),虚拟画布上每个位置的颜色代表了最终渲染结果对应像素的颜色。在发射光线时,通常以相机为起点,虚拟画布上的每个位置为终点,构建一条射线,每个方向可以根据采样设置发射多条射线。每个方向的射线的平均结果为对应像素的最终颜色。

在这里插入图片描述

光栅器的构建过程

这一部分是我在学习raytracing in one weekend教程时,我认为重点部分的罗列。

图像格式

raytracing in one weekend教程中采用了ppm格式,这种格式很简单,可以用ASCII文本表示。详细介绍可以参考:https://zhuanlan.zhihu.com/p/609960339

基本的光追过程

简述一下光线追踪的过程:

  1. 屏幕上的每一个像素都进行光线投射。

  2. 光线的每次投射都需要判断交点,而且投射到交点后还可能产生反射、折射,那么就往相应的方向继续进行新的投射,直到投射到天空或者投射次数达到限制。

  3. 最后,将每个交点的受光照情况以一定权重综合起来,得到一束光线获得的颜色,根据采样次数,每个像素发出的多个颜色的平均值为该像素的颜色。

下图是一个示例。

在这里插入图片描述

光线追踪的伪代码:

RayTracing(Ray ray, hittable_list world, int depth){if(depth <= 0)return black color;hit_record rec; // 弹射点的属性记录if(Intersect(ray, world, out rec)){material = rec.mat; // 弹射点所在物体的材质normal = rec.normal;localColor = ShaderCalculate(ray, material, normal);out_ray = Get_outputRay(ray, material, normal);localColor = shaderCalculate(direction,hitpoint,normal);return localColor * RayTracing(out_ray, world, depth - 1);}else{return the color of background;}
}

抗锯齿

看到一个有趣的真相:每个小像素块不是正方形,参考文献,不过为了简单起见,我们假设每个小像素块是正方形。

这里为了进行抗锯齿,采用了一定程度的随机,即从相机向虚拟画布发射光线时,以像素为单位为射线的终点做随机扰动。

在代码中的体现如下:

ray get_ray(int i, int j) const {// 获取位置 i,j 处像素的随机采样光线。auto pixel_center = pixel00_loc + (i * pixel_delta_u) + (j * pixel_delta_v);auto pixel_sample = pixel_center + pixel_sample_square();auto ray_origin = center;auto ray_direction = pixel_sample - ray_origin;return ray(ray_origin, ray_direction);}vec3 pixel_sample_square() const {// 返回一个单位像素正方形周围的随机点。auto px = -0.5 + random_double();auto py = -0.5 + random_double();return (px * pixel_delta_u) + (py * pixel_delta_v);}

漫反射材质

(最简单的)漫反射材质,在光线射入表面后,会在法线半球随机射出。

而如何获得一个随机的单位球内的向量?文中给出的方法是在单位正方体内随机取点,将不在单位球内的点丢弃。而进一步删选是否在表面法线半球,则可以通过将获得的向量与法线点积,如果点积结果为正则采用,为负则丢弃。

为了让漫反射结果更真实,我们应该采用Lambertian Reflection。采用这种方法,在采样时越靠近法线处概率越高。我们可以在与表面交点相切的球体内采样反射光线,示意图如下:

在这里插入图片描述

gamma矫正

另外需要注意gamma矫正,简单来说,屏幕是处于gamma空间上的,而我们渲染的结果在未经处理时是在linear空间上的,为了使色彩不失真,我们需要将渲染的结果转换到gamma空间上。

以下是gamma矫正前和gamma矫正后的对比图:

在这里插入图片描述

金属材质

这里的金属材质与镜子比较类似,金属材质有一个fuzz参数,代表材质表面反射的模糊度。当反射模糊度为零时,这个材质就相当于一个带颜色的镜子。

fuzz参数:反射时,可以对反射光线加一个随机,表示模糊效果。具体随机方式如下图,对反射光线的末端,加一个半径为fuzz范围的球体随机。

在这里插入图片描述

金属材质的效果:

在这里插入图片描述

玻璃材质

引入了光线的折射,下面贴一下教程原文的计算表示过程。

在这里插入图片描述

在做折射时,需要注意全反射的情况。

另外,在现实生活中,当我们贴近玻璃表面时,玻璃会表现地像镜子,这个效果可以用Christophe Schlick给出的公式来模拟。

此时我们得到的是一个通过物体后光线颠倒的效果,这显然不真实。

在这里插入图片描述

有一个trick,我们可以镶嵌两层玻璃球(内层的玻璃球采用负半径,让表面法线颠倒),消除之前的颠倒效果。

在这里插入图片描述

散焦模糊(defocus blur)

这个概念是模仿相机的景深,指的是在相机拍摄时,焦距附近的图像会很清晰,而焦距之外的图像比较模糊。

要模仿真实的相机,我们还需要模拟相机内各种透镜的折射,这太复杂了。为了简单一点,教程中把我们的相机从发射点扩展为发射圆盘,即每次发射光线时从一个半径为r的圆盘中发射光线,穿过虚拟画布。这种模拟不是严格的相机成像,但是效果还不错,具体原理我没怎么搞清。渲染出来的结果如下图:

在这里插入图片描述

最终的渲染结果

最终作者给了一个大场景,我在机器上跑了十多个小时才跑出来。

在这里插入图片描述

完整代码

不想上传个单独的github项目了,就传在网盘上吧:

链接:https://pan.baidu.com/s/1TQUo7GbRUsR-tyLDOv_vOg?pwd=duxm
提取码:duxm
–来自百度网盘超级会员V6的分享

ps: 我只分享了源代码,没有什么依赖库,应该可以直接跑出图片。

参考

https://raytracing.github.io/books/RayTracingInOneWeekend.html

https://zhuanlan.zhihu.com/p/168791125

https://zhuanlan.zhihu.com/p/357142662

https://www.cnblogs.com/KillerAery/p/15106773.html

相关文章:

一个简单的光线追踪渲染器

前言 本文参照自raytracing in one weekend教程&#xff0c;地址为&#xff1a;https://raytracing.github.io/books/RayTracingInOneWeekend.html 什么是光线追踪&#xff1f; 光线追踪模拟现实中的成像原理&#xff0c;通过模拟一条条直线在场景内反射折射&#xff0c;最终…...

C++学习笔记(十二)------is_a关系(继承关系)

你好&#xff0c;这里是争做图书馆扫地僧的小白。 个人主页&#xff1a;争做图书馆扫地僧的小白_-CSDN博客 目标&#xff1a;希望通过学习技术&#xff0c;期待着改变世界。 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 文章目录 前言 一、继承关系…...

DC电源模块的设计与制造技术创新

BOSHIDA DC电源模块的设计与制造技术创新 DC电源模块的设计与制造技术创新主要涉及以下几个方面&#xff1a; 1. 高效率设计&#xff1a;传统的DC电源模块存在能量转换损耗较大的问题&#xff0c;技术创新可通过采用高效率的电路拓扑结构、使用高性能的功率开关器件和优化控制…...

Sketch for Mac:实现你的创意绘图梦想的矢量绘图软件

随着数字时代的到来&#xff0c;矢量绘图软件成为了广告设计、插画创作和UI设计等领域中必不可少的工具。在众多矢量绘图软件中&#xff0c;Sketch for Mac&#xff08;矢量绘图软件&#xff09;以其强大的功能和简洁的界面脱颖而出&#xff0c;成为了众多设计师的首选。 Sket…...

ReactNative0.73发布,架构升级与更好的调试体验

这次更新包含了多种提升开发体验的改进&#xff0c;包括&#xff1a; 更流畅的调试体验: 通过 Hermes 引擎调试支持、控制台日志历史记录和实验性调试器&#xff0c;让调试过程更加高效顺畅。稳定的符号链接支持: 简化您的开发工作流程&#xff0c;轻松将文件或目录链接到其他…...

SVN忽略文件的两种方式

当使用版本管理工具时&#xff0c;提交到代码库的文档我们不希望存在把一些临时文件也推送到仓库中&#xff0c;这样就需要用到忽略文件。SVN的忽略相比于GIT稍显麻烦&#xff0c;GIT只需要在.gitignore添加忽略规则即可。而SVN有两种忽略方式&#xff0c;一个是全局设置&#…...

手写VUE后台管理系统10 - 封装Axios实现异常统一处理

目录 前后端交互约定安装创建Axios实例拦截器封装请求方法业务异常处理 axios 是一个易用、简洁且高效的http库 axios 中文文档&#xff1a;http://www.axios-js.com/zh-cn/docs/ 前后端交互约定 在本项目中&#xff0c;前后端交互统一使用 application/json;charsetUTF-8 的请…...

JavaScript装饰者模式

JavaScript装饰者模式 1 什么是装饰者模式2 模拟装饰者模式3 JavaScript的装饰者4 装饰函数5 AOP装饰函数6 示例&#xff1a;数据统计上报 1 什么是装饰者模式 在程序开发中&#xff0c;许多时候都我们并不希望某个类天生就非常庞大&#xff0c;一次性包含许多职责。那么我们就…...

C++学习笔记01

01.C概述&#xff08;了解&#xff09; c语言在c语言的基础上添加了面向对象编程和泛型编程的支持。 02.第一个程序helloworld&#xff08;掌握&#xff09; #define _CRT_SECURE_NO_WARNINGS #include<iostream> using namespace std;//标准命名空间int main() {//co…...

【UE5】初识MetaHuman 创建虚拟角色

步骤 在UE5工程中启用“Quixel Bridge”插件 打开“Quixel Bridge” 点击“MetaHumans-》MetaHuman Presets UE5” 点击“START MHC” 在弹出的网页中选择一个虚幻引擎版本&#xff0c;然后点击“启动 MetaHuman Creator” 等待一段时间后&#xff0c;在如下页面点击选择一个人…...

物流实时数仓:数仓搭建(DWD)一

系列文章目录 物流实时数仓&#xff1a;采集通道搭建 物流实时数仓&#xff1a;数仓搭建 物流实时数仓&#xff1a;数仓搭建&#xff08;DIM&#xff09; 物流实时数仓&#xff1a;数仓搭建&#xff08;DWD&#xff09;一 文章目录 系列文章目录前言一、文件编写1.目录创建2.b…...

MATLAB安装

亲自验证有效&#xff0c;多谢这位网友的分享&#xff1a; https://blog.csdn.net/xiajinbiaolove/article/details/88907232...

C语言——预处理详解(#define用法+注意事项)

#define 语法规定 #define定义标识符 语法: #define name stuff #define例子 #include<stdio.h> #define A 100 #define STR "abc" #define FOR for(;;)int main() {printf("%d\n", A);printf("%s\n", STR);FOR;return 0; } 运行结果…...

Linux(23):Linux 核心编译与管理

编译前的任务&#xff1a;认识核心与取得核心原始码 Linux 其实指的是核心。这个【核心(kernel)】是整个操作系统的最底层&#xff0c;他负责了整个硬件的驱动&#xff0c;以及提供各种系统所需的核心功能&#xff0c;包括防火墙机制、是否支持 LVM 或 Quota 等文件系统等等&a…...

Oracle RAC环境下redo log 文件的扩容

环境&#xff1a; 有一个2节点RAC每一个节点2个logfile group每一个group含2个member每一个member的大小为200M 目标&#xff1a;将每一个member的大小有200M扩充到1G。 先来看下redo log的配置&#xff1a; SQL> select * from v$log;GROUP# THREAD# SEQUENCE# …...

Java入门学习笔记一

一、Java语言环境搭建 1、JAVA语言的跨平台原理 1.1、什么是跨平台性&#xff1f; 跨平台就是说&#xff0c;同一个软件可以在不同的操作系统&#xff08;例如&#xff1a;Windows、Linux、mad&#xff09;上执行&#xff0c;而不需要对软件做任务处理。即通过Java语言编写的…...

分布式块存储 ZBS 的自主研发之旅|元数据管理

重点内容 元数据管理十分重要&#xff0c;犹如整个存储系统的“大黄页”&#xff0c;如果元数据操作出现性能瓶颈&#xff0c;将严重影响存储系统的整体性能。如何提升元数据处理速度与高可用是元数据管理的挑战之一。SmartX 分布式存储 ZBS 采用 Log Replication 的机制&…...

六大设计原则

六大设计原则 1、单一职责原则 一个类或者模块只负责完成一个职责或者功能。 2、开放封闭原则 规定软件中的对象、类、模块和函数对扩展应该是开放的&#xff0c;对于修改应该是封闭的。用抽象定义结构&#xff0c;用具体实现扩展细节。 3、里氏替换原则 如果S是T的子类型…...

dockerfile创建镜像 lNMP+wordpress

dockerfile创建镜像 lNMPwordpress nginx dockernginx mysql dockermysql php dockerphp nginx vim nginx.conf vim Dockerfile docker network create --subnet172.17.0.0/16 --opt "com.docker.network.bridge.name""docker1" mynetwork docker buil…...

深入理解——快速排序

目录 &#x1f4a1;基本思想 &#x1f4a1;基本框架 &#x1f4a1;分割方法 ⭐Hoare版本 ⭐挖坑法 ⭐前后指针法 &#x1f4a1;优化方法 ⭐三数取中法 ⭐小区间内使用插入排序 &#x1f4a1;非递归实现快速排序 &#x1f4a1;性能分析 &#x1f4a1;基本思想 任取待排…...

【代码随想录】算法训练计划50

dp 1、123. 买卖股票的最佳时机 III 题目&#xff1a; 给定一个数组&#xff0c;它的第 i 个元素是一支给定的股票在第 i 天的价格。 设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。 注意&#xff1a;你不能同时参与多笔交易&#xff08;你必须在再次购…...

【数据分享】2019-2023年我国区县逐年二手房房价数据(Excel/Shp格式)

房价是一个区域发展程度的重要体现&#xff0c;一个区域的房价越高通常代表这个区域越发达&#xff0c;对于人口的吸引力越大&#xff01;因此&#xff0c;房价数据是我们在各项城市研究中都非常常用的数据&#xff01;之前我们分享了2019—2023年我国区县逐月的二手房房价数据…...

Redis设计与实现之整数集合

目录 一、内存映射数据结构 二、整数集合 1、整数集合的应用 2、数据结构和主要操作 3、intset运行实例 创建新intset 添加新元素到 intset 添加新元素到 intset&#xff08;不需要升级&#xff09; 添加新元素到 intset (需要升级) 4、升级 升级实例 5、关于升级 …...

[Kubernetes]2. k8s集群中部署基于nodejs golang的项目以及Pod、Deployment详解

一. 创建k8s部署的镜像 1.部署nodejs项目 (1).上传nodejs项目到节点node1 (2).压缩nodejs项目 (3).构建nodejsDockerfile 1).创建nodejsDockerfile 具体可参考:[Docker]十.Docker Swarm讲解,在/root下创建nodejsDockerfile,具体代码如下: FROM node #把压缩文件COPY到镜像的…...

讯飞星火大模型api调用

讯飞星火大模型&#xff0c;通过websocket方式通信传递协议要求的报文&#xff0c;然后将流式返回的报文拼接为完整的响应内容&#xff0c;status2时是最后一条消息。因为是websocket方式所以是异步响应的&#xff0c;如果想要同步需要使用CountDownLatch控制下线程等待最后一条…...

TCP与UDP:网络世界中的“顺丰快递”与“广播电台”

随着互联网的普及&#xff0c;我们每天都在与网络打交道。而在这背后&#xff0c;数据的传输离不开TCP和UDP这两种传输协议。它们就像网络世界中的“顺丰快递”和“广播电台”&#xff0c;各自有着不同的工作方式和特点。让我们一起来了解一下它们吧&#xff01; 一、TCP&…...

升级Xcode15,iOS17后问题解决

1、Could not build module ‘WebKit’ 报错 解决方案&#xff1a; 编辑文件 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS17.0.sdk/System/Library/Frameworks/WebKit.framework/Headers/WKWebsiteDataStore.h 将里面…...

RabbitMQ搭建集群环境、配置镜像集群、负载均衡

RabbitMQ集群搭建 Linux安装RabbitMQ下载安装基本操作命令开启管理界面及配置 RabbitMQ集群搭建确定rabbitmq安装目录启动第一个节点启动第二个节点停止命令创建集群查看集群集群管理 RabbitMQ镜像集群配置启用HA策略创建一个镜像队列测试镜像队列 负载均衡-HAProxy安装HAProxy…...

leetcode:457. 环形数组是否存在循环

环形数组是否存在循环 存在一个不含 0 的 环形 数组 nums &#xff0c;每个 nums[i] 都表示位于下标 i 的角色应该向前或向后移动的下标个数&#xff1a; 如果 nums[i] 是正数&#xff0c;向前&#xff08;下标递增方向&#xff09;移动 |nums[i]| 步 如果 nums[i] 是负数&…...

Kafka集成springboot

安装kafka&#xff0c;直接到官网下载bin文件&#xff0c;本文使用windows进行使用kafka。 下载之后&#xff0c;第一步&#xff0c;启动zookeeper&#xff1a; zookeeper-server-start.bat ..\..\config\zookeeper.properties 第二步&#xff0c;启动kafka&#xff1a; kafka…...

夏邑县百城建设提质网站/广告营销策略

今天突然对Android的自动化测试有点儿感兴趣&#xff0c;google了下&#xff0c;发现自动化测试的工具还真不少&#xff0c;有Monkey,MonkeyRunner,Robotium等太多了&#xff0c;前段时间也看到了 风泊海上 写的《Android自动化测试之Robotium学习》的博文&#xff0c;呵呵感觉…...

wordpress商城开源/广告信息发布平台

今天从网上搞了一个基于osip 库的 SIP 协议的简单的 UAC 代理客户端和 UAS 代理服务器端&#xff0c;并进行了编译连接&#xff0c;代码整理后如下&#xff1a;----------- UAC 代理客户端的代码整理 ---------------/*** 一个使用了 osip 和 eXosip 库的 UAC 代理客户端的演示…...

网站怎么做脚注/北京优化靠谱的公司

打开Eclipse下该文件&#xff1a;\configuration\.settings\org.eclipse.ui.ide.prefs 删除&#xff1a;“RECENT_WORKSPACES” 后面不用的工作空间。转载于:https://www.cnblogs.com/ace-9527/p/4957975.html...

蒙文网站开发/seo免费培训教程

我们每天都会听到越来越多关于征服IT行业的虚拟助手的消息。几乎每家大公司都在尝试做一些与众不同的事情。Apple的Siri&#xff0c;三星的Bixby&#xff0c;亚马逊的Alexa&#xff0c;微软的Cortana等。您可以通过说“Siri&#xff0c;我想要披萨”来订购披萨&#xff0c;或者…...

镇江网站建设 的公司/腾讯企点下载

什么是gerber文件 Gerber文件是所有电路设计软件都可以产生的文件&#xff0c;在电子组装行业又称为模版文件&#xff08;stencil data&#xff09;,在PCB制造业又称为光绘文件。可以说Gerber文件是电子组装业中最通用最广泛的文件格式。因此对于一个电子生产企业&#xff0c;拥…...

基于aws ec2免费实例进行网站建设/营销策划书范文案例

介绍&#xff1a; 一个富有动感的Sheet(选择器)&#xff0c; 支持背景虚化,背景暗化,支持快速拓展.支持从 Menu 中填充数据。运行效果&#xff1a; 使用说明&#xff1a; 上面是设计图&#xff0c;demo运行效果图&#xff1a; MainActivity.class 1234567891011121314151617181…...