(DirectX9) 隐式应用伽玛校正
更新:
非常感谢大家的回答。正如杰西·霍尔(Jesse Hall)所说,看起来这是一个驱动程序(或硬件)问题。我在其他配置上尝试了相同的应用程序,它按预期工作。
我在共享相同 GPU (ATI 4800 HD) 但驱动程序版本不同的其他计算机上测试了该应用程序,它们都显示出相同的错误行为(似乎是写入时的双伽玛校正)。在这些计算机上,如果必须将 D3DRS_SRGBWRITEENABLE 设置为 false 才能修复显示。有人知道这是否是该硬件上的已知错误?
更奇怪的是,我使用这两种配置得到相同的最终结果:
- D3DRS_SRGBWRITEENABLE = FALSE 和 D3DSAMP_SRGBTEXTURE 为 TRUE
- D3DRS_SRGBWRITEENABLE = FALSE 和 D3DSAMP_SRGBTEXTURE 为 FALSE
在像素调试器中,我看到在情况 1 中正确应用了线性化,但(自动)校正写入时给出与情况 2 相同的输出(根本不执行任何转换)...
// --更新结束
我在修复 DirectX9 应用程序的伽玛校正时遇到一些问题。
当我在采样器中启用纹理线性化 (D3DSAMP_SRGBTEXTURE) 和 sRGB 写入输出 (D3DRS_SRGBWRITEENABLE) 时,伽玛校正看起来应用了两次。
这是我的设置。我使用了以下纹理(来自此处) 绘制全屏四边形:
图片右侧的结果在视觉上太亮。我使用 PIX 来调试这些灰色像素之一,如果一切设置正确,我预计输出值为 0.73 (=0.5^(1.0/2.2))。不幸的是,像素着色器的输出为 0.871(看起来可能是应用了两次伽玛校正?)。我使用调试器进入像素着色器,纹理获取返回的值为 (0.491, 0.491, 0.491),这应该意味着读取时的线性化工作正常。
当我禁用 D3DRS_SRGBWRITEENABLE 时,像素着色器的输出为 0.729,这对我来说看起来更正确。
知道这个转换来自哪里吗(在调试器中像素着色器输出为 0.491)?我还应该检查哪些其他标志/渲染状态?
非常感谢您的帮助!
UPDATE:
Thank you all very much for your answers. As Jesse Hall suggested, it looks like it is a driver (or hardware) problem. I tried the same app on other configurations and it worked as expected.
I tested the app on other computers which share the same GPU (ATI 4800 HD) but different versions of the driver and they all showed the same erroneous behavior (what seems to be a double gamma correction on write). On these computers, if have to set D3DRS_SRGBWRITEENABLE to false to fix the display. Anyone knows if this is a known bug on this hardware?
Even more strange is that I get the same end results with these two configurations:
- D3DRS_SRGBWRITEENABLE = FALSE and D3DSAMP_SRGBTEXTURE to TRUE
- D3DRS_SRGBWRITEENABLE = FALSE and D3DSAMP_SRGBTEXTURE to FALSE
In the pixel debugger, I see that linearization is applied properly in case 1 but (automatic) correction on write gives the same output as case 2 (which performs no conversion at all)...
// -- END OF UPDATE
I'm having some trouble fixing the gamma correction of a DirectX9 application.
When I enable texture linearization in the samplers (D3DSAMP_SRGBTEXTURE) and sRGB write for output (D3DRS_SRGBWRITEENABLE), it looks like gamma correction is applied twice.
Here is my setup. I used the following texture (from here) to draw a fullscreen quad:
The results were visually too bright on the right side of the picture. I used PIX to debug one of those grey pixels and, if everything was set up properly, I would have expected an output value of 0.73 (=0.5^(1.0/2.2)). Unfortunately, the output of the pixel shader was 0.871 (which looks like it could be a gamma correction applied twice ?). I stepped inside the pixel shader with the debugger and the texture fetch returned a value of (0.491, 0.491, 0.491), which should mean linearization on read worked properly.
When I disable D3DRS_SRGBWRITEENABLE, the output of the pixel shader is 0.729 which looks much more correct to me.
Any idea where does this conversion come from (in the debugger the pixel shader output was 0.491)? What other flags/render states should I check?
Thank you very much for your help!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
一种可能性是您将线性伽玛变换应用两次。使用 D3DRS_SRGBWRITEENABLE 写入渲染目标时一次。然后其他时候用 D3DPRESENT_LINEAR_CONTENT 呈现帧缓冲区(如果您已指定该标志)。您不需要 D3DPRESENT_LINEAR_CONTENT,因为您已经使用 D3DRS_SRGBWRITEENABLE 转换回 RGB 空间。
另一种可能性是,您的图形硬件在转换为像素着色器的线性空间之前正在过滤纹理。您可以通过禁用 D3DSAMP_SRGBTEXTURE 和过滤来测试这一点,然后在像素着色器中转换到线性空间并进行过滤。或者只是将纹理绘制得足够大,这样过滤就不再是问题了。一篇关于伽玛校正的好文章还提到 GeForce 8 及更高版本的显卡在过滤之前正确转换为线性空间,可以在这里找到:
线性的重要性
如果你没有使用D3DPRESENT_LINEAR_CONTENT,那么我的下一个猜测是你的显卡不支持您正在进行的伽玛变换。以编程方式或使用 DirectX Caps Viewer Tool 等工具检查设备功能:
DirectX Caps 查看器工具
One possibility is that you are applying the linear to gamma transform twice. Once when writing to the render target with D3DRS_SRGBWRITEENABLE. Then other time when presenting the frame buffer with D3DPRESENT_LINEAR_CONTENT (if you have specified that flag). You do not need D3DPRESENT_LINEAR_CONTENT since you already transformed back to rgb space with D3DRS_SRGBWRITEENABLE.
Another possibility is that your graphics hardware is filtering the texture before converting to linear space for your pixel shader. You can test for this by disabling D3DSAMP_SRGBTEXTURE and filtering, then doing the conversion to linear space and filtering in the pixel shader. Or simply drawing the texture large enough that filtering is not an issue. A good article on gamma correction that also mentions that GeForce 8 and later cards correctly convert to linear space before filtering can be found here:
The Importance of Being Linear
If you are not using D3DPRESENT_LINEAR_CONTENT, then my next guess is that your graphics card does not support the gamma transformations you are doing. Check the device capabilities programatically or with a tool like DirectX Caps Viewer Tool:
DirectX Caps Viewer Tool
这与问题相关,但不完全相关,但值得了解!
我在 Vista/Win7 上的 D3D9 运行时遇到了一个错误。该运行时是在 D3D10 之上编写的某种模拟层。在 D3D10 中,SRGB 状态是纹理格式的一个属性,在 D3D9 中,它是基于采样器的渲染状态。设置 D3D9 纹理时,SRGB 状态始终设置为“关闭”,因为可能正在使用纹理的格式,并且 D3D9 没有 SRGB 纹理格式。这意味着在绑定纹理后需要设置 D3DSAMP_SRGBTEXTURE 状态才能正确显示。
This is related to the question but not exactly, but worth knowing!
I have run across a bug in the D3D9 runtime on Vista/Win7. This runtime is an emulation layer of sorts written on top of D3D10. In D3D10 the SRGB state is a property of the texture format, in D3D9 it is a sampler based renderstate. When setting a D3D9 texture, the SRGB state always set to 'off' lost as the texture's format is probably being used, and D3D9 doesnt have an SRGB texture format. This means that the D3DSAMP_SRGBTEXTURE state needs to be set after the texture is bound in order to show up correctly.