C++ 怎么手写光线追踪器中的漫反射光线投射与能量衰减

胖杰同学_7842

胖杰同学_7842

2026-11-02

130人浏览

原创

正确生成漫反射方向需用余弦加权半球采样:构造局部坐标系,用φ=2πξ₁、cosθ=√ξ₂生成方向,并归一化;能量衰减须含albedo、cosθ及1/pdf校正,pdf=cosθ/π,最终衰减为albedo;禁用均匀球面采样,因其pdf=1/(2π)导致能量不守恒。

c++ 怎么手写光线追踪器中的漫反射光线投射与能量衰减

漫反射方向怎么生成:别用均匀球面采样

直接在单位球面上均匀采样得到的方向,会导致 Lambert 漫反射模型的能量不守恒——视觉上物体会过亮,尤其在低粗糙度材质下更明显。正确做法是用余弦加权的半球采样:cosθ 分布(θ 是与法向夹角),让采样密度正比于 cosθ,才能匹配 Lambert 反射率定义。

实操建议:

  • 设表面法向为 n,先构造局部坐标系:用 orthonormal_basis(n) 得到两个正交向量 u、v
  • 生成两个 [0,1) 均匀随机数 ξ₁、ξ₂,计算:
    φ = 2 * M_PI * ξ₁
    cosθ = sqrt(ξ₂)
    sinθ = sqrt(1 - ξ₂)
    direction = u * cosφ * sinθ + v * sinφ * sinθ + n * cosθ
  • 注意:必须归一化 direction(即使数学上已单位化,浮点误差仍可能导致 dot(direction, direction) != 1)

能量衰减怎么算:别漏掉几何项和 PDF 校正

漫反射光线打到新点后,接收到的能量不是简单乘个 albedo 就完事。路径追踪中,每次反弹都要按渲染方程做蒙特卡洛积分,衰减项包含三部分:albedo(反射率)、cosθ(入射角衰减)、1 / pdf(概率密度函数倒数)。

常见错误现象:diffuse surface looks too dark near edges 或 noise spikes on flat diffuse walls,往往就是漏了 1 / pdf。

实操建议:

  • 对上面生成的余弦加权方向,其 PDF(在半球上的概率密度)是 pdf = cosθ / π
  • 因此 BRDF × cosθ / pdf = albedo / π × cosθ / (cosθ / π) = albedo —— 这才是无偏的权重
  • 最终该次散射贡献为:ray_color * albedo * attenuation,其中 attenuation 就是这个简化后的 albedo,但前提是采样逻辑和 PDF 完全匹配

为什么不能直接用 random_in_unit_sphere()?

很多初学者抄代码时直接复用生成单位球内随机点的函数,然后归一化成方向,这本质是均匀球面采样。它在半球上的 PDF 是 1/(2π),而非正确的 cosθ/π。强行套用会引入系统性偏差:所有漫反射都多乘了约 2 倍的 cosθ,导致明暗过渡生硬、边缘发灰、收敛慢。

C++14
C++14

C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。

下载

性能与兼容性影响:

  • 均匀球采样虽快,但需要更高样本数才能压住噪点;余弦加权半球采样虽多两三个 sqrt/sin/cos,但收敛更快
  • 如果后续要支持各向异性或 Oren-Nayar 等扩展模型,余弦加权是基础接口,硬塞球采样会破坏架构一致性

实际写 scatter() 函数时的关键检查点

C++ 中典型的材质 scatter 接口返回是否发生散射、新的光线、衰减系数。漫反射实现里最容易被忽略的是法向朝向和光线方向的一致性判断。

实操建议:

  • 入射光线方向 ray.direction() 是从相机指向交点的,所以真实入射方向是 -ray.direction();确保 dot(n, incident) > 0,否则说明交点在背面,应拒绝散射或翻转法向
  • 生成的散射方向 scattered.direction() 必须满足 dot(n, scattered.direction()) > 0,否则光线会扎进物体内部,造成黑斑或 NaN
  • attenuation 应为 albedo * (1.0f / M_PI)(Lambert BRDF 的常数项),而不是 albedo * cosθ 或其他变体
  • 不要在 scatter() 里做距离衰减(如 1/r²)——那是 ray_color() 递归调用时由光线传播距离自然体现的

余弦加权采样的数学推导不难跳过,但漏掉 PDF 校正或法向朝向检查,调试时几乎无法通过肉眼区分是 BRDF 写错了还是采样错了。这两个地方一旦出问题,噪点模式会非常“有规律”地集中出现在斜面或阴影交界处。

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关专题

更多
c++和c语言的区别有哪些
c++和c语言的区别有哪些

c++和c语言的区别:1、面向对象编程(OOP)支持不同;2、新增特性不同;3、标准库不同;4、编译方式不同;5、命名空间不同等等。想了解更多c++的相关内容,可以阅读本专题下面的文章。

2024.03.14

2288

9

c++和python学习顺序推荐
c++和python学习顺序推荐

一般建议先学习C++,再学习Python,因为这样可以逐步从较为底层的编程语言向更高级的语言过渡。想了解更多python的相关内容,可以阅读本专题下面的文章。

2024.03.14

1039

6

python和c++学习性价比分析
python和c++学习性价比分析

Python易于学习,广泛应用于Web开发、数据科学和人工智能等领域,但性能较低。C语言性能高,适用于对性能要求较高的场景,如游戏开发和系统编程,但学习曲线陡峭,错误处理复杂。想了解更多python的相关内容,可以阅读本专题下面的文章。

2024.03.14

447

5

c语言和c++一样吗
c语言和c++一样吗

c语言和c++是两种不同的编程语言,虽然有相似之处,但存在显著差异。c语言专注于过程式编程和系统级开发,以简洁、高效著称。c++作为c语言的超集,引入了面向对象编程,增强了代码组织和管理能力,但学习曲线也更陡峭。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.14

347

5

c语言和c++先学哪个好
c语言和c++先学哪个好

初学者选择学习c语言还是c++语言,需要根据个人学习目标、背景以及编程兴趣和预期应用方向来决定。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.14

426

5

c语言和c++的区别和联系
c语言和c++的区别和联系

c语言和c++是计算机科学领域应用广泛的编程语言。虽然它们有着相似的基础,但它们在语言类型、语法功能和内存管理方面存在着显著差异。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.14

600

5

c++软件中文更改教程
c++软件中文更改教程

对于 ide,可通过打开设置,找到语言设置,选择中文,并保存更改。对于非 ide 应用程序,可查找设置或选项,选择语言设置,更改为中文,并保存更改。想了解更多c++的相关内容,可以阅读本专题下面的文章。

2024.03.21

1429

9

python和java和c++学习性价比分析
python和java和c++学习性价比分析

Python以其易学性、丰富的库和活跃的社区而著称,适合数据科学、人工智能和Web开发。Java以其跨平台性、企业级应用开发和Android应用开发而闻名。C++以其底层控制能力、高效性能和游戏开发而著称。选择哪种语言取决于个人兴趣、职业方向和特定需求。想了解更多python和java和c++的相关内容,可以阅读本专题下面的文章。

2024.03.22

1237

7

c++和c语言学习顺序推荐
c++和c语言学习顺序推荐

对于初学者,建议先学习C语言,掌握编程基础后再转入C++,便于理解面向对象编程概念。有编程经验者可直接学习C++,快速接触高级编程技术。想了解更多c++和c语言的相关内容,可以阅读本专题下面的文章。

2024.03.25

1325

9

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C++ 手册教程
C++ 手册教程

共41课时 | 78.6万人学习

C++ Core Guidelines
C++ Core Guidelines

共0课时 | 0人学习

C++ Reference
C++ Reference

共0课时 | 0人学习