SPD 光谱功率分布

CoefficientSpectrum

根据给定采样数表示光谱,为RGBSpectrum、SampledSpectrum的父类。

重载大量的基础代码,比较简单不做赘述。其中为了方便访问对应区域的SPD,而重载了[]操作符。(TabulatedBSSRDF等会用到)

该类只要以各种基础运算函数、重载各种操作符为主,以及一个Float c[nSpectrumSamples];用于保存SPD信息。

SampledSpectrum

SampledSpectrum则将光谱表达为波长范围上的采样点集合。(通过采样求得光谱系数)

人眼对400~700纳米波长的光最敏感,通常采样量为30即可准确地表示渲染时的SPD

    static SampledSpectrum FromSampled(const Float *lambda, const Float *v,int n) {//如果处于无序状态,则在排序后在返回结果spectrumif (!SpectrumSamplesSorted(lambda, v, n)) {std::vector<Float> slambda(&lambda[0], &lambda[n]);std::vector<Float> sv(&v[0], &v[n]);//SortSpectrumSamples:讲sLambda与sv放入一个map中,使用sort进行排序后在放回对应的Vector//这里出现了一个骚操作,因为Vector存储的数据是紧挨着存储的和数组一样,所以可以直接用float*取地址进行操作SortSpectrumSamples(&slambda[0], &sv[0], n);return FromSampled(&slambda[0], &sv[0], n);}SampledSpectrum r;for (int i = 0; i < nSpectralSamples; ++i) {//计算该采样区域的平均值Float lambda0 = Lerp(Float(i) / Float(nSpectralSamples),sampledLambdaStart, sampledLambdaEnd);Float lambda1 = Lerp(Float(i + 1) / Float(nSpectralSamples),sampledLambdaStart, sampledLambdaEnd);r.c[i] = AverageSpectrumSamples(lambda, v, n, lambda0, lambda1);}return r;}
Float AverageSpectrumSamples(const Float *lambda, const Float *vals, int n,Float lambdaStart, Float lambdaEnd) {for (int i = 0; i < n - 1; ++i) CHECK_GT(lambda[i + 1], lambda[i]);CHECK_LT(lambdaStart, lambdaEnd);//处理越界以及单一采样的情况if (lambdaEnd <= lambda[0]) return vals[0];if (lambdaStart >= lambda[n - 1]) return vals[n - 1];if (n == 1) return vals[0];Float sum = 0;//如果头尾采样都在区间内,则将其加入结果中if (lambdaStart < lambda[0]) sum += vals[0] * (lambda[0] - lambdaStart);if (lambdaEnd > lambda[n - 1])sum += vals[n - 1] * (lambdaEnd - lambda[n - 1]);//移动到对应的区间int i = 0;while (lambdaStart > lambda[i + 1]) ++i;CHECK_LT(i + 1, n);//遍历各个区间,通过插值计算平均值,最终加到结果中auto interp = [lambda, vals](Float w, int i) {return Lerp((w - lambda[i]) / (lambda[i + 1] - lambda[i]), vals[i],vals[i + 1]);};for (; i + 1 < n && lambdaEnd >= lambda[i]; ++i) {Float segLambdaStart = std::max(lambdaStart, lambda[i]);Float segLambdaEnd = std::min(lambdaEnd, lambda[i + 1]);sum += 0.5 * (interp(segLambdaStart, i) + interp(segLambdaEnd, i)) *(segLambdaEnd - segLambdaStart);}return sum / (lambdaEnd - lambdaStart);
}

针对任意SPD转化为$ X_\lambda Y_\lambda Z _\lambda$的计算,PRBT通过三条曲线进行适配。
所有的Spectrum都必须提供这个方法。在渲染图片的一个像素时,一束携带光谱信息的光线射入摄像机中的胶片,第一步胶片会将SPD转化为xyz系数,再经过一系列处理,最终将其转化为可以显示的RGB值。

RGB系数根据基于SPD相应曲线积分计算获得。对于既定曲线,乘积积分可通过预计算实现,并将全转换表示为一个矩阵。

inline void XYZToRGB(const Float xyz[3], Float rgb[3]) {rgb[0] = 3.240479f * xyz[0] - 1.537150f * xyz[1] - 0.498535f * xyz[2];rgb[1] = -0.969256f * xyz[0] + 1.875991f * xyz[1] + 0.041556f * xyz[2];rgb[2] = 0.055648f * xyz[0] - 0.204043f * xyz[1] + 1.057311f * xyz[2];
}inline void RGBToXYZ(const Float rgb[3], Float xyz[3]) {xyz[0] = 0.412453f * rgb[0] + 0.357580f * rgb[1] + 0.180423f * rgb[2];xyz[1] = 0.212671f * rgb[0] + 0.715160f * rgb[1] + 0.072169f * rgb[2];xyz[2] = 0.019334f * rgb[0] + 0.119193f * rgb[1] + 0.950227f * rgb[2];
}void ToRGB(Float rgb[3]) const {Float xyz[3];ToXYZ(xyz);XYZToRGB(xyz, rgb);
}

RGBSpectrum

讲光谱系数转化为RGB值(先转成x、y、z,再转成RGB值)

static RGBSpectrum FromSampled(const Float *lambda, const Float *v, int n) {if (!SpectrumSamplesSorted(lambda, v, n)) {std::vector<Float> slambda(&lambda[0], &lambda[n]);std::vector<Float> sv(&v[0], &v[n]);SortSpectrumSamples(&slambda[0], &sv[0], n);return FromSampled(&slambda[0], &sv[0], n);}Float xyz[3] = {0, 0, 0};for (int i = 0; i < nCIESamples; ++i) {Float val = InterpolateSpectrumSamples(lambda, v, n, CIE_lambda[i]);xyz[0] += val * CIE_X[i];xyz[1] += val * CIE_Y[i];xyz[2] += val * CIE_Z[i];}Float scale = Float(CIE_lambda[nCIESamples - 1] - CIE_lambda[0]) /Float(CIE_Y_integral * nCIESamples);xyz[0] *= scale;xyz[1] *= scale;xyz[2] *= scale;return FromXYZ(xyz);
}Float InterpolateSpectrumSamples(const Float *lambda, const Float *vals, int n,Float l) {for (int i = 0; i < n - 1; ++i) CHECK_GT(lambda[i + 1], lambda[i]);if (l <= lambda[0]) return vals[0];if (l >= lambda[n - 1]) return vals[n - 1];int offset = FindInterval(n, [&](int index) { return lambda[index] <= l; });CHECK(l >= lambda[offset] && l <= lambda[offset + 1]);Float t = (l - lambda[offset]) / (lambda[offset + 1] - lambda[offset]);return Lerp(t, vals[offset], vals[offset + 1]);
}

因为这里的代码都要后面几章才会用到,看得不太明白,待看到后面几章后再补充。

剩下的辐射度部分比较简单(稍微介绍了一下brdf、btdf、bsdf、bssrdf,而且和第二版是一样的),而且知乎上已经有一些比较好的解释了,不做赘述。不过我依然建议去看原文。

转载于:https://www.cnblogs.com/blueroses/p/9961009.html

PBRT笔记(4)——颜色和辐射度相关推荐

  1. PBR理论基础1:辐射度与BRDF

    前置:UnityShader9:光照基础回顾 一.反射等式(Reflection Equation) 定义: :观察视角 :入射方向 :表面法向量 有基于物理的反射等式:,其为渲染方程的一个实例:其中 ...

  2. 辐射度算法(radiosity)原理

    简单地说,辐射度算法就是:把场景细分到很细很细的面片(如1个像素那么大的三角形),分别计算它们接受和发出的光能,然后逐次递归,直到每个面片的光能数据不再变化(或者到一定的阀值)为止.因此,计算量很大( ...

  3. 光通量、照度、光强度、亮度、辐射度、色彩还原的概念

    当我们想设计一个显示屏背光时,可能知道一些下面的知识,会让我们做的更好. 1.光通量 光通量指光源发出的光且被人眼感知的光亮. 备注1:当提到光源时,辐射功率通常用辐射通量代替. 备注2:通量指所有方 ...

  4. 计算机图形学【GAMES-101】11、渲染前沿技术介绍(双向路径追踪BDPT、MLT、光子映射、实时辐射度、外观建模)

    快速跳转: 1.矩阵变换原理Transform(旋转.位移.缩放.正交投影.透视投影) 2.光栅化(反走样.傅里叶变换.卷积) 3.着色计算(深度缓存.着色模型.着色频率) 4.纹理映射(重心坐标插值 ...

  5. 3d游戏开发――辐射度算法

    Hugo Elias 何咏 译 声明:本文原文由Hugo Elias 撰写,由何咏 翻译.本文仅供学习交流之用. 任何人未经本人同意不得私自转载,任何人不得将本文用于任何商业活动. 简 介:这篇文章是 ...

  6. 转:辐射度算法(radiosity)原理

    转:辐射度算法(radiosity)原理 http://blog.sina.com.cn/s/blog_537cc4d90101iiil.html 简单地说,辐射度算法就是:把场景细分到很细很细的面片 ...

  7. Games101课程笔记_lecture20_color颜色

    Games101课程笔记_lecture20_color颜色 1 light Field/Lumingraph 1 全光函数 2 光场 3 光场相机 2 颜色 1 光谱 2 颜色 1 人靠什么感知颜色 ...

  8. 利用辐射光谱计算温度 matlab,时间调制型FTIR光谱仪辐射度定标方法的研究

    1引言近年来,由于时间调制型FTIR自身具有灵敏度高.光谱分辨率高和波数准确度高等优点,其在实际中的应用越来越多,无论是军用.工业应用还是民用,时间调制型FTIR都有着广阔的应用前景[1-5].辐射度 ...

  9. 1.辐射度学以及四个基本量

    辐射度学是什么? 本篇博客在理论基础上加入自己的初步理解,致力于形象结束辐射度学相关概念. 如果看完还是觉得不清楚,可以访问个人博客:https://zhaishengfu.github.io查阅辐射 ...

最新文章

  1. Repeater中嵌套DropDownList
  2. 二. 主流视频编码标准的发展
  3. hdu5459(2015沈阳网络赛J题)
  4. 计算机任务驱动法教学应用,任务驱动教学法在计算机教学中的应用
  5. 服务器此时无法接受控制信息,您无法修改域或信任信息,因为无法联系一个主域控制器(PDC)仿真器,请确认当前域的PDC仿真器和网络都联机并正常运行。...
  6. java 绘图 打印_java调用本地打印机,绘制打印模板,小票模板
  7. 做朋友圈需先从做人开始
  8. 用java编写录音机类_java实现录音机
  9. PHPStorm 设置背景图片
  10. Python中列表的常用方法总结
  11. 用java编写英寸到厘米的转换_像素、英寸、厘米的换算 - flyinglife - JavaEye技术网站...
  12. Python3自定义包
  13. Python期末大作业 —— 射靶
  14. React18 tearing tree issue 撕裂状态问题
  15. luoguP1903 [国家集训队]数颜色 / 维护队列
  16. (翻译)箭头和省略号的使用方式
  17. java常见的面试题
  18. windows找不到文件gpedit.msc怎么办?
  19. [《关于外婆家的一些记忆》闲笔记事集]2012年1月22日
  20. linux 证书文件权限,Linux运维之道之admin1.4(权限和归属,LDAP认证)

热门文章

  1. 吴恩达 deeplearning.ai 新课上线:TensorFlow 移动和 web 端机器学习
  2. 人脸识别百亿蓝海之下,还需解决两方面问题
  3. 对中国医学影像AI产品商业化的思考
  4. 让AI计算无处不在,华为干了一件大事
  5. 2020上半年收集到的优质AI文章 – AI+和+AI
  6. 2020 年最值得学习的 5 大 AI 编程语言
  7. 一文读懂深度学习:这个AI核心技术被美国掌控,很危险
  8. 蔚来李斌:自动驾驶好处是解放生产力、保障生命安全
  9. 对话式AI 2019年遇来的新市场
  10. DeepMind网红博士300页论文出炉:面向NLP的神经迁移学习