OpenGL: пятна на поверхности изображения

Я пытаюсь закодировать интерфейс для кубика Рубика.

Однако, когда я рисую его, на гранях куба появляются пятна:

Куб

Вот хорошо прокомментированный код. Может ли кто-нибудь помочь мне и, возможно, запустить код и сказать мне, где я могу ошибаться?

#include <GL/glut.h>
#include <stdlib.h>

#include <stdio.h>

void init() {

  glClearColor(1.0f, 0.0f, 1.0f, 1.0f);

  glEnable(GL_DEPTH_TEST);

}

static float x_degs = 0.0f;
static float y_degs = 0.0f;

void keyboard(unsigned char key, int x, int y) {

  switch (key) {

    case 'q':

      exit(EXIT_SUCCESS);

    case 'h':

      y_degs -= 1.0f;

      glutPostRedisplay();

      glutSwapBuffers();

      break;

    case 'j':

      x_degs -= 1.0f;

      glutPostRedisplay();

      glutSwapBuffers();

      break;

    case 'k':

      x_degs += 1.0f;

      glutPostRedisplay();

      glutSwapBuffers();

      break;

    case 'l':

      y_degs += 1.0f;

      glutPostRedisplay();

      glutSwapBuffers();

      break;

  }

}

// half the length of one card

static const float card_half_size = 1.0f;

// half the space between cards

static const float space_half_size = 0.1f;

// number of cards per face

static const int NUM_CARDS_PER_FACE = 4;
/*
// start position of center of top left card 

const float start = - 3 * (card_half_size + space_half_size);

// increment between center of cards

const float incr = 2 * (card_half_size + space_half_size);

// half the size of a cube face

const float cube_half_size = 4 * (card_half_size + space_half_size);
*/
// draw a card centered at the origin

void draw_card() {

  glBegin(GL_QUADS);
    glVertex3f(- card_half_size, - card_half_size, 0.0f);
    glVertex3f(- card_half_size, card_half_size, 0.0f);
    glVertex3f(card_half_size, card_half_size, 0.0f);
    glVertex3f(card_half_size, - card_half_size, 0.0f);
  glEnd();

}

// draw a cube face made up of cards

void draw_card_face() {

  const float cube_half_size = 4 * (card_half_size + space_half_size);
  const float start = - 3 * (card_half_size + space_half_size);
  const float incr = 2 * (card_half_size + space_half_size);

  glColor3f(0.0f, 1.0f, 1.0f);

  glBegin(GL_QUADS);
    glVertex3f(- cube_half_size, - cube_half_size, -0.001f);
    glVertex3f(- cube_half_size, cube_half_size, -0.001f);
    glVertex3f(cube_half_size, cube_half_size, -0.001f);
    glVertex3f(cube_half_size, - cube_half_size, -0.001f);
  glEnd();

  glColor3f(1.0f, 1.0f, 1.0f);

  for (int i = 0; i < NUM_CARDS_PER_FACE; i++)

    for (int j = 0; j < NUM_CARDS_PER_FACE; j++) {

      glPushMatrix();
        glTranslatef(start + i * incr, start + j * incr, 0.0f);
        draw_card();
      glPopMatrix();

    }

}

// draw a cube made up of cards

void draw_card_cube() {

  const float cube_half_size = 4 * (card_half_size + space_half_size);

  // front face

  glPushMatrix();
    glTranslatef(0.0f, 0.0f, cube_half_size);
    draw_card_face();
  glPopMatrix();

  // back face

  glPushMatrix();
    glTranslatef(0.0f, 0.0f, - cube_half_size);
    glRotatef(180.0f, 0.0f, 1.0f, 0.0f);
    draw_card_face();
  glPopMatrix();

  // right face

  glPushMatrix();
    glTranslatef(cube_half_size, 0.0f, 0.0f);
    glRotatef(90.0f, 0.0f, 1.0f, 0.0f);
    draw_card_face();
  glPopMatrix();

  // left face

  glPushMatrix();
    glTranslatef(- cube_half_size, 0.0f, 0.0f);
    glRotatef(- 90.0f, 0.0f, 1.0f, 0.0f);
    draw_card_face();
  glPopMatrix();

  // top face

  glPushMatrix();
    glTranslatef(0.0f, cube_half_size, 0.0f);
    glRotatef(90.0f, 1.0f, 0.0f, 0.0f);
    draw_card_face();
  glPopMatrix();

  // bottom face

  glPushMatrix();
    glTranslatef(0.0f, - cube_half_size, 0.0f);
    glRotatef(- 90.0f, 1.0f, 0.0f, 0.0f);
    draw_card_face();
  glPopMatrix();


}

void display() {

  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glLoadIdentity();

  glRotatef(x_degs, 1.0f, 0.0f, 0.0f);
  glRotatef(y_degs, 0.0f, 1.0f, 0.0f);

  gluLookAt(-0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
  draw_card_cube();
  glutSwapBuffers();

}

void reshape(int w, int h) {

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(-15.0f, 15.0f, -15.0f, 15.0f, -15.0f, 15.0f);
  glViewport(0, 0, w, h);
  glMatrixMode(GL_MODELVIEW);

}

int main(int argc, char **argv) {

  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
  glutCreateWindow(argv[0]);
  init();
  glutKeyboardFunc(keyboard);
  glutDisplayFunc(display);
  glutReshapeFunc(reshape);
  glutMainLoop();
  return 0;

}

Хорошо, я пересмотрел код, чтобы отрисовывать голубые прямоугольники с отставанием на 0,01f единиц вместо 0,001f, и это, кажется, исправило z-борьбу. Однако мне бы хотелось использовать glPolygonOffset(factor,unit) для решения этой проблемы, но я не смог этого сделать по следующим причинам:

  1. Я не знаю, как установить facor и unit (я пробовал 1.0 для обоих).
  2. Я пробовал разные значения безрезультатно.

Вот код без кровотечения/прошивания/z-файтингов:

#include <GL/glut.h>
#include <stdlib.h>

#include <stdio.h>

void init() {

  glClearColor(1.0f, 0.0f, 1.0f, 1.0f);

  glEnable(GL_DEPTH_TEST);

}

static float x_degs = 0.0f;
static float y_degs = 0.0f;

void keyboard(unsigned char key, int x, int y) {

  switch (key) {

    case 'q':

      exit(EXIT_SUCCESS);

    case 'h':

      y_degs -= 1.0f;

      glutPostRedisplay();

      glutSwapBuffers();

      break;

    case 'j':

      x_degs -= 1.0f;

      glutPostRedisplay();

      glutSwapBuffers();

      break;

    case 'k':

      x_degs += 1.0f;

      glutPostRedisplay();

      glutSwapBuffers();

      break;

    case 'l':

      y_degs += 1.0f;

      glutPostRedisplay();

      glutSwapBuffers();

      break;

  }

}

// half the length of one card

static const float card_half_size = 1.0f;

// half the space between cards

static const float space_half_size = 0.1f;

// number of cards per face

static const int NUM_CARDS_PER_FACE = 4;
/*
// start position of center of top left card 

const float start = - 3 * (card_half_size + space_half_size);

// increment between center of cards

const float incr = 2 * (card_half_size + space_half_size);

// half the size of a cube face

const float cube_half_size = 4 * (card_half_size + space_half_size);
*/
// draw a card centered at the origin

void draw_card() {

  glBegin(GL_QUADS);
    glVertex3f(- card_half_size, - card_half_size, 0.0f);
    glVertex3f(- card_half_size, card_half_size, 0.0f);
    glVertex3f(card_half_size, card_half_size, 0.0f);
    glVertex3f(card_half_size, - card_half_size, 0.0f);
  glEnd();

}

// draw a cube face made up of cards

void draw_card_face() {

  const float cube_half_size = 4 * (card_half_size + space_half_size);
  const float start = - 3 * (card_half_size + space_half_size);
  const float incr = 2 * (card_half_size + space_half_size);

  glColor3f(0.0f, 1.0f, 1.0f);

  glBegin(GL_QUADS);
    glVertex3f(- cube_half_size, - cube_half_size, -0.001f);
    glVertex3f(- cube_half_size, cube_half_size, -0.001f);
    glVertex3f(cube_half_size, cube_half_size, -0.001f);
    glVertex3f(cube_half_size, - cube_half_size, -0.001f);
  glEnd();

  glColor3f(1.0f, 1.0f, 1.0f);

  for (int i = 0; i < NUM_CARDS_PER_FACE; i++)

    for (int j = 0; j < NUM_CARDS_PER_FACE; j++) {

      glPushMatrix();
        glTranslatef(start + i * incr, start + j * incr, 0.0f);
        draw_card();
      glPopMatrix();

    }

}

// draw a cube made up of cards

void draw_card_cube() {

  const float cube_half_size = 4 * (card_half_size + space_half_size);

  // front face

  glPushMatrix();
    glTranslatef(0.0f, 0.0f, cube_half_size);
    draw_card_face();
  glPopMatrix();

  // back face

  glPushMatrix();
    glTranslatef(0.0f, 0.0f, - cube_half_size);
    glRotatef(180.0f, 0.0f, 1.0f, 0.0f);
    draw_card_face();
  glPopMatrix();

  // right face

  glPushMatrix();
    glTranslatef(cube_half_size, 0.0f, 0.0f);
    glRotatef(90.0f, 0.0f, 1.0f, 0.0f);
    draw_card_face();
  glPopMatrix();

  // left face

  glPushMatrix();
    glTranslatef(- cube_half_size, 0.0f, 0.0f);
    glRotatef(- 90.0f, 0.0f, 1.0f, 0.0f);
    draw_card_face();
  glPopMatrix();

  // top face

  glPushMatrix();
    glTranslatef(0.0f, cube_half_size, 0.0f);
    glRotatef(90.0f, 1.0f, 0.0f, 0.0f);
    draw_card_face();
  glPopMatrix();

  // bottom face

  glPushMatrix();
    glTranslatef(0.0f, - cube_half_size, 0.0f);
    glRotatef(- 90.0f, 1.0f, 0.0f, 0.0f);
    draw_card_face();
  glPopMatrix();


}

void display() {

  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glLoadIdentity();

  glRotatef(x_degs, 1.0f, 0.0f, 0.0f);
  glRotatef(y_degs, 0.0f, 1.0f, 0.0f);

  gluLookAt(-0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
  draw_card_cube();
  glutSwapBuffers();

}

void reshape(int w, int h) {

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(-15.0f, 15.0f, -15.0f, 15.0f, -15.0f, 15.0f);
  glViewport(0, 0, w, h);
  glMatrixMode(GL_MODELVIEW);

}

int main(int argc, char **argv) {

  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
  glutCreateWindow(argv[0]);
  init();
  glutKeyboardFunc(keyboard);
  glutDisplayFunc(display);
  glutReshapeFunc(reshape);
  glutMainLoop();
  return 0;

}

person John Goche    schedule 11.11.2011    source источник
comment
пятна на гранях куба. Есть ли шанс получить изображение?   -  person Bart    schedule 11.11.2011
comment
Я предлагаю использовать мягкое моющее средство и мягкую ткань.   -  person Throwback1986    schedule 11.11.2011
comment
Здравствуйте, я не знаю, как включить изображение в переполнение стека, поэтому я разместил его на PicasaWeb здесь: !ссылка   -  person John Goche    schedule 11.11.2011
comment
Вам не нужны glutSwapBuffers() в обработчике клавиатуры, только glutPostRedisplay()   -  person genpfault    schedule 11.11.2011
comment
Правда, я удалил glutSwapBufers() из оператора switch, но пятна остались. Не знаю, что с этим делать, я попытался нарисовать голубой прямоугольник немного позади белых квадратов, но безуспешно. Есть идеи?   -  person John Goche    schedule 12.11.2011
comment
Дважды проверьте, сколько битов имеет ваш буфер глубины с помощью glGet(). и GL_DEPTH_BITS. Некоторые люди могут по умолчанию получать 24- или 32-битные буферы глубины, тогда как вы можете получить 16, если вы запускаете свою программу на виртуальной машине.   -  person genpfault    schedule 12.11.2011
comment
инт фу; glGetIntegerv(GL_DEPTH_BITS, &foo); printf(%d\n, foo); результат этого вызова 24 на моей машине.   -  person John Goche    schedule 12.11.2011


Ответы (3)


Я думаю, что вы рисуете свои шашки как компланарные четырехугольники граней вашего основного куба; в этом случае проблема, с которой вы сталкиваетесь, называется «z-борьбой».

Вы можете взглянуть на точку 12.040. Кажется, что буферизация глубины работает, но полигоны, кажется, просачиваются через полигоны, которые находятся перед ними. Что происходит? здесь: http://www.opengl.org/resources/faq/technical/depthbuffer.htm

По сути, ваш буфер глубины не имеет достаточной точности, чтобы определить, какой четырехугольник отображать для каждого пикселя, что вызывает проблему.

Вы можете вручную добавить смещение к квадратам шашек, чтобы отодвинуть их от куба; или используйте смещение глубины через glPolygonOffset, чтобы решить проблему.

person rotoglup    schedule 11.11.2011

Я думаю, вы пытаетесь сделать копланарный рендеринг. Загляните в glPolygonOffset() вместо того, чтобы использовать небольшие смещения по оси Z, как вы делаете.

person genpfault    schedule 11.11.2011
comment
Спасибо за ваши ответы. Да, я пытался сделать копланарный рендеринг. Почему glPolygonOffset() более стабильна, чем использование небольших смещений по оси z, и как мне использовать ее в моем коде? Как выбрать два параметра для glPolygonOffset() и где разместить вызовы glPolygonOffset() в коде. - person John Goche; 12.11.2011

Вот что я получаю из вашего кода, скомпилированного с помощью gcc -std=c99 -lGL -lGLU -lglut a.c: никаких пятен. Можешь опубликовать свой? (Ubuntu 11.10, графический процессор Intel)

локальный скриншот

person eudoxos    schedule 11.11.2011
comment
Привет, спасибо за ваш ответ, например, верхняя сторона полностью синяя, а не клетчатая. Теперь попробуйте ввести j, k, h, l, чтобы переместить куб. Смотрите ссылку выше, где я разместил изображение. Есть подтеки (также Ubuntu 11.10 с gcc -std=c99 foo.c -lGL -lGLU -lglut - person John Goche; 11.11.2011
comment
Куб стабилен, если я его вращаю, по крайней мере здесь. Из того, что вы опубликовали, я предполагаю, что некоторые вершины очень близки друг к другу, и какой треугольник выигрывает на поверхности, численно нестабилен. Но код подробно не читал. - person eudoxos; 12.11.2011
comment
Имеет ли значение тот факт, что я запускаю свой код внутри Oracle VirtualBox с Ubuntu 11.10? Моя видеокарта — NVIDIA GeForce 410M. - person John Goche; 12.11.2011
comment
Кажется, драйвер - единственная разница. Другие ответы, кажется, подтверждают нестабильность координаты z, которую я также предложил. - person eudoxos; 12.11.2011