Ray_Tracing_In_One_Weekend上

news2024/11/15 23:27:18

目标:

使用vscodeIDE编写代码,这是我的配置

学习这个教程,完成一个简易的光线追踪器开发

1·输出PPM图像

在不使用 opengl (渲染图像)/ std_image.h(加载图像)等库的情况下,怎样通过代码自定义图像?

有一种PPM格式的图像,可以通过定义数据生成简单的图像

首先p3表明颜色是ASCII码格式,接着指定分辨率,和最大颜色值之后下面的都是RGB颜色值 ,

我们可以通过代码设置这些数据:

首先指定p3和分辨率(200宽100高)和255最大颜色值,然后设置每个像素颜色值,首先在0---1之间,然后转为0---255的颜色

对于PPM来说从左往右,从上到下写入的,因此首先输出的数据是左上,最后输出的是右下

#include <iostream>

int main()
{
    const int image_width = 200;
    const int image_height = 100;

    std::cout << "P3\n"
              << image_width << ' ' << image_height << "\n255\n";

    for (int j = image_height - 1; j >= 0; --j)
    {
        for (int i = 0; i < image_width; ++i)
        {
            auto r = double(i) / image_width;
            auto g = double(j) / image_height;
            auto b = 0.2;
            int ir = static_cast<int>(255.999 * r);
            int ig = static_cast<int>(255.999 * g);
            int ib = static_cast<int>(255.999 * b);
            std::cout << ir << ' ' << ig << ' ' << ib << '\n';
        }
    }
}

我们已经有了所有数据,通过新建终端,然后执行命令

我们可以运行exe,并将cout输出的内容写入到PPM格式的文件中

加载ppm文件的网站

最终效果:

2·VEC3文件

用vec3`类来储存所有的颜色, 位置, 方向, 偏移等

它是一个有3个double类型数据的数组,重载了+加-减*乘/除,dot()点乘cross()叉乘,unit_vector()标准化等矢量运算

构造函数会接收3个数据,作为向量

write_color()函数,可以让值转为0---255之间

像素颜色设置,通过调用自定义的API,还是之前显示结果

vec3 color(double(i) / image_width, double(j) / image_height, 0.2);
color.write_color(std::cout);

3·ray类

光线是一个射线,a原点,t ,double值,b方向 

vec3 at(double t) const:返回t时间下,ray的向量

在main中,控制的从每个像素发射的ray方向为x(-1--1)y(-2----2)

vec3 lower_left_corner(-2.0, -1.0, -1.0);
vec3 horizontal(4.0, 0.0, 0.0);
vec3 vertical(0.0, 2.0, 0.0);
for (int j = image_height - 1; j >= 0; --j)
{
    for (int i = 0; i < image_width; ++i){
        auto u = double(i) / image_width;//0--1
        auto v = double(j) / image_height;//1--0
        //u*horizontal: 0--4
        //v*vertical: 2--0
        //lower_left_corner + :x:-2--2, y:1-- -1
        ray r(origin, lower_left_corner + u*horizontal + v*vertical);
    }
}

ray_color(ray)函数根据y值将蓝白做了个线性插值的混合

vec3 ray_color(const ray& r) {/* 根据ray的y值,返回渐变的蓝白色 */
    vec3 unit_direction = unit_vector(r.direction());/* 单位化光线 */
    auto t = 0.5*(unit_direction.y() + 1.0);/* 1---0 */
    return (1.0-t)*vec3(1.0, 1.0, 1.0) + t*vec3(0.5, 0.7, 1.0);/* 从上到下,从蓝到白 */
}

完成效果:

4·渲染球体

 隐式表示:

这是球心在0,0,0位置的方程,所有球面的点xyz都满足=r^2,如果<r^2则点在内部,否则在外部

如果球心在cx,cy,cz,则

其中r可以写为点p和球心c的向量形式(等价) ,最终的球面方程:

 

那么光线和球体相交,两个方程都满足,即光线为t时间时的坐标,作为点p满足在球体表面

唯一的未知数就是t,即关于t的一个一元二次方程
 ,通过求根公式判断交点个数、

我们创建一个球心在vec3(0, 0, -1),半径为0.5的球体,根据hit_sphere()光线和球体 求交,如果相交,返回颜色值return vec3(1, 0, 0);,否则仍然是原来的背景

bool hit_sphere(const vec3 &center, double radius, const ray &r)
{
    vec3 oc = r.origin() - center;
    auto a = dot(r.direction(), r.direction());
    auto b = 2.0 * dot(oc, r.direction());
    auto c = dot(oc, oc) - radius * radius;
    auto discriminant = b * b - 4 * a * c;/* 当 b2−4ac>=0 时,表示二次函数与x轴有至少一个交点 */
    return (discriminant > 0);
}

最终效果: 

5·着色

对于hit_sphere()我们返回一个double值,如果光线物体没有交点,返回-1,否则返回t的结果(光线在t时间与球体相交)

if (discriminant < 0) {
    return -1.0;
}
else {
    return (-b - sqrt(discriminant) ) / (2.0*a);
}

 我们求解物体的法线(光线 - 球心),然后根据法线向量,简单的为球体着色

auto t = hit_sphere(vec3(0,0,-1), 0.5, r);
if (t > 0.0) {
    vec3 N = unit_vector(r.at(t) - vec3(0,0,-1));
    return 0.5*vec3(N.x()+1, N.y()+1, N.z()+1);
}

结果:

6·优化代码

项1:求根公式

我们可以把求根公式中的b替换为2h,经过展开移项后

因此,简化后的代码 

double hit_sphere(const vec3 &center, double radius, const ray &r)
{
    vec3 oc = r.origin() - center;
    auto a = r.direction().length_squared();
    auto half_b = dot(oc, r.direction());
    auto c = oc.length_squared() - radius*radius;
    auto discriminant = half_b*half_b - a*c;

    if (discriminant < 0) {
        return -1.0;
    } else {
        return (-half_b - sqrt(discriminant) ) / a;
    }
}

项2:物体继承体系

我们建立一个物体基类叫做hittable,其中STRUCT hit_record记录交点的信息,hit()虚函数用来判断是否有交点

建立一个sphere派生类继承hittable

项3:法线方向

我们想要物体在内外方向都有法线,因此如果光线和法线dot>0即同方向即光线从球体内部照射,则法线反转,否则不反转

在物体基类STRUCT hit_record中引入了,和新建了set_face_normal()函数,用来反转法线,并在求交时加入射入面的判别

double t;
bool front_face;//是否是正面

项4:物体列表

我们新建一个hittable_list物体列表类继承hittable,维护一个std::vector<shared_ptr<hittable>>物体列表

并且重写了hit函数,其中会对for (const auto &object : objects)物体列表的所有物体依次求交

并且维护了t_min, closest_so_far参数,负责深度测试

项5:常用函数和工具

rtweekend.h类

7·两个球体

在main函数中,创建两个球体,大的球体作为地板

hittable_list world;
world.add(make_shared<sphere>(vec3(0, 0, -1), 0.5));
world.add(make_shared<sphere>(vec3(0, -100.5, -1), 100));

然后调用hittable_list类中的hit函数,求交点信息更新像素颜色

结果:

8·反走样/抗锯齿

 MSAA:每个像素增加到samples_per_pixel个采样点,每个采样点的颜色值为 1 / samples_per_pixel的权重

首先在rtweekend.h添加随机数生成器和clamp()函数(负责将值限制在min和max之间)

然后抽象出轴对齐摄像机类,也就是屏幕像素

最后结果与对比:

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

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

相关文章

某信服, 一点底线都没有, 一点Face都不要

某些软件厂商, 仗着自己有点背景, 做出来的东西真的是流氓 !!! 铁子们, 这玩意儿怎么卸载呢?

CertiK《Hack3d:2024年第三季度安全报告》(附报告全文链接)

CertiK《Hack3d&#xff1a;2024年第三季度Web3.0安全报告》现已发布&#xff0c;本次报告深入分析了2024年7月至9月的链上安全状况&#xff0c;本季度总损失金额为7.53亿美元&#xff0c;网络钓鱼和私钥泄露是本季度造成资产损失的主要原因。 ​ 关键数据 2024年第三季度&a…

数电基础(脉冲波形的变化和发生+multisim)

1.脉冲波形的变化和发生 1.1单稳态电路 1.1.1逻辑门组成的单稳态电路 基本概念 &#xff08;1&#xff09;单稳态电路&#xff08;monostable multivibrator又称one-shot&#xff09;常用于脉冲的变换&#xff0c;延时和定时 电路的输出有稳态和暂稳态两个不同的工作状态 …

java常用框架结构

1. Spring框架 特色&#xff1a;Spring框架就像是一个万能工具箱&#xff0c;提供了丰富的功能来满足开发者的各种需求。它支持面向切面编程&#xff08;AOP&#xff09;、依赖注入&#xff08;DI&#xff09;等特性&#xff0c;使得代码更加模块化和可维护。Spring还提供了对数…

【web安全】——XXE漏洞

1.XML基础 1.1.XML简介 XML被称为可扩展标记语言&#xff0c;与HTML类似&#xff0c;但是HTML中的标签都是预定义(预先定义好每个标签的作用)的&#xff0c;而XML语言中的标签都是自定义(可以自己定义标签的名称、属性、值、作用)的;HTML中的标签可以是单标签&#xff0c;而X…

洛谷 P11045 [蓝桥杯 2024 省 Java B] 最优分组

[Problem Discription] \color{blue}{\texttt{[Problem Discription]}} [Problem Discription] [Analysis] \color{blue}{\texttt{[Analysis]}} [Analysis] 首先得注意这么一点&#xff1a; k k k 必须得是 n n n 的因数&#xff08;这里的 n , k n,k n,k 对应于题目的 N ,…

【若依】postman调试出现认证失败,无法访问系统资源

如果前后端都已经连接通了&#xff0c;但是调试出现错误代码&#xff0c;可能是因为没有授权的问题&#xff0c;需要获得授权。 授权内容在cookie中 把cookie中的token内容粘贴到postman里面 这个时候再在postman里测试接口&#xff0c;发现可以拿到数据了

【C++】“list”的介绍和常用接口的模拟实现

【C】“list”的介绍和常用接口的模拟实现 一. list的介绍1. list常见的重要接口2. list的迭代器失效 二. list常用接口的模拟实现&#xff08;含注释&#xff09;三. list与vector的对比 一. list的介绍 list是可以在常数范围内在任意位置进行插入和删除的序列式容器&#xf…

操作符详解与表达式求值

目录 操作符分类 1.算数操作符 2.移位操作符&#xff08;只适用于整数范围&#xff09; &#xff08;1&#xff09;引入 &#xff08;2&#xff09;左移操作符<< &#xff08;2&#xff09;右移操作符>> 3.位操作符 4.赋值操作符 复合赋值符 5.单目操作符 5…

SQL:函数以及约束

目录 介绍 函数 字符串函数 数值函数 日期函数 流程函数 约束 总结 介绍 说到函数我们都不陌生,在C,C,java等语言中都有库函数,我们在平时也是经常使用,函数就是一段代码,我们既可以自定义实现,又可以使用库里内置的函数;从来更加简洁方便的完成业务;同样的在SQL中也有…

vscode qt 最新开发环境配置, 基于最新插件 Qt All Extensions Pack

qt 之前发布了vscode qt offical ,但是最新更新中将其升级改为了几个不同的插件&#xff0c;功能更强大 1. 前置条件 qt 已安装 2. 插件安装 打开vscode 插件安装&#xff0c;搜索qt 会看到很多qt插件&#xff0c;直接选择Qt All Extensions Pack 安装 会安装qt环境所需的…

国内旅游:现状与未来趋势分析

在当今社会快速发展的背景下&#xff0c;国内旅游更是呈现出蓬勃的发展态势。中国&#xff0c;这片拥有悠久历史、灿烂文化和壮丽山河的广袤土地&#xff0c;为国内旅游的兴起与发展提供了得天独厚的条件。 本报告将借助 DataEase 强大的数据可视化分析能力&#xff0c;深入剖…

Linux:深入理解冯诺依曼结构与操作系统

目录 1. 冯诺依曼体系结构 1.1 结构分析 1.2 存储结构分布图 2. 操作系统 2.1 概念 2.2 如何管理 2.3 什么是系统调用和库函数 1. 冯诺依曼体系结构 1.1 结构分析 不管是何种计算机&#xff0c;如个人笔记本电脑&#xff0c;服务器&#xff0c;都是遵循冯诺依曼结构。…

小论树形dp

文章目录 树形dp 概述树形dp 路径问题 树的最长路径 思路代码树的中心 换根DP思路代码数字转换 思路代码树形dp 有依赖的背包 二叉苹果树 思路代码树形dp 状态机 没有上司的舞会 思路代码战略游戏 思路代码皇宫看守 思路代码总结 概述 树形 DP&#xff0c;即在树上进行的 …

通信工程学习:什么是DQDB分布式队列双总线

DQDB&#xff1a;分布式队列双总线 DQDB&#xff08;Distributed Queue Dual Bus&#xff09;&#xff0c;即分布式队列双总线&#xff0c;是美国电气电子工程师学会(IEEE)802.6标准中定义的一种城域网(MAN)数据链路层通信协议。该协议主要用于城域网的数据、语音和视频传输&am…

Python 中的 os 模块

Python 中的 os 模块 在Python中&#xff0c;os 模块是一个内置的标准库&#xff0c;提供了许多与操作系统交互的功能。它允许你执行一系列操作&#xff0c;如文件和目录操作、环境变量管理等。要在Python脚本中使用os模块&#xff0c;你需要首先导入它。 一些常见的用法&…

如何在 Android 中用 Kotlin 将 dp 转换为 px

我们在开发 Android 应用时&#xff0c;经常需要将 dp&#xff08;密度无关像素&#xff09;转换为 px&#xff08;像素&#xff09;。这是因为不同设备有不同的屏幕密度&#xff0c;使用 dp 可以保持在不同设备上的一致性。&#x1f4f1; 但究竟如何将 dp 转换为 px 呢&#x…

鸿蒙网络管理模块02——Socket

如果你也对鸿蒙开发感兴趣&#xff0c;加入“Harmony自习室”吧&#xff01;扫描下方名片&#xff0c;关注公众号&#xff0c;公众号更新更快&#xff0c;同时也有更多学习资料和技术讨论群。 1、概述 Socket 连接主要是通过 Socket 进行数据传输&#xff0c;支持 TCP/UDP/Mul…

Redis篇(面试题 - 连环16炮)(持续更新迭代)

目录 &#xff08;第一炮&#xff09;一、Redis&#xff1f;常用数据结构&#xff1f; 1. 项目里面到了Redis&#xff0c;为什么选用Redis&#xff1f; 2. Redis 是什么&#xff1f; 3. Redis和关系型数据库的本质区别有哪些&#xff1f; 4. Redis 的线程模型了解吗&#x…

探索未来:掌握python-can库,开启AI通信新纪元

文章目录 **探索未来&#xff1a;掌握python-can库&#xff0c;开启AI通信新纪元**背景介绍**python-can**库简介安装指南函数使用示例应用场景常见问题及解决方案总结 探索未来&#xff1a;掌握python-can库&#xff0c;开启AI通信新纪元 背景介绍 在人工智能和物联网的飞速…