我正在尝试编写我自己的光谱路径跟踪器,并将计算出来的SPD转换为LDR值。我现在所做的是使用CIE 1931颜色匹配函数将采样SPD(在W/m^-1中)转换为XYZ:
Vec3 xyz(0, 0, 0);
float norm = 0;
for (int i = 0; i < SPD_SAMPLE_COUNT; ++i) {
const float wavelength =
lerp(MIN_WAVELENGTH, MAX_WAVELENGTH, i / SPD_SAMPLE_COUNT);
const Vec3 cieMatchingFunctionValue = cie1931(wavelength);
xyz += cieMatchingFunctionValue * spd[i];
norm += cieMatchingFunctionValue.y;
}
xyz /= norm;在这里,cie1931的实现是来自怀曼等人的任意近似。
然后XYZ到xyY (即色度和亮度),将亮度归一化为整个图像的范围(现在,通过除以我的最大亮度来保持简单):
float maxLuminance = 0;
for (auto &xyz : image) {
maxLuminance = std::max(maxLuminance, xyz.y);
}
for (auto &xyz : image) {
Vec2 chromaticity = Vec2(xyz.x, xyz.y) / (xyz.x + xyz.y + xyz.z);
float luminance = xyz.y / maxLuminance;
// then to "scaled" XYZ and RGB, see below
}此外,我还尝试了Reinhard音调映射操作符:
float logSum = 0;
for (auto &xyz : image) {
logSum += std::log(xyz.y);
}
float logAvgLuminance = std::exp(logSum / image.size());
for (auto &xyz : image) {
Vec2 chromaticity = Vec2(xyz.x, xyz.y) / (xyz.x + xyz.y + xyz.z);
const float a = 0.18; // constant from Reinhard's paper.
float luminance = a * xyz.y / logAvgLuminance;
luminance /= luminance + 1;
// then to "scaled" XYZ and RGB, see below
}然后回到XYZ,而不是线性RGB (wia 这:
for (auto &xyz : image) {
// XYZ to chromaticity and "scaled luminance", see above
Vec3 scaledXyz(
chromaticity.x * luminance / chromaticity.y,
luminance,
(1 - chromaticity.x - chromaticity.y) * luminance / chromaticity.y
);
float r = dot(Vec3( 3.2406, -1.5372, -0.4986), scaledXyz);
float g = dot(Vec3(-0.9689, 1.8758, 0.0415), scaledXyz);
float b = dot(Vec3( 0.0557, -0.2040, 1.0570), scaledXyz);
// Output RGB, i.e. std::cout << Vec3(r, g, b);
}之后,我仍然得到RGB值。我做错了什么?似乎“最大”亮度应该取决于颜色的色度。有什么算法可以解释这一点吗?
发布于 2019-01-27 00:06:35
当使用光谱渲染时,获得外部的sRGB值是预期的和正常的。
sRGB色域仅覆盖CIE色度空间中间的一个三角形:

(图表取自维基百科)
大的“马蹄铁”形状是所有物理上可能的色度(CIE,xy坐标)从任何可能的光谱集合。因此,您的xy坐标应该被期望在horseshoe...but中的某个位置,只有在三角形内部的坐标才能表示为sRGB!其他的对于sRGB来说“太饱和”了,并且将不得不以某种方式被夹紧或重新映射。(色调映射本身并不能解决这个问题,因为它关注的是亮度,而不是色度。)
有多种方法可以根据你想要的复杂程度来处理色域外的颜色:
scaledXyz之前编辑xy坐标。如果初始xy坐标位于sRGB三角形之外,请查找从xy坐标到白点的线段(例如D65);然后查找该直线段与sRGB三角形的交集。这是最近的sRGB点,其亮度和色调与原始点相同,但饱和度较低。( sRGB三角形的顶点可以通过将RGB(1,0,0),RGB(0,1,0)和RGB(0,0,1)转换为CIE空间得到。https://computergraphics.stackexchange.com/questions/8505
复制相似问题