news 2026/4/15 17:34:44

基于C++实现的基于物理的图像渲染引擎

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于C++实现的基于物理的图像渲染引擎

在本地编译前,请在 settings.h 中更新 workspace 路径,为使用 openmp,请使用”-fopenmp“参数进行编译

本来这两周计划测试不同 bvh 算法、实现 photonmapping 和 GUI 的,但是最近要去实验室,所以没空写也就算了。

图 1 样例

系统构架

目前没有使用 make/cmake,但都留了接口 │ background.h 背景光 │ bound.h 即 AABB,用于 hit 时的搜索 │ camera.h 相机模块 │ hitable.h 光线与物体相交模块,管理 hitable 文件夹中的各种形状 │ log.txt 运行日志 │ main.cpp CLI 主函数 │ main.exe CLI 编译程序 │ material.h 材质模块,管理 material 文件夹各种材质 │ picture.ppm 输出的 ppm 格式图片 │ ray.h 光线 Class │ README.md │ sampler.h 取样模块,即 Monte-Carlo,管理 sampler 文件夹采样函数 │ scene.h 场景(目前全部写在一个文件中) │ geometry/geometry.h 3vector Class │ ├─accelerator 加速模块,目前只写了 bvh 加速,kd-tree 和基于其上的 photon-mapping 还没来及写 │ │ bvh.h bvh Class │ │ │ └─bvh_method │ bvh_build.h bvh 函数定义 │ bvh_node.h bvh 使用的 struct │ ├─gui GUI 界面,使用 Qt5 ├─hitable │ aabb.h 实际上使用的是 bound.h │ cube.h 采用 intersect 方法写的 cube(还可以使用三角面片等方法实现) │ cylinder.h 圆柱体 │ hitable_list.h 其实应该叫做 Union,是 hitable 集合的并 │ intersect.h Intersect, hitable 集合的交 │ plane.h 无穷大平面 │ sphere.h 球 │ triangle.h 三角面片 │ ├─loader 文件加载器 │ │ myobjloader.h 自己写的 c based obj/mtl 模型文件加载 │ │ mypngloader.h 基于 stb_image 的图片加载器(理论上不仅支持 png),本来尝试使用 pnglib,但很笨重,最后决定直接用 stb │ │ │ └─external │ stb_image.h │ ├─material │ glass.h 玻璃 │ lambertian.h 余弦体 │ metal.h 金属 │ source.h 光源 │ texture.h 贴图 │ ├─model 模型文件(目前仅支持 obj/mtl,可以使用开源的 blender 转格式) │ ├─mylib │ common.h 基本所有模块都要用到的基本头 │ mycode.h 我 coding 是的一些习惯性宏或函数 │ mylogo.h Cli 界面 LOGO │ myrand.h 随机数生成器 │ onb.h onb 模块,用的不是太多 │ settings.h 编译参数宏(利于使用什么算法,是否打开色散 etc.)可以用 cmake 输入,根据需求进行编译 │ ├─notes 笔记 │ bvh.md │ idea.md │ ├─pics 输出(各种测试)图片 │ ├─png png 格式输出 │ └─ppm ppm 格式输出 │ ├─sampler │ cos_sampler.h 余弦分布采样 │ hit_sampler.h 光源 oriented 采样 │ mix_sampler.h 混合采样 │ └─test 测试模块

交互界面

GUI 使用 Qt5,但是还没来及写好,下图是作为替代随便写的 Cli 交互界面

图 2 CLI

Hitable

几何体

几何体实现都不复杂因为懒只实现了 cube、sphere、plane、cylinder,其实使用牛顿下山等方法,任意曲面都很好实现。

  • cylinder
    目前的实现在代码层面上有些暴力,可优化
  • cube
    cube 虽然有多种方法,但这里实现的其实更鲁棒一点,实际上实现的是平行六面体,比 cube 有更高的自由度。
逻辑物体

hitable_list 和 Intersect 实现的时物体组的交并

三角面片

很简单(解的三元线性方程组即可)又很重要,不做赘述,值得一提的时 obj 文件是右手螺旋顺序,以及当下的实现尽可能将计算量预处理在生成三角面片时,但是会浪费存储(目前跑下来加上贴图和模型内存占用也并不大,所以不是什么问题)

如图二是加载了 02 模型加贴图,使用了 bvh 树,20000spp,8 线程 openmp 的资源占用:


图 3 任务管理器

Material

玻璃
色散(dispersion)

玻璃的折射与投射都是很基础的内容,很容易实现,这里额外实现了色散(dispersion)效果,因为只是将光线在第一次发生色散时分为三个通道分别走 rgb 而已(和容易看到,光线可逆对色散也成立,所以可以这样做),复杂度增加是常数量级(<3),在 settings.h 种可以设置宏的值开关决定是否编译色散的部分,为了节省资源,一半会将色散关闭。

正常玻璃 rgb 折射率跨度只有约 0.5,因此没必要用Sellmeier equation,不过为了让效果稍微明显点,图 4 使用了 1.5-1.6 的折射率跨度,注意物体的边缘有明显的色散效果。

全反射

显然,全反射在球形玻璃中不会出现,但图 4 中立方体中可以看到明显的全反射。

图 4 dispersion

金属和余弦体

没什么好说的

光源

光源目前使用的是球状面光源,三角面片的面光源也实现了,但并未使用,因为在 Monte-Carlo 中为了使用重要性采样,需要计算面光源的立体角,而三角面片的立体角无法在 O(1)时间内精准计算,只能在足够远或三角面片足够小的近似下计算,所以有可能造成光源近处物体的失真(但是应该看不出来,而且只要三角面片够小也可以)

另外还有 directed source,准备和 photon-mapping 一起实现(因为可以做出汇聚光的效果)

Texture

Texture 通过计算碰撞点相对贴图的 uv 坐标返回反射率或颜色,目前只有 png 和常数贴图(即单色),其他实现的必要似乎也不大。

只实现 png 的主要原因是 png 是无损压缩,大部分模型贴图使用的都是 png 格式。

下图 5.1 是 02mainbody 贴图,5.2 是在室外的渲染效果,颜色比较淡的原因是使用了 gamma 修正,而图 5.3 则是关闭 gamma 修正的效果(都是 100spp)。

图 5.2 gamma on

图 5.2 gamma on

Camera

目前 Camera 只能设置 FOV,LookFrom,LookAt,还不支持焦距,之所以不支持原因是现在只是用了纯 Monte-Carlo,因此噪音已经很大了,如果加上焦距(和延迟摄影)效果,采样自由度又会增加,从而造成噪音不可控(具体可以参见 sampler 部分)。

但是只要利用焦平面和透镜组三基点(主点、节点、焦点)的性质,并在 Class ray 中加上时间自由度,景深和延迟摄影效果都很好实现。

Sampler

采用了重要性采样的 Monte-Carlo,简单而言就是让更多的光线打到亮的地方(例如光源,平面镜,玻璃),之后通过加权得到真实的亮度,这样有两点好处

  1. shader 更容易打到光源上终止,即 shader 深度降低,大大提升程序效率
  2. 因为大部分 sample 光强比较大,这样绝对误差就会更小
  3. 同样较低的采样率,使用 monte-carlo 显然会更亮(更接近实际情况)

特别是在黑暗的环境中,如果不用重要性采样的 Monte-Carlo,场景就会一片黑暗

图 6.1, 6.2 是同样 sample 数下(300spp)使用与不使用重要性采样的对比(其中图 6.2 中墙上的影子是一个小 bug,已经修复了)

图 6.1 300spp 不使用重要性采样的 Monte Carlo

图 6.1 300spp 使用重要性采样的 Monte Carlo

但是 Monte-Carlo 这种纯采样机制,注定会噪声很大,图 7 是 wiki 上的对比,每张图都比前一张采样率翻倍,可以看到 noise 是 Monte-Carlo 无法避免且致命的缺陷。

图 7 Monte Carlo 噪声变化

随机数生成

随机数生成对图片的噪声(显然)也有很大影响

图 8.1 和 8.2 是同样 spp 同一场景下使用不同随机数生成方法得到的结果(因为场景生成也用了随机数,所以场景也略有不同)

图 8.1 随机数生成器 1

inline double random_double() { return rand() / (RAND_MAX + 1.0); }

图 8.2 随机数生成器 2

static double random_double() { static std::random_device seed_gen; static std::mt19937 engine(seed_gen()); static std::uniform_real_distribution<> dist(0.0, 1.0); return dist(engine); }
Cos-sampler

按余弦分布采样,对于有环境光的场景(室外),以为余弦体就是余弦分布,这样采样采样率分布与实际贡献一致,误差最小

hit-sampler

像光源(或玻璃)采样

mix-sampler

支持任意数量 sampler 按任意权重加权采样,一般采用 cos,hit 各一半进行采样。

Shader

目前没有单独出来作为一个模块,功能主要是递归的 path tracing。

Loader

写的时候使用了 C 风格的输入输出,后面会替换程 cpp 风格

图 9 是没有加载贴图的效果

图 9 no texture 02 indoor

Accelerator

加速模块主要是 bvh、kd-tree、photon mapping,不过目前只实现了 bvh

bvh

之所以使用 bvh 而非 kd-tree(photon mapping 会使用 kd-tree),原因在于 bvh 虽然是基于物体的分割(kd-tree 是基于空间的分割),造成无法保证前后遮挡关系,不能终止树的遍历,从而导致性能不如 kd-tree,但是 kd-tree 可以维护(以为着可以适用于 RTRT 场景)并且通过一些加速算法(例如我使用的 ordered bvh),可以达到与 bvh 不相上下的效果,自然会更 popular,可以参考 Stack Exchange 上的回答。

本文参考了 Wald et. al.的论文和 PBRT 的实现,不过应为还没来及测试各种算法实际跑出来的速率,所以具体细节会放到下一次作业,这里只简单提一下:

  1. 因为现在渲染的是静态场景,所以考虑的是尽可能牺牲 bvh build 的时间和空间换取 shading 的速度。因此采用的是遍历 O(n)种 SAH 取其中最优解的方法(共 O()种),因为无法避免排序,所以bvh build的时间是,从图二可以看到,02 的 bvh build time 大约 20sec,使用 bucket SAH 应该可以有十倍以上加速,但不知道 shading 速度会减多少。
  2. 采用了排序的 bvh,这样每次都会先访问中心靠光线更近的 bvh,虽然不能立刻终止,但可以尽可能减小 t_max(光线 hit 的上界)从而尽早终止。
  3. 所有物体都按照 2 种访问顺序重排,这样有更大的概率访问内存种连续部分,且顺序访问
  4. bvh node 使用了 32 位对准
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 11:08:28

多机器人全覆盖路径规划:改变地图与机器人数量的Matlab实现

多机器人全覆盖路径规划&#xff0c;可改变地图和机器人数量matlab最近在研究多机器人全覆盖路径规划的问题&#xff0c;发现这玩意儿挺有意思的。简单来说&#xff0c;就是让一群机器人在一个地图上走一遍&#xff0c;确保每个角落都被覆盖到&#xff0c;而且效率还得高。今天…

作者头像 李华
网站建设 2026/4/15 5:35:02

LangFlow增量静态再生(ISR)应用场景

LangFlow 与增量静态再生&#xff1a;让 AI 工作流高效落地 在构建 AI 应用的今天&#xff0c;一个常见的困境是&#xff1a;模型能力越来越强&#xff0c;但把它们变成用户真正能用的产品却依然困难重重。我们花大量时间写代码、调接口、处理数据流&#xff0c;而业务方还在等…

作者头像 李华
网站建设 2026/4/16 8:59:37

Open-AutoGLM脱敏规则进阶配置(仅限内部分享的7种高级模式)

第一章&#xff1a;Open-AutoGLM 数据脱敏规则定制在构建企业级大模型应用时&#xff0c;数据安全与隐私保护是不可忽视的核心环节。Open-AutoGLM 提供了一套灵活可扩展的数据脱敏机制&#xff0c;支持用户根据业务场景自定义脱敏规则&#xff0c;确保敏感信息在模型训练与推理…

作者头像 李华
网站建设 2026/4/11 15:51:54

为什么你的敏感数据识别总失败?Open-AutoGLM五大优化策略首次披露

第一章&#xff1a;为什么你的敏感数据识别总失败&#xff1f;企业在实施数据安全策略时&#xff0c;常依赖敏感数据识别技术来发现和分类关键信息。然而&#xff0c;许多组织发现其识别准确率远低于预期。问题根源往往不在于工具本身&#xff0c;而在于实施过程中的常见误区。…

作者头像 李华
网站建设 2026/4/16 6:47:25

【数据安全新纪元】:基于Open-AutoGLM的敏感信息识别优化方案全公开

第一章&#xff1a;数据安全新纪元的挑战与机遇随着云计算、人工智能和物联网技术的迅猛发展&#xff0c;数据已成为企业最核心的资产之一。然而&#xff0c;数据规模的爆炸式增长也带来了前所未有的安全挑战。传统防火墙与加密手段已难以应对日益复杂的网络攻击&#xff0c;零…

作者头像 李华
网站建设 2026/4/11 22:19:43

为什么90%的AI系统存在隐私漏洞?Open-AutoGLM审计方案一文讲透

第一章&#xff1a;为什么90%的AI系统存在隐私漏洞&#xff1f;人工智能在医疗、金融和社交平台等关键领域广泛应用&#xff0c;但随之而来的隐私风险却常被忽视。研究表明&#xff0c;超过90%的AI系统在数据处理或模型训练阶段存在潜在隐私泄露路径&#xff0c;其根源往往并非…

作者头像 李华