Почему gluTess не работает при первом звонке? - PullRequest
1 голос
/ 23 июня 2011

Я использую функции gluTess * для рисования невыпуклых многоугольников. Чтобы избежать повторения тесселяции на каждом этапе, я сохраняю результат в массиве и использую возможности массива вершин OpenGL для рисования.

Моя проблема в том, что по какой-то причине в первый раз, когда я использую gluTess *, рисуется только часть треугольников. Если я заставлю воссоздать gluTess *, то все в порядке.

Обратите внимание, что для воссоздания gluTess * я полностью уничтожаю объект, содержащий массив вершин, и воссоздаю его (что вызывает пересчет объекта массива вершин).

Есть идеи, почему это так?

Некоторые случайные идеи:

  • Может ли это быть из-за того, что для первого вызова OpenGL окно еще не в полном размере?
  • мне нужно установить какое-нибудь состояние OpenGL, что будет сделано позже, но не при первом вызове?

Спасибо.

Редактировать : В качестве теста я только что создал, уничтожил и воссоздал массив вершин. Это решит проблему. Это означает: без каких-либо изменений в состоянии OpenGL, первый вызов gluTess * не сможет правильно тесселировать полигон. Но вторая удалась. Кто-нибудь заметил это раньше?

Редактировать (2) : Вот код:

VA va;
GLUtesselator *t = gluNewTess();
gluTessCallback(t, GLU_TESS_BEGIN_DATA, (GLvoid (*)())beginVA);
gluTessCallback(t, GLU_TESS_END_DATA, (GLvoid (*)())endVA);
gluTessCallback(t, GLU_TESS_VERTEX_DATA, (GLvoid (*)())vertexVA);
gluTessCallback(t, GLU_TESS_ERROR, (GLvoid (*)())&tessError);
gluTessCallback(t, GLU_TESS_COMBINE, (GLvoid (*)())&tessCombine);

gluTessProperty(t, GLU_TESS_BOUNDARY_ONLY, GL_FALSE);
gluTessProperty(t, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO);

gluTessBeginPolygon(t, &va);
gluTessBeginContour(t);
foreach(Point3d& p, points)
  gluTessVertex(t, const_cast<GLdouble*>(p.c_data()), (void*)&p);
gluTessEndContour(t);
gluTessEndPolygon(t);
gluDeleteTess(t);

Когда второй вызов завершился успешно, я подозреваю, что beginVA, endVA и vertexVA работают нормально (как я уже говорил, второй вызов выполняется путем разрушения структуры данных VA, которая в основном содержит массив вершин).

Редактировать (3) : Вот отсутствующий код:

struct VA
{
  std::vector<Point3d> positions; // Vertex array
  GLenum current_mode; // Drawing mode (GL_TRIANGLE, *_FAN or *_STRIP)
  Point3d v1, v2; // Two last vertices for _FAN or _STRIP
  bool has_v1, has_v2; // did we get the two last vertices?
  int n; // Index of the vertex, for *_STRIP
};


void beginVA(GLenum mode, VA *va)
{
  va->current_mode = mode; // Store the mode
  va->has_v1 = va->has_v2 = false; // We haven't had any vertex yet
  va->n = 0;
}

void endVA(VA *va)
{
  va->current_mode = 0; // Not really necessary, but cleaner
}

void vertexVA(Point3d *p, VA *va)
{
  ++va->n;
  if(va->current_mode == GL_TRIANGLES) // The simple case
    va->positions.push_back(*p);
  else if(!va->has_v1) {
    va->v1 = *p;
    va->has_v1 = true;
  } else if(!va->has_v2) {
    va->v2 = *p;
    va->has_v2 = true;
  } else if(va->current_mode == GL_TRIANGLE_STRIP) {
    if(va->n%2 == 1) {
      va->positions.push_back(va->v1);
      va->positions.push_back(va->v2);
      va->positions.push_back(*p);
    } else {
      va->positions.push_back(va->v2);
      va->positions.push_back(va->v1);
      va->positions.push_back(*p);
    }
    va->v1 = va->v2;
    va->v2 = *p;
  } else { // GL_TRIANGLE_FAN
    va->positions.push_back(va->v1);
    va->positions.push_back(va->v2);
    va->positions.push_back(*p);
    va->v2 = *p;
  }
}

Редактировать (4) : В конце концов, ошибка была в другом месте. Должно быть, я устал, я использовал std :: vector для хранения результата функции объединения. Я не знаю, почему это сработало позже, но это было нормально, это не сработало с первого раза! Извините, я сейчас закрою эту тему.

1 Ответ

2 голосов
/ 23 июня 2011

OpenGL и GLU не зависят друг от друга.Обычно они собираются вместе, но функции тесселяции GLU работают независимо от OpenGL.

Хорошо хранить данные вершин в тесселяции, вот как это должно быть сделано.

РЕДАКТИРОВАТЬ: ответили первые два вопроса:

Пытались ли вы перерисовать без пересоздания данных по тесселяции?

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

РЕДАКТИРОВАТЬ: ответ на третий вопрос edit:

Следующий вопрос: Что такое подпись beginVA, endVA, vertexVA?И как vertexVA вставляет вершину в VA.Как выглядит VA?(класс, определение структуры и т. д.).

Могу ли я предложить следующее предложение:

struct VA
{
  std::vector<Point3d> positions; // Vertex array
  std::vector<GLuint> triangle_face_indices;
  std::vector<GLuint> tristrip_face_indices;
  std::vector<GLuint> trifan_face_indices;
  GLenum current_mode; // Drawing mode (GL_TRIANGLE, *_FAN or *_STRIP)
};

void beginVA(GLenum mode, VA *va)
{
  va->current_mode = mode; // Store the mode
}

void endVA(VA *va)
{
  va->current_mode = 0; // Not really necessary, but cleaner
}

void vertexVA(void *p, VA *va)
{
  GLuint idx = (GLuint)((intptr_t) p);

  switch(va->current_mode) {
  case      GL_TRIANGLES: va->triangle_face_indices.push_back(i); break;
  case GL_TRIANGLE_STRIP: va->tristrip_face_indices.push_back(i); break;
  case   GL_TRIANGLE_FAN: va->trifan_face_indices.push_back(i); break;
  }
}

использовать так

gluTessBeginPolygon(t, &va);
gluTessBeginContour(t);
for(GLuint i = 0; i < va.positions.size(); i++) {
  gluTessVertex(t, const_cast<GLdouble*>(va.positions[i].c_data()), (void*)((intptr_t)i));
}
gluTessEndContour(t);
gluTessEndPolygon(t);
gluDeleteTess(t);

И нарисоватьиспользуя 3 последовательных вызова на glDrawElements для любого режима рисования.

...