【学习总结】Ray Tracing in One Weekend(梳理与总结)

被群友推荐了这个光追(这一篇应该是路径追踪)教程,学完下来确实收获蛮多的,也解决了以前遗留的很多问题。最大的感触是,图形学是真的好玩,hhhhh 晚点看看能不能开个超清分辨率来渲染一张图,就看GPU能不能挺住了。

如果有错误的地方,欢迎指出

代码上传到GitHub(刚开通,别骂了别骂了)了~可供大家下载(使用Visual Studio 2017)
Mygit-RayTracing in One Weekend

这门课的前置知识可能需要闫令琪老师的101课程,b站就可以搜得到(强推)

整个制作流程原文在这里:Ray Tracing in One Weekend
但我推荐这位老哥的翻译:中文翻译
本文还有一些引用的地方来自于这一篇我觉得也可以成为教程级的博客:光线追踪渲染实战

原理

光追概述

光线追踪有别于传统的光栅化技术,是一种真正的基于物理模拟的渲染技术。
一般来说,光线追踪应该是从光源出发,模拟每一束光在场景中的弹射和碰撞,最后收束到摄像机之中
在这里插入图片描述
但是这样以来,计算量就实在是太大了。最主要的原因就是每一个像素接收到的光线数量可能是难以计数的。因此,我们会采用一个反向的策略,即从摄像机屏幕这边的每一个像素出发,发射光线去场景中碰撞得到结果。这种方式我们一般叫做路径追踪(光追的分支)
在这里插入图片描述
光线追踪的原理很简单,概括起来可以分为以下几步:

  1. 从每一个像素发射一系列的采样线(在像素内随机发射)
  2. 计算每一条采样线在场景中的碰撞和弹射,并逐渐积累颜色
  3. 将这些颜色值返回之后取平均即可得到一个像素对应的颜色值

那么怎么描述发出的线与场景中的物体在某一交点的颜色呢?
我们可以将对一个点入射的无数光看作是该点入射面半球的积分积累,通过计算一个半球面的积分来确定整体入射光的强度。
而这里就可以引入渲染方程(上方所说的半球积分)了:
在这里插入图片描述
可以注意到这个方程是一个递归的形式,同时也是一个困难积分,于是就要用到蒙特卡洛积分方法了~
蒙特卡洛积分方法的做法一句话就可以说的清楚:通过离散的采样来模拟连续的最终结果
使用该方法有两个好处:

  1. 约束整个场景中的光线数量,减少运算次数。将每一次的弹射递归数(即光线弹射发散的数量)约束到可控范围
  2. 可以避免进行渲染方程这样一个复杂函数的计算,通过简单的采样取平均得到他的结果
  3. 多次采样还可以抗锯齿

注:虽然在教程中没有提及这个积分方法,但是在做抗锯齿的时候用的却是也是多次采样取平均的方法

以上就是光线追踪的大致原理了。

教程做了些什么

教程做的事情其实无非就是把整个光追的过程给抽象出来:
在这里插入图片描述
大致流程如下:
在这里插入图片描述

  1. 原理部分已经说过了,路径追踪是对每一个像素发出一系列的光线去场景中碰撞,散射最后得到一个颜色的积累值。所以教程的主循环里面也正是用一个二重循环去遍历每一个像素做处理。(注意:由于整个场景都是运行在CPU上的,所以分辨率根据自己电脑的实际情况控制,不然渲染要好久)
  2. 从Camera类打出的每一条光线,都是通过ray_color()函数来计算颜色的,计算结果进行逐个累积
  3. ray_color()函数是一个递归函数,模拟的是场景中光线的碰撞。由于碰撞次数很可能是无数次,所以为了避免函数爆栈,教程中我们人为的给他限制到了50次的一个递归次数。在这个函数中,首先是通过场景列表(这里就没有什么资源树去做优化了)遍历每一个元素,计算它们的交点(只计算第一个碰撞的交点),得到交点之后,得到第一个相应的颜色值和衰减度(教程中都是attenuation),然后得到这个物体的材质(BRDF),去得到反射的光线,然后再次调用ray_color()计算
  4. 经过N轮弹射(递归),我们也就得到了一条光线的颜色采样值。对,没错,仅仅是一条。然后你还有99条(教程中设定的是每一个像素一百条采样线)采样线需要同样的计算。接着这样的计算需要扩展到每一个像素。所以,光追如果没有GPU的支撑,计算是相当缓慢的

主要的函数可以这样去跟,其它的流程教程中已经讲的很清楚了:
在这里插入图片描述

一些问题

  1. 最开始输出颜色值为255.999是因为颜色值是取不到256的
  2. ray类是最重要的光线类,这里用的是射线线性模拟,即
    在这里插入图片描述
    在这里插入图片描述
  3. 输出为ppm格式,可以用极速看图打开,还挺好用
  4. 最开始地面的是绿色的原因是因为下方的大球显示在屏幕里的部分法向量全部朝上,你可以看看小球的顶部是不是也是绿色(最开始是将法向量直接输出为颜色的,还挺好看的↓)
    在这里插入图片描述
  5. 线性插值的一般方式:
    在这里插入图片描述
  6. 光追的抗锯齿方法是通过同一像素发出多条射线进行随机采样然后取平均完成的
  7. 文中用到的随机方法基本都是球模拟法。用一个球体来随机采样得到随机的反射结果。(不论是漫反射材质还是金属球的模糊效果都是用这个方法来做的)
  8. 反射向量的计算方法(reflect):
    在这里插入图片描述
  9. 材质类应该至少做两件事情:(1)计算散射了多少光线,并返回衰减度和颜色 (2)需要告诉程序经过这个材质表面散射后的光线是怎么样的

10.相机旋向的计算问题(看图吧,对着源码理解):
在这里插入图片描述
10. 伽马矫正
简单来说,伽马矫正是为了适应人眼的特性而出现的。人类的视觉系统进化出了一个特性,黑暗环境下的辨识能力要强于明亮环境,这可能有助于我们及时发现黑暗中隐藏的危险。因此在有限的计算机颜色(民用显示器和操作系统中黑色到白色256个色阶)中,亮色和暗色均匀分布的话,那亮色部分就会精度过剩而暗色部分就会精度不足。更多详细的内容可以参考这篇知乎回答:伽马矫正
最直观的感受参考下图(from learnopengl):
在这里插入图片描述
11. Snell定律无解的情况出现时,我们一般认为它发生了反射。而有时还会发生全内反射。(比如教程举例的光线想从玻璃球里面进入大气)

720P渲染图片

由于没有做并行运算,也没有使用Compute Shader,直接CPU做渲染整了七个小时…
在这里插入图片描述

  • 8
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Ray Tracing(光线追踪)是一种在计算机图形学中使用的技术,用于生成高度逼真的图像。它通过跟踪光线从视点开始的路径,来模拟光在场景中的运动,计算出光线与物体的交点以及光线在经过物体时的反射、折射等效果,并最终生成图像。 以下是光线追踪的基本步骤[^1]: 1. 从相机位置发出一条光线。 2. 确定该光线与场景中物体的交点。 3. 计算该交点处的光照强度,包括直接光照和间接光照。 4. 根据物体的表面特性,计算反射或折射光线的方向和强度。 5. 递归计算反射或折射光线的路径,直到达到最大递归深度或光线不再与物体相交。 6. 将所有光线的颜色值组合在一起,得到最终的图像。 下面是一个简单的 Python 代码示例,演示了如何使用 Pygame 和 PyOpenGL 库实现简单的光线追踪效果[^2]: ```python import pygame from OpenGL.GL import * # 初始化 Pygame 和 PyOpenGL pygame.init() display = (800, 600) pygame.display.set_mode(display, pygame.DOUBLEBUF | pygame.OPENGL) # 设置相机位置和方向 glMatrixMode(GL_MODELVIEW) glLoadIdentity() gluLookAt(0, 0, 0, 0, 0, -1, 0, 1, 0) # 设置场景中的物体 glColor3f(1, 1, 1) glBegin(GL_TRIANGLES) glVertex3f(-1, -1, -5) glVertex3f(1, -1, -5) glVertex3f(0, 1, -5) glEnd() # 定义光线追踪函数 def raytrace(x, y): glReadBuffer(GL_BACK) color = glReadPixels(x, y, 1, 1, GL_RGB, GL_FLOAT) return color # 创建主循环 while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() quit() # 绘制场景和光线 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glBegin(GL_LINES) glVertex3f(0, 0, 0) glVertex3f(0, 0, -5) glEnd() # 调用光线追踪函数 x, y = pygame.mouse.get_pos() w, h = display color = raytrace(w - x, h - y) # 输出光线追踪结果 print("Color at (%d, %d): %s" % (x, y, color)) # 更新 Pygame 显示窗口 pygame.display.flip() ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值