【问题标题】:Use shader on texture instead of screen在纹理而不是屏幕上使用着色器
【发布时间】:2024-01-06 12:19:01
【问题描述】:

我编写了一个简单的 GL 片段着色器,它对图像执行 RGB 伽玛调整:

uniform sampler2D tex;
uniform vec3 gamma;

void main()
{
    vec3 texel = texture2D(tex, gl_TexCoord[0].st).rgb;
    texel = pow(texel, gamma);
    gl_FragColor.rgb = texel;
}

纹理绘制了大部分屏幕,我想到这是在屏幕上应用每个输出像素的调整,而不是纹理上的每个输入像素。虽然这不会改变它的外观,但这个纹理与屏幕相比是很小的。

为了提高效率,如何让着色器处理纹理像素而不是屏幕像素?如果有帮助,无论如何我都会在每一帧上更改/重新加载此纹理的数据,所以我不介意纹理是否被永久更改。

【问题讨论】:

  • "无论如何我都会在每一帧上更改/重新加载此纹理的数据" 为什么在重新加载时不应用伽玛?
  • @NicolBolas 这是 Java。提取和重新合并整数的 RGB 分量所需的数组边界检查以及笨拙的移位和掩码使其变慢。 GPU 要好得多。

标签: opengl glsl shader


【解决方案1】:

我突然想到这是在屏幕上应用每个输出像素的调整

几乎。每个输出fragment(因此得名)执行片段着色器。在写入像素之前,片段是光栅化的最小单位。被可见渲染几何体覆盖的每个像素都会变成一个或多个片段(是的,片段可能比被覆盖的像素更多,例如在绘制到抗锯齿帧缓冲区时)。

为了效率,

现代 GPU 甚至不会“注意到”略微降低的负载。这是一种微优化,处于不可测量的边缘。我的建议:不要担心。

如何让着色器处理纹理像素而不是屏幕像素?

您可以预处理纹理,首先通过纹理大小的非抗锯齿帧缓冲区对象将其渲染到中间纹理。但是,如果您的更改是非线性,并且伽马调整正是如此,那么您不应该这样做。您希望在线性色彩空间中处理图像并尽可能晚地应用非线性变换。

【讨论】:

  • 谢谢!正如您所解释的,我尝试渲染到中间纹理。 (我不能在 OpenGL 2 上使用帧缓冲区,但我相信,我使用 glCopyTexImage2D 得到了或多或少相同的东西。)它使代码变得混乱,并且在使用普通着色器时增加了约 50% 的帧时间减慢,或者不,似乎对时代没有任何影响。我就不管它,让 GPU 继续处理。