一个周末搞懂光线追踪 理论+实践

一个周末搞懂光线追踪 理论+实践

本文翻译自 Ray Tracing One Weekend

  • 后续将继续做出演示demo,敬请关注

1 显示结果的方法

  • 使用PPM格式图片展示渲染结果
  • PPM格式很方便,改了就能看到改变

2 vec3类

  • 虽然有4D vector,但是本文使用3D vector就够了
    • 位置、缩放、旋转
    • 颜色
  • 提供基本的向量运算操作
    • 数学4则运算
    • 模长

3 射线、简单的相机、背景

  • ray tracer
    • ray class
    • 计算一条射线能看到什么颜色
  • P(t) = A + t * B
    • t 浮点参数
    • A 射线起点
    • B 射线方向
  • 射线追踪的核心
    • 发射穿过像素的射线
    • 计算通过这些射线能看到的颜色
  • 使用的图片
    • 200x100
    • 中心点(0,0)
    • y轴向上、x轴向右
  • 朝向屏幕的是z轴负方向,朝向屏幕外的是z轴正方向
  • 从屏幕左下角扫描屏幕,使用2个偏移向量来移动射线终点来穿过屏幕
    • lower_left_corner + u*horizontal + v*vertical
    • horizontal: (4.0,0.0,0.0)
    • vertical: (0.0,2.0,0.0)
  • 没有让射线是单位向量,为了代码保持简单轻快
  • 流程
    遍历每一个像素,把像素坐标转换成到0,1),计算指向每一个像素的射线,计算这个射线的颜色
    

4 加入球体

  • 球体计算直接了当
  • x*x + y*y + z*z = R*R
  • (x - cx)^2 + (y - cy)^2 + (z - cz)^2 = R*R
  • 点p, dot((p-c),(p-c))=R*R
  • 根据公式p(t)=A+t*B
    • dot(p(t)-c,p(t)-c)=R*R
    • 用p(t)展开的形式:dot(A+t*B-C,A+t*B-C)=R*R
  • 展开等式并且左移后得:t*t*dot(B,B)+2*t*dot(A-C,A-C)+dot(C,C)-R*R=0

5 表面法线和多个物体

  • 表面法线垂直于表面指向外面
  • 球体法线:撞击点 - 球心
  • 显示法线的颜色
    • 如果是单位向量,范围是(-1,1),需要把这些值映射到(0,1)
      • x = (x + 1) * 0.5
    • 着色时如果射线抵达的是球体表面显示法线颜色
  • 增加了一个hitable类,用来计算给定射线和tmin, tmax,射线射中了哪里
    • 新的hit函数
      • hit(ray r, float tmin, float tmax, hit_recrod rec)
    • 计算射中球体表面时增加了选择的策略
      • 优先使用距离摄像机较近的那个点,即计算结果中t更小的那个点
      • 这个t必须满足 tmin < t < tmax
  • 创建多个球体用来显示,更新了球体的类和main函数
    • 在main函数中遍历一个hitable列表来渲染多个球体

6 抗锯齿

  • 编写一个Camera类来创建射线
  • 在一个像素点周围做一组采样然后求平均值
    • 在计算一个像素点的颜色的时候循环若干次,随机的在其周围获取像素并且求平均值

7 漫反射材质

  • 分离几何体与材质
  • 漫反射
    • 漫反射物体不发光只根据自身颜色反射环境光
    • 光线在漫反射表面随机反射
    • 如果向2个漫反射物体的夹角里发射射线,射线会随机反射
    • 吸收大于反射
  • 创建反射射线
    • 找到撞击点hit point,撞击点沿着法线上移0.5,获得一个单位球的球心
    • 在球内随机选取一点的方法
      • 在恰好包裹立方体的圆里随机选一点
      • 如果这个点不在球内,重复上一步,直到获得可用的随机点s
    • 获得射线 s - hit point,求这条射线的颜色 color
    • 最终颜色 = 吸收率 * color
  • 伽马矫正:(0,1)的值在被存储为byte前需要被转换
    • 有很多原因,我们知道这事就可以
  • “gamma 2”
    • 提亮颜色:颜色的1/gamma次方
    • 我们这里使用:color的(1/2)次方,即开方

8 金属材质

  • 为了显示不同材质的物体
    • 需要不同材质类型,用不同的参数调整
    • 编写材质类
      • 创建散射光线
      • 指明吸收率
      • 金属材质使用反射公式直接计算反射射线
    • 物体和材质需要互相引用,出现循环引用
  • 反射策略
    • 用反射率R来削弱射线
    • 使用1-R来削弱射线
    • 混用以上2种方法
  • Lambertian材质,拥有反照率参数
  • 越大的球体其反射越显得模糊
    • 增加一个模糊参数fuzz
    • 计算最终的反射射线 reflected + fuzz * random_in_unit_sphere
      • 根据不同大小的球体传入不同的fuzz控制反射射线随机偏移程度,从而控制模糊程度

9 半透明物体

  • 水、玻璃、钻石,半透明物体同时具有反射和折射
  • 射线碰撞到物体时,在反射和折射中随机选一种作为追踪的方式
  • 折射光线的debug是困难的
  • 折射公式:n*sign(theta) = n’*sign(theta’)
  • 折射率过大时折射不会再发生
  • 实践中反射和折射都是发生在固体之间
  • 球体法线向内可以做出气泡效果
  • 本章新增dielectric材质用于渲染半透明物体
  • 如果用一个陡峭的角度,比如基本垂直着看过去,会像镜面,使用Christophe Schlick的简化公式
    • 计算一个阈值,当随机一个点是用折射时发现随机出的值小于阈值,那这里是作为镜面,则使用反射

10 可以调整位置的相机

  • 对相机进行debug是痛苦的
  • adjustable field of view
  • vertical fov
  • 和以前相机的不同
    • 相机制作从左下角到右上角进行扫描的射线
    • 现在使用vfov来准备制作扫描射线的参数,定义宽高比
    • camera(float vfov, float aspect)
  • 关心的位置
    • lookfrom
    • lookat
      • 如果需要,这个可以变成方向
  • 处理旋转
    • view up(vup)
    • u 水平方向
    • v 垂直方向
    • w 从物质指向相机的向量
    • 以上向量都不是单位向量
    • 新的左下角:origin - half_widthu - half_heightv - w
  • 和仅有fov的情况以前相比,现在可以控制相机的位置和朝向

11 视野深度

  • 现实中为了获得更多的光线使用大的孔
    • 如果从孔中伸出一个透镜,会有一个距离能让所有的东西都被聚焦
    • 这个距离被相机的透镜和感知器的距离控制
    • 光圈越大获得的光线越多
  • 虚拟相机有完美的感知器并且不需要更多光线,所有我们只需要光圈
  • 模拟感知、透镜、光圈,指出从哪里发射射线,翻转图片
    • 胶卷中的图片上下颠倒
  • 具体到代码
    • 发射射线的时候从一个圆的表面随机的选取一个点作为射线的起点

12 后续

  • 放一堆材质球到场景里面
  • 列表
    1. 散射射线
    2. 模型
    3. 纹理
    4. 坚实材质
    5. 体积和介质,比如冰块
    6. 并行,用不同的种子+核心运行不同追踪器,gpu ray tracing
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值