使用GLSL渲染矩形纹理

9
我创建了一个类,将视频帧(在Mac上)渲染到一个自定义的帧缓冲对象中。我有一个YUV纹理作为输入,并成功创建了一个片段着色器,它以3个矩形纹理作为输入(每个矩形纹理对应一个Y、U和V平面,数据通过GL_TEXTURE_RECTANGLE_ARB、GL_LUMINANCE和GL_UNSIGNED_BYTE上传)。在渲染之前,我将活动纹理设置为三个不同的纹理单元(0、1和2),并绑定每个纹理,出于性能考虑,我使用了GL_APPLE_client_storage和GL_APPLE_texture_range。然后使用glUseProgram(myProg)和glBegin(GL_QUADS) ... glEnd()进行渲染。
这很好用,我得到了期望的结果(除了闪烁效果,我猜测这与我在两个不同线程上使用了两个不同的GL上下文有关,它们可能在某个时刻相互干扰[这是另一个问题的主题])。无论如何,我决定进一步改进我的代码,添加一个顶点着色器,这样我就可以跳过glBegin/glEnd,因为我读到它已经过时,应该避免使用。
所以,作为下一步,我创建了两个缓冲对象,一个用于顶点,一个用于纹理坐标:
      const GLsizeiptr posSize = 4 * 4 * sizeof(GLfloat);
      const GLfloat posData[] =
      {
            -1.0f, -1.0f, -1.0f, 1.0f,
             1.0f, -1.0f, -1.0f, 1.0f,
             1.0f,  1.0f, -1.0f, 1.0f,
            -1.0f,  1.0f, -1.0f, 1.0f
        };

        const GLsizeiptr texCoordSize = 4 * 2 * sizeof(GLfloat);
        const GLfloat texCoordData[] =
        {
            0.0, 0.0,
            1.0, 0.0,
            1.0, 1.0,
            0.0, 1.0
        };

    glGenBuffers(1, &m_vertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, posSize, posData, GL_STATIC_DRAW);

    glGenBuffers(1, &m_texCoordBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, m_texCoordBuffer);
    glBufferData(GL_ARRAY_BUFFER, texCoordSize, texCoordData, GL_STATIC_DRAW);

然后在加载着色器后,我尝试检索顶点着色器中属性的位置:
        m_attributeTexCoord = glGetAttribLocation( m_shaderProgram, "texCoord");
        m_attributePos = glGetAttribLocation( m_shaderProgram, "position");

这让我得到了纹理坐标(texCoord)的值为0,位置(position)的值为1,看起来很好。

在获取属性后,我还会调用

        glEnableVertexAttribArray(m_attributePos);
        glEnableVertexAttribArray(m_attributeTexCoord);

我只需要做一次这样的更改,还是在每次调用glVertexAttribPointer和glDrawArrays之前都需要进行?每个纹理单元需要这样做吗?或者当我的着色器使用glProgram激活时?还是可以在任何地方进行这样的更改?

然后我修改了渲染代码以替换glBegin/glEnd:

        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texID_Y);

        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texID_U);

        glActiveTexture(GL_TEXTURE2);
        glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texID_V);

        glUseProgram(myShaderProgID);

        // new method with shaders and buffers
        glBindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer);
        glVertexAttribPointer(m_attributePos, 4, GL_FLOAT, GL_FALSE, 0, NULL);
        glBindBuffer(GL_ARRAY_BUFFER, m_texCoordBuffer);
        glVertexAttribPointer(m_attributeTexCoord, 2, GL_FLOAT, GL_FALSE, 0, NULL);
        glDrawArrays(GL_QUADS, 0, 4);

        glUseProgram(0);

但是,自从我把代码改成这样后,我总是只得到一张黑屏作为结果。所以我想我可能错过了一些简单的步骤,也许是一些glEnable/glDisable或正确设置某些内容-但正如我所说,我是新手,所以我没有真正的想法。供您参考,以下是顶点着色器:

#version 110
attribute vec2 texCoord;
attribute vec4 position;

// the tex coords for the fragment shader
varying vec2 texCoordY;
varying vec2 texCoordUV;

//the shader entry point is the main method
void main()
{   
    texCoordY = texCoord;
    texCoordUV = texCoordY * 0.5; // U and V are only half the size of Y texture
    gl_Position = gl_ModelViewProjectionMatrix * position;
}

我猜测我可能漏掉了一些显而易见的东西,或者还没有对这里正在进行的过程有足够深入的理解。我也尝试使用OpenGLShaderBuilder,它帮助我正确编写了片段着色器的原始代码(这就是为什么我没有在此处发布它的原因),但是自从添加了顶点着色器后,它也没有给我任何输出信息(我想知道如果它不知道位置/纹理坐标属性,它怎么知道如何产生输出呢?)


1
对于纹理矩形,坐标不应该被归一化,但您似乎正在传递归一化的坐标。 - harold
1
那么对于texCoordData[],我传递的不是0.0、1.0等,而是例如1920.0、1080.0(即视频帧的实际大小)? - Bjoern
黑屏死亡在图形界面中非常常见。我猜你已经尝试更改清除颜色以确保你正在绘制任何东西了吧?如果你确实在绘制,那么这可能是着色器问题,否则就是顶点数组的问题。 - geometrian
好的,是的,我的清晰颜色是一种可怕的黄色 :-) 我刚刚发现了我的两个问题:1.我必须将纹理坐标更改为非规范化(感谢哈罗德!),2.glEnableVertexAttribArray似乎在之前被调用到了错误的位置。现在我终于让它工作了 - 谢谢大家! - Bjoern
1个回答

2

我没有仔细研究每一行代码,但我认为你的逻辑大部分是正确的。我发现缺失的部分是glEnableVertexAttribArray。在调用glDrawArrays之前,您需要启用两个顶点属性。


感谢您的快速回复,很抱歉,我已经在做这个了,但是在上面的帖子中忘记提到了(现在会编辑),而且这并没有真正帮助我。 - Bjoern
好的,事实证明我在错误的位置调用了glEnableVertexAttribArray。之前我在获取属性位置后才调用它,所以现在我改为每帧调用它,最终它可以工作了。但是我不明白为什么需要每帧调用它,我以为它会记住已经启用了呢? - Bjoern
@Bjoern,它应该记住它而无需在每帧调用它,你可能在某个地方禁用了它吗? - Tim
1
哦,我刚刚意识到问题所在:我有两个GL上下文(共享资源),一个在解码视频的线程上(我在其中创建了着色器),另一个在主渲染线程上(在那里我实际使用了该着色器)。但我在解码线程而不是渲染线程上启用了它。这一定是为什么......我想我可能也应该将着色器的创建移动到另一个线程中(但这意味着在渲染第一帧时会有额外的延迟)......但是那些多线程GL问题我会在另一个问题中提出...... - Bjoern

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