我无法正确处理sRGB纹理的三个.js。我该怎么办?
这是sRGB测试图像,应该统一显示为50%灰色:
它主要由棋盘图案中交替的黑白像素组成。黑=(0,0,0)白=(255,255,255) 这应该导致平均线性强度为50%。 中间有三个50%强度灰色的色块,用sRGB编码为(188,188,188)(下面解释)。
解释:(见sRGB的维基百科文章 这表示标准化的50%强度应该得到sRGB值(1.055 * 0.5 ^(1 / 2.4)) - 0.055 = 0.735358,在8位sRGB中约为187.516,因此将其编码为188的逻辑。
视觉上,在任何经过适当校准的显示器上本机查看时,纹理显然是正确的,并且除非您的浏览器缩小了图像,否则在此帖子中看起来可能正常。 (浏览器也会因伽马校正的下采样而失败,因此如果您已经可以轻松查看三个条形图,请以原始分辨率查看图像。)
当缩小此图像时,大多数天真的软件将简单地平均sRGB编码并达到太暗的虚假强度。黑色和白色像素将被天真地平均为(0 + 255)/ 2,以获得(128,128,128)的颜色,其强度仅为约22%(((128/255)+0.055)/(1.055)^ 2.4 )= ~0.215861。这比50%的期望强度(相当贡献的平均强度为0%和100%)暗得多。直观地说,"半亮度"是50%。
在OpenGL中,这很容易。您只需将纹理视为sRGB并使用sRGB帧缓冲区。纹理样本在采样时从sRGB编码转换为线性,并且在写入帧缓冲区时线性值被编码为sRGB,并且一切都很好。
我完全失去了如何在three.js框架内实现这一目标。有人可以帮忙吗?
我试过设置......
renderer.gammaFactor = 2.2;
renderer.gammaInput = true;
renderer.gammaOutput = true;`
...但实际上看来mipmap生成并没有将纹理正确地视为sRGB。加载纹理时我没有做任何特别的事情 - 只使用了THREE.TextureLoader。
var texture = textureLoader.load( 'images/gamma_srgb.png' );
但是这里质量差的结果是图像的棋盘部分太暗,但图像的纯色区域要亮得多。
仅供参考,我确实使用{antialias: true}
创建了WebGLRenderer,并且我在纹理上将maxAnisotropy
设置为渲染器的最大各向异性值。
编辑:在jsfiddle中添加了一个repro。 https://jsfiddle.net/fvusxp1g/