Search code examples
copengl

OpenGL, object blinking when moving


I'm new to OpenGL, and I'm trying to move an object using the mouse. I'm using OpenGL 4.4 Core Profile, MinGW32, freeGLUT, GLU, and GLEW, programming in C.

The program draw an hexagon with GL_LINE_LOOP and the color (0.5, 0.5, 0.5, 1.0).

The problem is when I move it using the mouse, the object is softly blinking, the color changes to a darker grey. The blinking also occurs when drawing with the color (1.0, 1.0, 1.0, 1.0), but it is less visible.

I tried to change the swap interval using wglSwapIntervalEXT(), but it accepts only values 0 and 1. I also tried to enable Triple Buffering and "wait for Vsync" parameter of my graphic card. Changing these three parameters doesn't solve the problem.

The code is very simple, the vertex shader takes an Uniform vector t that corresponds to the translation to apply to the object.

Vertex shader program:

#version 440 core
in vec3 vertex_position;
uniform vec3 vertex_color;
uniform vec4 t;
uniform mat4 matrix;

out vec4 color;

vec4 vp;

void main() {
  color = vec4(vertex_color,1.0);
  vp = matrix * vec4(vertex_position,1.0);
  gl_Position = vec4(vp.x+t.x, vp.y+t.y, vp.z+t.z, vp.w+t.w);
}

Fragment shader program:

#version 440 core
in vec4 color;
void main()
{
  gl_FragColor = color;
}

The draw function is very simple, and I have a timer function that call glutPostRedisplay() every 16 ms, in order to have arround 60 FPS. I tried without the timer function, it increases the FPS, but the blinking even occurs.

The draw function:

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

static int init = 1;
if(init == 1) {
  glUseProgram(shader_program_core);
  matrixloc = glGetUniformLocation(shader_program_core,"matrix");
  // Load the matrix into the vertex shader:
  glUniformMatrix4fv(matrixloc, 1, GL_FALSE, PMVmatrix);
  colorloc = glGetUniformLocation(shader_program_core,"vertex_color");
  // translation localisation:
  tloc = glGetUniformLocation(shader_program_core,"t");

  init = 0;
}

glUniform3f(colorloc,0.5,0.5,0.5);
// translation:
glUniform4f(tloc,tx,ty,tz,tw);

glBindVertexArray(vao);

glDrawArrays(GL_LINE_LOOP, 0, 6);

glBindVertexArray(0);


glutSwapBuffers();

The complete source code that shows the problem is here:

#define GLEW_STATIC

#include <GL/glew.h>
#include <GL/freeglut.h>
#include <stdio.h>
#include <math.h>
#include <time.h>

// coordinates of the hexagon:
GLfloat hexagon[18];

GLuint vao;
GLuint vbo;

// translations:
GLfloat tx = 0.0;
GLfloat ty = 0.0;
GLfloat tz = 0.0;
GLfloat tw = 0.0;

// window dimensions:
GLint width;
GLint height;

int window;

// coordinates of clicked point
int clicked_x;
int clicked_y;

// set to 1 if clicked down:
int clicked_down = 0;




/////////////////////////////////////////////////////////
//
// Shader programs for core profile:
//

const char * vsprog_core =
"#version 440 core\n"
"in vec3 vertex_position;\n"
"uniform vec3 vertex_color;\n"
"uniform vec4 t;\n"
"uniform mat4 matrix;\n"
" \n"
"out vec4 color;\n"
" \n"
"vec4 vp;\n"
" \n"
"void main() {\n"
"  color = vec4(vertex_color,1.0);\n"
"  vp = matrix * vec4(vertex_position,1.0);\n"
"  gl_Position = vec4(vp.x+t.x, vp.y+t.y, vp.z+t.z, vp.w+t.w);\n"
"}\n";

const char * fsprog_core = 
"#version 440 core\n"
"in vec4 color;\n"
"void main()\n"
"{\n"
"  gl_FragColor = color;\n"
"}\n";

// uniforms locations:
GLint tloc;
GLint colorloc;
GLint matrixloc;

GLuint shader_program_core;

GLfloat PMVmatrix[16] = {
0.500000,  0.000000,  0.000000,  0.000000,
0.000000,  0.500000,  0.000000,  0.000000,
0.000000,  0.000000,  0.500000,  0.000000,
0.000000,  0.000000,  0.000000,  1.000000
};






void Draw()
{ 
    int i,j;

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);



    static int init = 1;
    if(init == 1) {
      glUseProgram(shader_program_core);
      matrixloc = glGetUniformLocation(shader_program_core,"matrix");
      // Load the matrix into the vertex shader:
      glUniformMatrix4fv(matrixloc, 1, GL_FALSE, PMVmatrix);
      colorloc = glGetUniformLocation(shader_program_core,"vertex_color");
      // translation localisation:
      tloc = glGetUniformLocation(shader_program_core,"t");

      init = 0;
    }

    glUniform3f(colorloc,0.5,0.5,0.5);
    // translation:
    glUniform4f(tloc,tx,ty,tz,tw);

    glBindVertexArray(vao);

    glDrawArrays(GL_LINE_LOOP, 0, 6);

    glBindVertexArray(0);



    glutSwapBuffers();

    //glutPostRedisplay();
}






void onMouseClick(int button, int state, int x, int y) {
  if(state == GLUT_UP && button == GLUT_LEFT_BUTTON) clicked_down = 0;
  if(state == GLUT_DOWN && button == GLUT_LEFT_BUTTON) {
    clicked_down = 1;

    clicked_x = x;
    clicked_y = y;
  }
}



void onMouseMove(int x, int y) {
  int i,j;
  if(clicked_down == 1) {

    // compute x coordinate of the clicked point from the clicked x pixel:
    GLfloat x1 = (clicked_x)*2.0/width - 1.0;

    // compute x coordinate of the actual point from the actual x pixel:
    GLfloat x2 = (x)*2.0/width - 1.0;

    // compute y coordinate of the clicked point from the clicked y pixel:
    GLfloat y1 = (clicked_y)*2.0/height - 1.0;

    // compute y coordinate of the actual point from the actual y pixel:
    GLfloat y2 = (y)*2.0/height - 1.0;

    tx += x2 - x1;
    ty += y1 - y2;


    // save actual coordinates as previous ones, for the next move:
    clicked_x = x;
    clicked_y = y;
  }
}

void timer( int value )
{
    glutPostRedisplay();
    glutTimerFunc( 16, timer, 0 );
}




int main( int argc, char *argv[ ], char *envp[ ] )
{ 
  int i,j;


  glutInitContextVersion(4, 4);
  glutInitContextFlags(GLUT_FORWARD_COMPATIBLE/* | GLUT_DEBUG*/);
  glutInitContextProfile(GLUT_CORE_PROFILE);


  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
  glutInitWindowSize(640,480);
  window = glutCreateWindow("Program");
  //glutFullScreen();

  width = glutGet(GLUT_WINDOW_WIDTH);
  height = glutGet(GLUT_WINDOW_HEIGHT);

  // get version info
  const GLubyte* renderer;
  const GLubyte* version;



  ///////////////////////////////////////////////////////////////////////
  //
  // start GLEW extension handler
  //

  glewExperimental = GL_TRUE;
  GLenum err = glewInit();
  if (GLEW_OK != err)
  {
    fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
    return(-1);
  }
  fprintf(stdout, "Status: Using GLEW %s\n", glewGetString(GLEW_VERSION));




  // get version info
  renderer = glGetString(GL_RENDERER); // get renderer string
  version = glGetString(GL_VERSION); // version as a string
  printf("\nRenderer: %s", renderer);
  printf("\nOpenGL version supported %s", version);
  fflush(stdout);


  // tell GL to only draw onto a pixel if the shape is closer to the viewer
  glEnable(GL_DEPTH_TEST); // enable depth-testing
  glDepthFunc(GL_LESS); // depth-testing interprets a smaller value as "closer"



  //////////////////////////////////////////////////////////
  //
  // Shaders:
  //
  GLint params;
  GLint len;

  GLuint vscore = glCreateShader(GL_VERTEX_SHADER);
  glShaderSource(vscore, 1, &vsprog_core, NULL);
  glCompileShader(vscore);
  glGetShaderiv(vscore,GL_COMPILE_STATUS,&params);
  if(params == GL_FALSE) {
    GLchar log[100000];
    glGetShaderInfoLog(vscore,100000,&len,log);
    printf("\n\n%s\n\n",log);
    return(-1);
  }

  GLuint fscore = glCreateShader(GL_FRAGMENT_SHADER);
  glShaderSource(fscore, 1, &fsprog_core, NULL);
  glCompileShader(fscore);
  glGetShaderiv(fscore,GL_COMPILE_STATUS,&params);
  if(params == GL_FALSE) {
    GLchar log[100000];
    glGetShaderInfoLog(fscore,100000,&len,log);
    printf("\n\n%s\n\n",log);
    return(-1);
  }

  shader_program_core = glCreateProgram();
  glAttachShader(shader_program_core, fscore);
  glAttachShader(shader_program_core, vscore);

  glLinkProgram(shader_program_core);
  glGetProgramiv(shader_program_core,GL_LINK_STATUS,&params);
  if(params == GL_FALSE) {
    GLchar log[100000];
    glGetProgramInfoLog(shader_program_core,100000,&len,log);
    printf("\n\n%s\n\n",log);
    fflush(stdout);
    return(-1);
  }

  //
  //////////////////////////////////////////////////////////




  //////////////////////////////////////////////////////////
  //
  // Compute coordinates of the hexagon:
  //
  hexagon[0] = cos(0.0*M_PI/3.0 + M_PI/6.0)*500.0/width;
  hexagon[1] = sin(0.0*M_PI/3.0 + M_PI/6.0)*500.0/height;
  hexagon[2] = 0.0;
  hexagon[3] = cos(1.0*M_PI/3.0 + M_PI/6.0)*500.0/width;
  hexagon[4] = sin(1.0*M_PI/3.0 + M_PI/6.0)*500.0/height;
  hexagon[5] = 0.0;
  hexagon[6] = cos(2.0*M_PI/3.0 + M_PI/6.0)*500.0/width;
  hexagon[7] = sin(2.0*M_PI/3.0 + M_PI/6.0)*500.0/height;
  hexagon[8] = 0.0;
  hexagon[9] = cos(3.0*M_PI/3.0 + M_PI/6.0)*500.0/width;
  hexagon[10] = sin(3.0*M_PI/3.0 + M_PI/6.0)*500.0/height;
  hexagon[11] = 0.0;
  hexagon[12] = cos(4.0*M_PI/3.0 + M_PI/6.0)*500.0/width;
  hexagon[13] = sin(4.0*M_PI/3.0 + M_PI/6.0)*500.0/height;
  hexagon[14] = 0.0;
  hexagon[15] = cos(5.0*M_PI/3.0 + M_PI/6.0)*500.0/width;
  hexagon[16] = sin(5.0*M_PI/3.0 + M_PI/6.0)*500.0/height;
  hexagon[17] = 0.0;


  // VAO:
  glGenVertexArrays(1, &(vao));
  glBindVertexArray(vao);

  // VBO:
  glGenBuffers(1,&(vbo));
  glBindBuffer(GL_ARRAY_BUFFER,vbo);
  glBufferData(GL_ARRAY_BUFFER, 18 * sizeof(GLfloat), hexagon, GL_STATIC_DRAW);
  glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0*sizeof(GLfloat), (GLvoid*)0);
  glEnableVertexAttribArray(0);
  glBindBuffer(GL_ARRAY_BUFFER,0);

  // End VAO:
  glBindVertexArray(0);



  glutMouseFunc(onMouseClick);
  glutMotionFunc(onMouseMove);
  glutDisplayFunc(Draw);
  glutTimerFunc(0,timer,0);

  glutMainLoop();

  return 0;
}

The shaders are defined in two char* constants. Left-clicking and moving the mouse allow to move the object.


Solution

  • As genpfault suggested, it was a hardware performance problem. I have tried the same program on a 75Hz LCD with 1ms response time.

    It still blinks a little, but it is a lot less perceptible.