Hello everyone,
I just recently started learning OpenGL by following this tutorial
and after altering the code to my likings I ran into behavior I cannot understand.
When I try to render a texture some pixels change their colour every time I run the code while others are always simply wrong.
Some examples:
[ATTACH=CONFIG]1820[/ATTACH]
gets rendered as
[ATTACH=CONFIG]1819[/ATTACH]
and
[ATTACH=CONFIG]1821[/ATTACH]
gets rendered as
[ATTACH=CONFIG]1822[/ATTACH]
(The images were scaled up to be visable but every coloured area is actually a single texel)
Note that the blue colour as background is intended but apart from the two at the top all texels have the wrong colour.
The colour of the bottom-right texel actually changes every time I run my code.
Everything works however when the resolution of the texture reaches 4 texels in width.
It seems to be independent from the height of the texture.
I also tried using one triangle instead of two but there was no change (except it only showing half of the corrupted texture).
I simplified the code as much as possible and ended up with this:
(I know it’s long but that’s the entire code needed to create this behavior and I wanted it to be possible for others to try)
#include <stdio.h>
#include <stdlib.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include "src/common/config.hpp"
#include "src/common/shader.hpp"
#include "src/common/texture.hpp"
int main()
{
//Initialise GLFW
if( !glfwInit() )
{
fprintf( stderr, "Failed to initialize GLFW
" );
getchar();
return -1;
}
glfwWindowHint(GLFW_SAMPLES, 4); //Antialiasing 4x
glfwWindowHint(GLFW_RESIZABLE,GL_TRUE);
//OpenGL Version: 3.3
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); //OSX Compatability
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); //no old OpenGL
//Open a window and create its OpenGL context
GLFWwindow* window = glfwCreateWindow( 768, 512, PROGRAM_NAME, NULL, NULL);
if( window == NULL ){
fprintf( stderr, "Failed to open GLFW window. Intel GPUs are not always OpenGL 3.3 compatible.
" );
getchar();
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
//Initialize GLEW
glewExperimental = true; // Needed for core profile
if (glewInit() != GLEW_OK) {
fprintf(stderr, "Failed to initialize GLEW
");
getchar();
glfwTerminate();
return -1;
}
//Set background
glClearColor(0.0f, 0.5f, 1.0f, 0.0f);
printf("Vendor: %s, Version: %s, Renderer: %s
", glGetString(GL_VENDOR), glGetString(GL_VERSION), glGetString(GL_RENDERER));
// --- Drawing Start ---
//Enable depth test
glEnable(GL_DEPTH_TEST);
//Accept fragment if it closer to the camera than the former one
glDepthFunc(GL_LESS);
GLuint VertexArrayID;
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
GLuint programID = LoadShaders( "../src/shader/vertex_shader.glsl", "../src/shader/fragment_shader.glsl" );
bool linear_interpolation = false;
bool bgr = false;
int width = 2, height = 2;
unsigned char data[width*height*3] = {0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff};
printf("linint = %d
bgr = %d
width|height = %d|%d
data = %x %x %x | %x %x %x | %x %x %x | %x %x %x
", linear_interpolation, bgr, width, height, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11]);
GLuint Texture;
glGenTextures(1, &Texture);
glBindTexture(GL_TEXTURE_2D, Texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, bgr? GL_BGR:GL_RGB, GL_UNSIGNED_BYTE, data);
if(linear_interpolation){
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glGenerateMipmap(GL_TEXTURE_2D);
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, linear_interpolation? GL_LINEAR:GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, linear_interpolation? GL_LINEAR_MIPMAP_LINEAR:GL_NEAREST);
GLuint TextureID = glGetUniformLocation(programID, "textureSampler");
static const GLfloat g_vertex_buffer_data[] =
{
0.1f, 0.1f,
0.1f, -0.1f,
-0.1f, 0.1f,
0.1f, -0.1f,
-0.1f, 0.1f,
-0.1f, -0.1f,
};
static const GLfloat g_uv_buffer_data[] =
{
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 1.0f,
0.0f, 0.0f,
0.0f, 1.0f,
};
GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW);
GLuint uvbuffer;
glGenBuffers(1, &uvbuffer);
glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_uv_buffer_data), g_uv_buffer_data, GL_STATIC_DRAW);
do{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(programID);
// Bind our texture in Texture Unit 0
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, Texture);
glUniform1i(TextureID, 0);
// 1rst attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(
0, //attribute. No particular reason for 0, but must match the layout in the shader.
2, //size
GL_FLOAT, //type
GL_FALSE, //normalized?
0, //stride
(void*)0 //array buffer offset
);
// 2nd attribute buffer : UVs
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
glVertexAttribPointer(
1, //attribute. No particular reason for 1, but must match the layout in the shader.
2, //size : U+V => 2
GL_FLOAT, //type
GL_FALSE, //normalized?
0, //stride
(void*)0 //array buffer offset
);
glDrawArrays(GL_TRIANGLES, 0, 2*3); // 12 Triangles
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
//Swap buffers (redraw)
glfwSwapBuffers(window);
glfwPollEvents();
} //Check if the ESC key was pressed or the window was closed
while( !glfwWindowShouldClose(window) );
//Cleanup VertexBufferObject
glDeleteBuffers(1, &vertexbuffer);
glDeleteBuffers(1, &uvbuffer);
glDeleteTextures(1, &Texture);
glDeleteVertexArrays(1, &VertexArrayID);
glDeleteProgram(programID);
glfwTerminate();
return 0;
}
My shaders are as simple as possible:
Fragment shader:
#version 330 core
in vec2 uv;
out vec3 colour;
uniform sampler2D textureSampler;
void main()
{
colour = texture(textureSampler, uv).rgb;
}
Vertex shader:
#version 330 core
layout(location = 0) in vec2 vertexpos;
layout(location = 1) in vec2 vertexuv;
out vec2 uv;
void main()
{
gl_Position = vec4(vertexpos,0,1); //z = 0, w = 1
uv = vertexuv;
}
As mentioned in the guidelines:
OS: Linux, Debian Stretch
Graphics Card: AMD A10-5757M APU with Radeon™ HD Graphics
Output from glGetString(GL_VENDOR), glGetString(GL_VERSION), glGetString(GL_RENDERER):
Vendor: X.Org,
Version: 4.1 (Core Profile) Mesa 13.0.6
Renderer: Gallium 0.4 on AMD ARUBA (DRM 2.49.0 / 4.9.0-7-amd64, LLVM 3.9.1)
For now I circumvented the issue by upsampling the texture to 4 by 4 but I would really like to now why this is needed.