在 glTexImage2D() 中指定 GL_RGBA32F 时输出奇怪

Posted

技术标签:

【中文标题】在 glTexImage2D() 中指定 GL_RGBA32F 时输出奇怪【英文标题】:Weird output when specifying GL_RGBA32F in glTexImage2D() 【发布时间】:2020-02-24 09:05:54 【问题描述】:

我正在开发一个 Java (JOGL) 程序来使用着色器程序进行一些计算,并且我遇到了来自片段着色器的奇怪输出值。 更具体地说,glGetTexImage() 似乎返回了缩放值。

现在,这是一个简单的片段着色器。

#version 330

layout(location=0) out vec4 fs_out_color;

void main()
    fs_out_color=vec4(-1.0,0.5,0.4,2.0);

我创建了一个浮点纹理来获取着色器的输出。 TEXTURE_WIDTH 和 TEXTURE_HEIGHT 都是 2。

glBindTexture(GL4.GL_TEXTURE_2D, texture_id);
glTexImage2D(
        GL4.GL_TEXTURE_2D, 0, GL4.GL_RGBA32F, 
        TEXTURE_WIDTH, TEXTURE_HEIGHT, 0, GL4.GL_RGBA, GL4.GL_FLOAT, null);
glTexParameteri(GL4.GL_TEXTURE_2D, GL4.GL_TEXTURE_MAG_FILTER, GL4.GL_NEAREST);
glTexParameteri(GL4.GL_TEXTURE_2D, GL4.GL_TEXTURE_MIN_FILTER, GL4.GL_NEAREST);
glTexParameteri(GL4.GL_TEXTURE_2D, GL4.GL_TEXTURE_WRAP_S, GL4.GL_CLAMP_TO_EDGE);
glTexParameteri(GL4.GL_TEXTURE_2D, GL4.GL_TEXTURE_WRAP_T, GL4.GL_CLAMP_TO_EDGE);
glBindTexture(GL4.GL_TEXTURE_2D, 0);

GL_RGBA32F 被传递给 glTexImage2D() 的第三个参数以获取未被钳位的值。

然后,使用以下代码获取结果:

int size=TEXTURE_WIDTH*TEXTURE_HEIGHT*4;
FloatBuffer buf=Buffers.newDirectFloatBuffer(size);

glBindTexture(GL4.GL_TEXTURE_2D, texture_id);
glGetTexImage(GL4.GL_TEXTURE_2D, 0, GL4.GL_RGBA, GL4.GL_FLOAT, buf);
glBindTexture(GL4.GL_TEXTURE_2D, 0);

最后,它们被输出到控制台。

for(int i=0;i<size;i+=4) 
    float r=buf.get();
    float g=buf.get();
    float b=buf.get();
    float a=buf.get();

    String str="("+r+","+g+","+b+","+a+")";
    System.out.println(str);

我在这里期望的是(-1.0,0.5,0.4,2.0)。 但是,实际输出是

(-2.0,1.0,0.8,4.0)
(-2.0,1.0,0.8,4.0)
(-2.0,1.0,0.8,4.0)
(-2.0,1.0,0.8,4.0)

我在着色器中尝试了另一个 vec4 变量 vec4(-10.0,0.5,0.4,20.0),我得到了

(-200.0,10.0,8.0,400.0)
(-200.0,10.0,8.0,400.0)
(-200.0,10.0,8.0,400.0)
(-200.0,10.0,8.0,400.0)

我做错了什么吗?如何获得片段着色器的原始输出? 任何建议将不胜感激。

注意: 片段着色器

fs_out_color=vec4(-1.0,0.5,0.4,2.0);

Java 代码

glTexImage2D(
        GL4.GL_TEXTURE_2D, 0, GL4.GL_RGBA, 
        TEXTURE_WIDTH, TEXTURE_HEIGHT, 0, GL4.GL_RGBA, GL4.GL_FLOAT, null);

输出是

(0.0,0.5019608,0.4,1.0)
(0.0,0.5019608,0.4,1.0)
(0.0,0.5019608,0.4,1.0)
(0.0,0.5019608,0.4,1.0)

似乎与 GL_RGBA 配合得很好。

【问题讨论】:

是的,纹理附加到帧缓冲区,我使用 glDrawElements() 对其进行渲染。 我碰巧在 5 个月后回来并审查了这个问题,一无所获。在发布之前,我对代码进行了不必要的更改。对 OpenGL 函数的实际调用如下所示:GL4 gl = GLContext.getCurrentGL().getGL4(); gl.glBindTexture(GL4.GL_TEXTURE_2D, textureID); 澄清一下。 【参考方案1】:

好的,让我们做一些或多或少有根据的猜测:

Input: -1.0,0.5,0.4,2.0   -> Output: -2.0,1.0,0.8,4.0
Input: -10.0,0.5,0.4,20.0 -> Output: -200.0,10.0,8.0,400.0 
Input: -1.0,0.5,0.4,2.0   -> Output: 0.0,0.5019608,0.4,1.0  (using UNORM target)

假设:您启用了Blending,并且您特别设置了glBlendFunc(GL_SRC_ALPHA, ...),以便片段着色器的输出(将是混合阶段的源操作数)乘以您提供的alpha值。请注意,当使用像 GL_RGBA 这样的 UNORM 渲染目标时,片段着色器的输出将在混合发生之前被限制为 [0,1],因此您会在其中得到 alpha = 1.0,并且乘法无效。

如果我的假设是正确的,那么在 UNORM GL_RGBA 格式的情况下,如果您尝试输入 alpha 为 0.5,您也会得到“错误”的缩放结果。

【讨论】:

这对我来说是一个完美的答案。我启用了混合并设置了 glBlendFunc(GL4.GL_SRC_ALPHA, GL4.GL_ONE_MINUS_SRC_ALPHA)。感谢您回答我的问题。 请注意,这也是未定义值的情况。由于您使用NULL 作为数据指针创建纹理,因此纹理内容未初始化,并且您添加(嗯,在您的场景中,1-alpha 是负数,因此您减去)它们作为混合过程中的目标因素。但是,在现实世界中,您的纹理很有可能全为零,但规范无法保证这一点。

以上是关于在 glTexImage2D() 中指定 GL_RGBA32F 时输出奇怪的主要内容,如果未能解决你的问题,请参考以下文章

使用单通道纹理(OpenGL 2)?

如何在 CodeNameOne 项目中指定 abiFilters?

如何在类型提示中指定函数类型?

是否可以在 Count() 中指定条件?

如何在 HTML 的图例中指定不同的形状?

如何在 RSACryptoServiceProvider .NET 类中指定公钥