实现一个片元着色器,模拟天文望远镜的频谱映射效果。 例如,可见光的频率范围约为 43b-75bHz,小端为红光,大端为蓝(紫)光,超出的部分为不可见光。 那么,现在欲观察 1k-2kHz 的范围,着色器就会把 1kHz 的片元映射为红色,把 2kHz 的片元映射为蓝(紫)色,超出的部分直接变黑。
颜色的本质就是频率嘛。 把源颜色转码成一个片元本身的“频率”,然后对频率做上面的变换,再转换回颜色就好了。 但是这里有两个问题:
- 显示器能显示的颜色总共就可见光这么多,现在要表示更广阔的频谱范围,如何表示?
- 上面的变换的数学形式何如?
问题二比较好回答,比如现在观察的频谱范围是
对于问题一,必须要知道的一点是:单色光的色相与显示器显示的色相虽然有所重合,但并不是一回事。
人眼的三种视锥细胞会对同一种(复色)光产生三种不同程度的激活,组合而成一个三维向量。 这个向量的“方向”就是人眼感知到的色相,因为形状上是一个圈,所以经常被画成色轮的样子。 但是,单色光能够形成的色相并不完全覆盖整个色轮,粉红色到紫色的这一部分是缺失的。 我们看到的粉色和紫色都是同时包含红色和蓝色波段的复色光所成的。
知道了这个之后,我们可以对一个图片定义一个「源频谱范围」,就像对地形高度图做的那样——红和蓝并不表示实际上的红和蓝,只是在源范围里的最小和最大值罢了。 然后,先将源颜色的 RGB 转换为 HSV,对 H 执行 clamp 操作(为了切掉粉紫色的部分,直接置黑也行),再将归约后的 H 套一层上面的变换,最后再将新的 HSV 逆变换回 RGB 即可。