【光线追踪系列一】PPM输出;自定义vec3;光线、简单相机及天空采样

2023-05-16

本次光线追踪系列从基础重新开始,主要参照 Ray Tracing in One Weekend ,具体实现代码框架见 https://github.com/RayTracing/raytracing.github.io/。本文只是主要精炼光追相关理论,具体实现可参照原文。

一、PPM输出

1.1 PPM格式

ppm是一种直接存储RGB颜色值的文件格式,第一行是p3,表示颜色值用ASCII存。第二行是图像的宽和高。接下来是每一行按顺序存放的颜色值。
在这里插入图片描述
,具体实现可参照原文,本人实现效果如下:
在这里插入图片描述

二、自定义vec3类

几乎所有图形程序都有一些用于存储几何矢量和颜色的类。在许多系统中,这些向量是4D(3D加上几何的齐次坐标,而RGB加上颜色的alpha透明通道)。就我们的目的而言,三个坐标就足够了。我们将对vec3颜色,位置,方向,偏移量等使用相同的类。
原文中,除了实现一些基本的操作外,还在该类中重载了许多vec3的拓展,用户可自己前去查看。

三、光线、简单相机及天空采样

本部分主要实现:
以相机所处的原点(0,0,0)为起点,对屏幕的每个像素都发射一条射线:
①. 如果命中物体,就处理命中物体的情况,这种情况放到下节处理
②. 如果没有命中,获取射线方向的单位向量的y值,从0到1对浅蓝色和白色进行插值,以模拟天空的颜色,最终将颜色值输出到屏幕。

3.1 光线类

Ray Tracing是一个光学成像的逆过程。所有光线跟踪器都具有的一件事是光线类别和对沿光线看到的颜色进行计算。让我们将射线视为函数P(t)= A +tb。这里 P 是沿3D线的3D位置。 一个 是射线的起源, b是射线方向。射线参数t是一个实数。插入其他t和 P(t)沿射线移动点。加上负数t值,您可以在3D线上的任何位置。对于正确的t,您只会得到在正向的t,这就是通常所说的半线或射线。
在这里插入图片描述
射线类代码如下:

class ray
{
public:
    vec3 A; //起点
    vec3 B; //方向

    ray() {}
    ray(const vec3 &a, const vec3 &b)
    {
        A = a;
        B = b;
    }
    vec3 origin() const { return A; }
    vec3 direction() const { return B; }
    vec3 point_at_parameter(float t) const { return A + t * B; } //终点的坐标
};

3.2 简单相机和背景输出

首先用一种非常简单的方式定义相机和屏幕:相机就是位于原点的一个点,屏幕就是一个4x2的矩形。
在这里插入图片描述
如图所示,假定Y轴指向上方,Z轴反方向面向屏幕,X轴指向右边。
u为像素在水平方向上的比值,v为像素在竖直方向上的比值,范围为[0,1]。
将相机的位置放置在原点(0,0,0)处,屏幕的左下角为(-2,-1,-1),右上角为(2,1,-1),宽为4,高为2。

接下来实现颜色输出函数,该函数的功能:发射一条射线,并采样该射线最终输出到屏幕的颜色值。

//发射一条射线,并采样该射线最终输出到屏幕的颜色值
vec3 color(const ray &r)
{
	vec3 blue = vec3(0.5, 0.7, 1.0); 
	vec3 white= vec3(1.0, 1.0, 1.0);
    vec3 unit_direction = unit_vector(r.direction());
    float t = 0.5 * (unit_direction.y() + 1.0);	//确保t的范围为[0,1]
    return (1.0 - t) * white + t * blue  ; //对白色和浅蓝色插值
}
  • 函数解释:由于目前我们还没有定义任何会被射线命中的物体,在没有命中物体的情况下,所以上面我们直接用线性插值公式,根据射线方向的单位向量的y,对白色和浅蓝色进行插值,以模拟天空的颜色。
    该现行插值公式如下:
    在这里插入图片描述
    其中C为输出的颜色,A为起始颜色,B为目标颜色。

说明:使用这种对射线方向的单位向量的y分量进行插值的方式,可以实现任意方向平行光一致的效果。也就是说,无论射线的起点在哪里,射线采样到的颜色只和仰角(即射线和XOZ平面的夹角)有关。举个例子,在这种情况下,在屋顶的东面45°仰望天空,和在南面45°仰望天空,观察到的颜色值是一样的。因为后面会涉及射线命中物体后的反射行为,反射后,光线的起点和方向会被修改,但这不影响射线对最终天空颜色值的正常采样,因此要事先特别说明一下。后面我们将会看到绝对光滑的金属材质,可以像镜子一样反射得到天空的颜色。

接下来,我们会在入口函数中,从原点出发,朝着屏幕上的每一个像素发射一条射线,然后用 color( r ) 函数返回该射线对应的颜色值,输出到屏幕上。

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);
vec3 origin(0.0, 0.0, 0.0);// 相机原点
void RayTracing()
{
    for (int j = ny - 1; j >= 0; j--)
    {
        for (int i = 0; i < nx; i++)
        {
            float u = float(i) / float(nx);	//像素在水平方向上的比值,范围[0,1]
            float v = float(j) / float(ny); //像素在竖直方向上的比值,范围[0,1]
            ray r(origin, lower_left_corner + u*horizontal + v*vertical);
            vec3 col = color(r);

            int ir = int(255.99 * col[0]);
            int ig = int(255.99 * col[1]);
            int ib = int(255.99 * col[2]);
            DrawPixel(i, j, ir, ig, ib);//根据像素点i.j位置绘制rgb颜色
        }
    }
}

最终可得到这张类似于天空的图像:
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【光线追踪系列一】PPM输出;自定义vec3;光线、简单相机及天空采样 的相关文章

  • 【测绘专用】 MATLAB 四叉树分割遥感图像

    MATLAB 四叉树分割遥感图像 四叉树是遥感图像处理里面常用的一种算法 xff0c 我这里采用递归的方法来实现 数据处理的思路 对于图像矩阵 xff0c 我是判断它的方差是否小于某个阈值 xff0c 大于就继续分 xff0c 小于就不分
  • VS code配置latex美赛模板

    VS code配置latex美赛模板 首先要知道安装的latex版本是miktex还是texlive Miktex 我的是2 9的 解压模板文件 xff1a 用VScode打开上面红圈里的文件即可进行编辑 Texlive 打开 Tex Li
  • OkHttpUtils (OkHttpUtil工具类)

    public class OkHttpUtil static OkHttpUtil okHttpUtil private OkHttpClient Builder builder private Request Builder reques
  • C++经典类库(C++开发必看)

    现实中 xff0c C 43 43 的库门类繁多 xff0c 解决的问题也是极其广泛 xff0c 库从轻量级到重量级的都有 本文为你介绍了十一种类库 xff0c 有我们常见的 xff0c 也有不常见的 xff0c 一起来看 AD xff1a
  • libcurl第九课 Content-Length的添加机制

    场景 lt DOCTYPE HTML PUBLIC 34 W3C DTD HTML 4 01 EN 34 34 http www w3 org TR html4 strict dtd 34 gt lt HTML gt lt HEAD gt
  • 英伟达NX上使用 Python 硬解码ip摄像头h264视频流

    问题 用另一篇博客rtsp拉流的方法 xff0c 当单独拉流时 xff0c 不会出现任何问题 可是如果将拉流和检测算法结合 xff0c 就会出现断流 xff0c 花屏 xff0c 跳帧 xff0c 播放延迟 xff0c 播放速度卡顿等问题
  • http库

    当我们使用 Go 语言进行 Web 开发时 xff0c 不可避免地要使用到 http 包 该包提供了 HTTP 客户端和服务器的实现 xff0c 可以轻松地编写 HTTP 服务器和客户端 在本节中 xff0c 我们将学习如何使用 Go 语言
  • CMake链接静态库

    set CMAKE CXX STANDARD 14 include directories CMAKE SOURCE DIR include include directories CMAKE SOURCE DIR include rtk
  • 清晰解读C语言中的位域、字节序、比特序、大小端

    一 比特序 位序 比特序表示一个字节中8个比特位 xff08 bit xff09 之间的顺序问题 分为LSB 0 位序和MSB 0 位序 LSB least significant bit xff1a 数据的最低位存放在字节的第0位 MSB
  • swiper轮播图代码实例

    lt span class hljs constant DOCTYPE span html gt lt html gt lt head gt lt meta charset 61 span class hljs string 34 UTF
  • Ubuntu编译安装Node.js

    编译安装nodejs 1 wget c https nodejs org dist v6 9 1 node v6 9 1 tar gz 2 tar zxvf node v6 9 1 tar gz 3 cd node v6 9 1 4 con
  • node.js的post和get简单取值

    span class hljs reserved var span http 61 span class hljs built in require span span class hljs string 39 http 39 span s
  • php 判断是移动端还是pc端访问web页面

    function is mobile span class hljs variable user agent span 61 span class hljs variable SERVER span span class hljs stri
  • mongodb的where条件

    mongodb的where条件 1 比较条件 等于 db tian find span class hljs string 39 name 39 span span class hljs symbol span class hljs str
  • ZED相机的使用

    下面简要说明一下ZED双目相机的使用 1 开发环境搭建 首先zed的相机必须要nvidia显卡支持 xff0c 没有的同学可以洗洗睡了 xff0c 或者你可以拿来当普通相机用 首先安装cuda xff0c 再去zed官网下载对应cuda版本
  • libcurl第十一课 使用以及注意事项

    经验 1 xff09 配合Postman能够快速的生成例子代码 2 xff09 curl global init初始化 如果调用curl库函数的时候 xff0c 没有调用curl global init进行curl全局变量的初始化 xff0
  • 基于ROS的hector-slam使用Kinect V1建图

    距离值在ROS中被称为scan xff0c 并且姿态 xff08 位置 43 方向 xff09 信息会根据相对坐标关系而改变 xff0c 因此被称为tf xff08 transform xff09 一 建图实际操作 下载源码测试源码 xff
  • 下载Fiddler后不知从何下手?来看看怎么抓包抓接口吧

    1 Fiddler简介 Fiddler是位于客户端和服务器之间的一个代理 xff0c 类似于生活中厂家和客户之间的代理商或微商 2 Fiddler抓包实战 当打开Fiddler时 xff0c 便会自动开启代理服务器 xff0c 监听端口号抓
  • socket、select、poll、epoll实现TCP并发处理

    网络通信 常用网络通信接口大概四种 xff0c socket select poll epoll 使用socket实现服务器的并发处理 优点 xff1a 代码框架简单 缺点 xff1a 碍于内存的限制 xff0c 并发量不会大 xff0c
  • find_package opencv

    1 find package OpenCV 3 REQUIRED 通过OpenCV DIR变量寻找OpenCVConfig cmake文件 xff0c 默认在 usr share OpenCV中 set OpenCV DIR 34 34 指

随机推荐