I’m trying to render an YUV frame using OpenGL. I’m trying for hours to find the problem but I can’t see what I did wrong. I see a green screen (because the YUV matrix converts black, which is 0,0,0 to green because there’s no initial data). If I uncomment //FragColor = vec4(1.0,0,0, 1.0);
, I see a red screen, which confirms the fragment shader is working.
As you can see, I have 3 texture units, one for Y
, other for U
and other for V
and I activate each one by tex_y
, tex_u
, tex_v
uniform samplers.
Vertex shader:
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;
out vec2 TexCoord;
void main()
{
gl_Position = vec4(aPos, 1.0);
TexCoord = vec2(aTexCoord.x, aTexCoord.y);
}
Fragment shader:
#version 330 core
out vec4 FragColor;
in vec2 TexCoord;
uniform sampler2D tex_y;
uniform sampler2D tex_u;
uniform sampler2D tex_v;
void main(void)tex_v
{
vec3 yuv;
vec3 rgb;
yuv.x = texture(tex_y, TexCoord).r;
yuv.y = texture(tex_u, TexCoord).r - 0.5;
yuv.z = texture(tex_v, TexCoord).r - 0.5;
rgb = mat3(1.0, 1.0, 1.0,
0.0, -0.39465, 2.03211,
1.13983, -0.58060, 0.0) * yuv;
FragColor = vec4(rgb, 1.0);
//FragColor = vec4(1.0,0,0, 1.0);
}
Here’s the rendering code:
if (firstRun) {
const GLfloat vertices_textures[20] = {
//vertices //positions
-1.0f, -1.0f, 0.0f, 0.0f, 1.0f,
1.0f, -1.0f, 0.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 0.0f, 0.0f, 0.0f,
1.0f, 1.0f, 0.0f, 1.0f, 0.0f
};
program = std::make_unique<Program>();
program->attach_shader(Shader(ShaderType::Vertex, "video.vert"));
program->attach_shader(Shader(ShaderType::Fragment, "yuv420p.frag"));
program->link();
vextexInLocation = glGetAttribLocation(program->get_id(), "aPos");
textureInLocation = glGetAttribLocation(program->get_id(), "aTexCoord");
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices_textures), vertices_textures, GL_STATIC_DRAW);
glVertexAttribPointer(vextexInLocation, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void *)0);
glEnableVertexAttribArray(vextexInLocation);
glVertexAttribPointer(textureInLocation, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(textureInLocation);
textureLocation[0] = glGetUniformLocation(program->get_id(), "tex_y");
textureLocation[1] = glGetUniformLocation(program->get_id(), "tex_u");
textureLocation[2] = glGetUniformLocation(program->get_id(), "tex_v");
glGenTextures(3, textureId);
for (int i = 0; i < 3; i++)
{
glBindTexture(GL_TEXTURE_2D, textureId[i]);
glTexImage2D(GL_TEXTURE_2D,
0,
GL_LUMINANCE,
width,
height,
0,
GL_LUMINANCE,
GL_UNSIGNED_BYTE,
NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
firstRun = false;
}
program->use();
for (int j = 0; j < 3; j++)
{
glActiveTexture(GL_TEXTURE0 + j);
glBindTexture(GL_TEXTURE_2D, textureId[j]);
glTexSubImage2D(GL_TEXTURE_2D,
0,
0,
0,
width,
height,
GL_LUMINANCE,
GL_UNSIGNED_BYTE,
frame->buffer[j]);
glUniform1i(textureLocation[j], j);
}
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);