Home > Blockchain >  Display RGB image using texture with OpenGL
Display RGB image using texture with OpenGL

Time:06-06

I'm trying to display RGB images in a GtkGLArea using a gtk/epoxy stack in C(/C ) langage brought by vcpkg. I have no errors but the widget stay white. Can someone teel me what I'm missing ?

here are the shaders:

#include <gtk/gtk.h>
#include <epoxy/gl.h>

const char* vertexShaderCode =
"#version 330 core\n"
"in vec3 a_position;"
"void main() {"
"  gl_Position = vec4(a_position,1.0);"
"}";

const char* fragmentShaderCode =
"#version 330 core\n"
"uniform sampler2D u_texture;"
"in vec2 tex_pos;"
"out vec3 color;"
"void main() {"
"  vec3 texel = texture2D(u_texture, tex_pos).rgb;"
"  color = texel;"
"}";

used variables (class members):

guint width, height;
guint vao;
guint texture;
guint program;
void* pixels; // image content

some Triangle coordinates:

GLfloat vertices[12] = {
            -1, -1, 0,
            1, -1, 0,
            -1, 1, 0,
            1, 1, 0
};

GLfloat textureVertices[8] = {
            0, 1,
            1, 1,
            0, 0,
            1, 0
};

Init:

glViewport(0, 0, width, height);
glClearColor(1.0f, 1.0f, 1.0f, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);


// shaders
guint vshader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vshader, 1, &vertexShaderCode, NULL);
glCompileShader(vshader);

guint fshader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fshader, 1, &fragmentShaderCode, NULL);
glCompileShader(fshader);


//program
program = glCreateProgram();
glAttachShader(program, vshader);
glAttachShader(program, fshader);
glLinkProgram(program);

glUseProgram(program);

glDisable(GL_BLEND);
glDisable(GL_DITHER);
glDisable(GL_DEPTH_TEST);

glDeleteShader(vshader);
glDeleteShader(fshader);

glGenVertexArrays(1, &vao);
glBindVertexArray(vao);


GLuint buffers[2];
glGenBuffers(2, &buffers[0]);
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);
glEnableVertexAttribArray(0);
    

glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(textureVertices), textureVertices, GL_STATIC_DRAW);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), 0);
glEnableVertexAttribArray(1);

glBindBuffer(GL_ARRAY_BUFFER, 0);


int textureHandle = glGetUniformLocation(program, "u_texture");
glUniform1i(textureHandle, 0);
glBindAttribLocation(program, 0, "a_position");
glBindAttribLocation(program, 1, "tex_pos");

// textures
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);// OR LINEAR
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_PACK_ALIGNMENT, 1);

glTexImage2D(
    GL_TEXTURE_2D, 0,
    GL_RGB,
    width, height, 0,
    GL_RGB,
    GL_UNSIGNED_BYTE, NULL);

    
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

glDisableVertexAttribArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindVertexArray(0);

glDeleteBuffers(2, &buffers[0]);

update drawing:

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glBindTexture(GL_TEXTURE_2D, texture);
// Bind the VAO
glViewport(0, 0, areaWidth, areHeight);

glUseProgram(program);
glBindVertexArray(vao);
glBindTexture(GL_TEXTURE_2D, texture);

glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glBindTexture(GL_TEXTURE_2D, 0);

each time needed data is copied to pixels pointer and rendering is requested:

gtk_gl_area_queue_render(GTK_GL_AREA(widget));

but the image is never rendered

CodePudding user response:

All vertex attributes are inputs to the vertex shader. You need to pass the texture coordinates from the vertex shader to the fragment shader:

#version 330 core

in vec3 a_position;
in vec2 a_tex_pos;
out vec2 tex_pos;

void main() {
    tex_pos = a_tex_pos;
    gl_Position = vec4(a_position,1.0);
}

glBindAttribLocation(program, 1, "tex_pos");

glBindAttribLocation(program, 1, "a_tex_pos");

Note that the vertex shader runs per vertex, but the fragment shader runs per fragment. The vertex shader outputs are interpolated along the fragments between the vertices. The interpolated outputs are the inputs to the fragment shader. With the interpolated texture coordinates, a different pixel of the image can be looked up for each fragment of the primitive.

CodePudding user response:

I fixed it, there was several mistakes:

mainly:

  • draw strips without an bound vertice buffer

working example:

here are the shaders:

#include <gtk/gtk.h>
#include <epoxy/gl.h>

const char* vertexShaderCode =
"#version 330 core\n"
"layout(location = 0) in vec3 a_position;"
"in vec2 a_tex_pos;"
"out vec2 tex_pos;"
"void main() {"
"  tex_pos = a_tex_pos;"
"  gl_Position = vec4(a_position,1.0);"
"}";

const char* fragmentShaderCode =
"#version 330 core\n"
"uniform sampler2D u_texture;"
"in vec2 tex_pos;"
"layout(location = 0) out vec4 color;"
"void main() {"
"  vec4 texel = texture2D(u_texture, tex_pos);"
"  color = texel;"
"}";

used variables (class members):

guint width, height;
guint vao;
guint texture;
guint program;
guint buffers[2];
void* pixels; // image content

some Triangle coordinates:

GLfloat vertices[12] = {
            -1, -1, 0,
            1, -1, 0,
            -1, 1, 0,
            1, 1, 0
};

GLfloat textureVertices[8] = {
            0, 1,
            1, 1,
            0, 0,
            1, 0
};

Init:

glViewport(0, 0, width, height);
glClearColor(1.0f, 1.0f, 1.0f, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);


// shaders
guint vshader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vshader, 1, &vertexShaderCode, NULL);
glCompileShader(vshader);

guint fshader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fshader, 1, &fragmentShaderCode, NULL);
glCompileShader(fshader);


//program
program = glCreateProgram();
glAttachShader(program, vshader);
glAttachShader(program, fshader);
glLinkProgram(program);

glUseProgram(program);

//glDisable(GL_BLEND);
glDisable(GL_DITHER);
//glDisable(GL_DEPTH_TEST);

glDeleteShader(vshader);
glDeleteShader(fshader);

glGenVertexArrays(1, &vao);
glBindVertexArray(vao);

fbo = 0;
glGenFramebuffers(1, &fbo);

GLuint buffers[2];
glGenBuffers(2, &buffers[0]);

// I swap buffers order

glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(textureVertices), textureVertices, GL_STATIC_DRAW);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), 0);
glEnableVertexAttribArray(1);

glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);
glEnableVertexAttribArray(0);
    
//glBindBuffer(GL_ARRAY_BUFFER, 0); not yet !


int textureHandle = glGetUniformLocation(program, "u_texture");
glUniform1i(textureHandle, 0);
glBindAttribLocation(program, 0, "a_position");
glBindAttribLocation(program, 1, "a_tex_pos");


// textures
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);// OR LINEAR
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_PACK_ALIGNMENT, 1);

glTexImage2D(
    GL_TEXTURE_2D, 0,
    GL_RGB,
    width, height, 0,
    GL_RGBA,
    GL_UNSIGNED_BYTE, NULL);

    
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); // it is effective now

glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
GLenum DrawBuffers[1] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, DrawBuffers);

glBindFramebuffer(GL_FRAMEBUFFER, 0);

glBindBuffer(GL_ARRAY_BUFFER, 0); // unbind now 

glDisableVertexAttribArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindVertexArray(0);

//glDeleteBuffers(2, &buffers[0]); no !

update drawing:

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glBindTexture(GL_TEXTURE_2D, texture);
// Bind the VAO
glViewport(0, 0, areaWidth, areHeight);

glUseProgram(program);
glBindVertexArray(vao);
glBindTexture(GL_TEXTURE_2D, texture);

glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels);

// rebind vertices
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);

glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glBindTexture(GL_TEXTURE_2D, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);

each time needed data is copied to pixels pointer and rendering is requested:

gtk_gl_area_queue_render(GTK_GL_AREA(widget));
  • Related