opengl - 使用 GLSL 渲染矩形纹理

标签 opengl glsl vertex-shader

我创建了一个类,将视频帧(在 Mac 上)渲染到自定义帧缓冲区对象。作为输入,我有一个 YUV 纹理,并且我成功创建了一个片段着色器,它采用 3 个矩形纹理作为输入(Y、U 和 V 平面各一个,其数据由 glTexSubImage2D 使用 GL_TEXTURE_RECTANGLE_ARB、GL_LUMINANCE 和 GL_UNSIGNED_BYTE 上传) ,在渲染之前,我将事件纹理设置为三个不同的纹理单元(0、1 和 2),并为每个单元绑定(bind)一个纹理,出于性能原因,我使用了 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");

这给了我 0 代表 texCoord 和 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,它帮助我正确获取片段着色器的原始代码(这就是为什么我没有将其发布在这里),但由于添加了顶点着色器,它也没有给我任何输出(我想知道如果它不知道位置/texCoord 属性,它如何知道如何生成输出?)

最佳答案

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

关于opengl - 使用 GLSL 渲染矩形纹理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10648628/

相关文章:

opengl - 在 OpenGL 的顶点着色器中获取元素 ID

c++ - OpenGL相机运动程序顶点着色器问题

c++ - FPS 计数器的奇怪问题 - 在较新的计算机上限制为 60fps

c++ - 渲染文本 - freetype 空白屏幕

C++ switch 语句不起作用

c++ - glsl 顶点着色器统一变量未激活

three.js - GLSL - 仅模糊红色 channel

opengl-es - WebGL 中的 AlphaFunctions?

c - C Opengl 过剩中的错误 'glutTimerfunc'

javascript - 你如何 "combine"一个ShaderMaterial和LambertMaterial?