1

非凸多角形を描画するために gluTess* 関数を使用しています。すべてのステップでテッセレーションをやり直すのを避けるために、結果を配列に格納し、OpenGL の頂点配列機能を使用して描画します。

私の問題は、何らかの理由で、初めて gluTess* を使用したときに、三角形の一部しか描画されないことです。gluTess* を強制的に再作成すれば、すべて問題ありません。

gluTess* を再作成するために、頂点配列を含むオブジェクトを完全に破棄して再作成することに注意してください (これにより、頂点配列オブジェクトの再計算が強制されます)。

なぜそうなるのかについて何か考えはありますか?

いくつかのランダムなアイデア:

  • 最初の OpenGL 呼び出しでは、ウィンドウがまだフルサイズになっていないためでしょうか?
  • 後で行うOpenGLの状態を設定する必要がありますか?最初の呼び出しではありませんか?

ありがとう。

編集:テストとして、頂点配列を作成、破棄、および再作成しました。それは問題を解決します。つまり、OpenGL の状態を変更しないと、gluTess* への最初の呼び出しでポリゴンを正しくテッセレートできません。しかし、2つ目は成功します。誰かが前にそれに気づきましたか?

編集(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);

2 番目の呼び出しが成功すると、beginVA、endVA、および vertexVA が正常に機能すると思われます (前述のとおり、2 番目の呼び出しは、主に頂点配列を保持するデータ構造 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 を使用して結合関数の結果を格納しました。後でうまくいった理由はわかりませんが、最初はうまくいかなかったのは当然のことでした。申し訳ありませんが、これで本件はクローズさせていただきます。

4

1 に答える 1

2

OpenGLとGLUは互いに独立しています。これらは通常一緒になりますが、GLUテッセレーション機能はOpenGLとは独立して機能します。

テッセレートされた頂点データを保存することは良いことです、それはそれが行われるべき方法です。

編集:最初の2つの質問編集で回答:

テッセレーションされたデータを再作成せずに再描画を発行しようとしましたか?

関連するコードとそのコンテキストを示すと、適切で賢明な答えを出すのがはるかに簡単になります。

編集:3番目の質問による回答編集:

次の質問: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ます。

于 2011-06-23T12:55:20.047 に答える