我创建了一个类,将视频帧(在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,因为我读到它已经过时,应该避免使用。
所以,作为下一步,我创建了两个缓冲对象,一个用于顶点,一个用于纹理坐标:
然后在加载着色器后,我尝试检索顶点着色器中属性的位置:
这很好用,我得到了期望的结果(除了闪烁效果,我猜测这与我在两个不同线程上使用了两个不同的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,它帮助我正确编写了片段着色器的原始代码(这就是为什么我没有在此处发布它的原因),但是自从添加了顶点着色器后,它也没有给我任何输出信息(我想知道如果它不知道位置/纹理坐标属性,它怎么知道如何产生输出呢?)