纹理数据在片段着色器中未被使用 - OpenGL

4
我正在OpenGL中练习纹理,将一种简单的白色纹理应用于四边形。代码编译和运行都没有问题,但四边形的颜色是黑色的,而不是我指定的白色。
我认为这是因为我的片段着色器没有做正确的采样,就好像它从纹理函数返回的数据全是零,因此四边形的纹理变成了黑色。我怀疑的原因是当我运行程序时,我可以让一个清晰的白色背景,并稍微移动四边形上的一个顶点,以查看背景(因为它通常填满整个表面)。然后我可以清楚地看到那里的白色背景,而四边形在其上方是黑色的。因此,某些输出颜色是由片段着色器产生的,只是错误的颜色,因为我提供的小像素数组只有白色。问题是我不知道为什么它会从我拥有的代码中产生错误的结果。我试图跟随一本书中的内容,该书使用或多或少相同的代码。我还尝试在不同的教程上查找它,但它们似乎都使用相同的方法,所以我被卡住了。
[编辑]
我找出了部分问题。通过使用glGetError()进行一些错误跟踪,我发现我的代码这行出了问题:
glTexStorage2D(GL_TEXTURE_2D, 0, GL_RGB8, 4, 4);

由于第二个参数level为0,返回错误代码1282(无效操作)。如果我将其设置为1,则错误消失。问题随之转移到以下代码行:

glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_R, GL_FLOAT, myTexture);

虽然更改等级参数,但返回相同的错误。

这是我使用的片段和顶点着色器:

片段着色器

// FRAGMENT SHADER
#version 330

uniform sampler2D tex;

in vec2 vs_tex_coord;

layout (location = 0) out vec4 outputColor;

void main(void)
{
    outputColor = texture(tex, vs_tex_coord);
}

顶点着色器

// VERTEX SHADER
#version 330

layout(location = 0) in vec4 position;
layout(location = 1) in vec2 in_tex_coord;

uniform vec2 offset;

out vec2 vs_tex_coord;

void main(void)
{
    vec4 finalOffset = vec4(offset.x, offset.y, 0.0, 0.0);
    gl_Position = position + finalOffset;
    vs_tex_coord = in_tex_coord;
}

我用于生成和存储纹理对象的代码非常简单:

我使用的代码如下:

glGenTextures(1, &textureHandle);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureHandle);

glTexStorage2D(GL_TEXTURE_2D, 0, GL_RGB8, 4, 4);

const GLubyte myTexture[] = {0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF,    0xFF, 0xFF, 0xFF,
                             0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF,    0xFF, 0xFF, 0xFF,
                             0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF,    0xFF, 0xFF, 0xFF,
                             0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF,    0xFF, 0xFF, 0xFF};

glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_RGB, GL_UNSIGNED_BYTE, myTexture);

myTexture只是以RGB内部格式包含4x4贴图,每个组件都有4位。我已将它们全部设置为白色。

然后,我简单地生成了一个默认采样器:

glGenSamplers(1, &mySampler);

glBindSampler(0, mySampler);

最后我进行渲染:

glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);

glUseProgram(theProgram);

GLuint samplerLoc = glGetUniformLocation(theProgram, "tex");

if (samplerLoc == -1)
    printf("Location name could not be found...\n");

glUniform1i(samplerLoc, 0);

glBindBuffer(GL_ARRAY_BUFFER, positionBufferObject);

glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);

glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);

glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)(16 * sizeof(float)));

glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

我上传到VBO的数组是:
const float vertexPositions[] =
{
    // Vertex position
    -0.8f, -1.0f, 0.0f, 1.0f,
     1.0f, -1.0f, 0.0f, 1.0f,
     1.0f,  1.0f, 0.0f, 1.0f,
    -1.0f,  1.0f, 0.0f, 1.0f,

    // Texture coordinates
    0.0f, 0.0f,
    1.0f, 0.0f,
    1.0f, 1.0f,
    0.0f, 1.0f
};

这是因为我使用采样器对象不正确吗?在正确工作之前,我需要设置某些设置吗?我错过了一些中间步骤吗?

对于任何感兴趣的人,视觉结果如下: enter image description here

您可以看到白色背景已清除,并且我故意将其中一个顶点位置移动了一点,以便您可以看到黑色四边形与白色背景形成对比。


在使用不可变纹理方面,使用*glTexStorage2D*会得到额外的加分。 - Nicol Bolas
1
我没有看到你将纹理绑定到上下文以供着色器使用的部分。我看到你初始化了纹理,但是当你实际渲染时,你是否已经绑定它了呢?还是你只是假设在初始化和使用之间不会有其他东西解绑纹理? - Nicol Bolas
是的,我只是假设在初始化和使用之间没有其他东西会解除纹理绑定(因为第一次绑定它以修改它)。话虽如此,我刚刚尝试在实际游戏循环中调用“glBindTexture(GL_TEXTURE_2D,textureHandle);”然后再调用“glDrawArrays”。不幸的是,似乎没有效果:( - CodingBeagle
2
顺便说一下,如果您是http://www.arcsynthesis.org/gltut/的作者(您的个人资料可能表明这一点),我想向您表示感谢:) 这是一个非常需要的初学者图形编程和OpenGL介绍,填补了一个空白,让我首先开始了所有这些。我仍在跟进 :) - CodingBeagle
在初始化和使用之间,没有任何其他的东西会解除纹理绑定” 这是肯定的。但是当您尝试查找错误时,最好要具体; 您永远不知道什么时候可能会发生偏差的 'glBindTexture' 并且您对此毫无所知。 - Nicol Bolas
显示剩余3条评论
1个回答

4

好的,经过一些错误跟踪,我终于找到了问题的所在! :) 对于将来遇到这个问题的任何人,这是(非常简单...呃!)的解决方案。

首先,就是这一行:

glTexStorage2D(GL_TEXTURE_2D, 0, GL_RGB8, 4, 4);

返回OpenGL错误1281(无效操作)的原因是第二个参数 levels 必须至少为1,以存储足够的内存用于基础图像,无论是否要使用mipmap(我认为应该为0)。因此,将其从0更改为1即可解决问题。

其次,这行代码:

glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_R, GL_FLOAT, myTexture);

在上面的代码片段中,format参数出了问题,它说GL_R,这是完全错误的。查看该函数的官方文档,它对此有以下说明:

format 指定像素数据的格式。 接受以下符号值: GL_RED, GL_RG, GL_RGB, GL_BGR, GL_RGBA, GL_BGRA, GL_DEPTH_COMPONENT和 GL_STENCIL_INDEX。

我之前在glTextStorage2D中指定的类型使用了GL_RGB8,其基本内部格式为GL_RGB,因此正确的版本应该是:
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_RGB, GL_UNSIGNED_BYTE, myTexture);

通过修复这两个问题,纹理效果得以显示 :)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接