【问题标题】:Why is gluTess not working on first call?为什么 gluTess 在第一次通话时不工作?
【发布时间】:2011-06-24 17:57:11
【问题描述】:

我正在使用 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 来存储 combine 函数的结果。我不知道为什么后来它起作用了,但它肯定是正常的,它第一次不起作用!抱歉,我现在关闭这个主题。

【问题讨论】:

    标签: opengl glu tesselation


    【解决方案1】:

    OpenGL 和 GLU 是相互独立的。它们通常组合在一起,但 GLU 细分函数独立于 OpenGL 工作。

    存储细分的顶点数据是一件好事,应该这样做。

    编辑:前两个问题编辑回答:

    您是否尝试过重绘 没有重新设计的棋盘格 数据?

    给一个好东西会容易得多 和明智的答案,如果你会展示 相关代码及其上下文。

    编辑:由第三个问题编辑回答:

    下一个问题:签名是什么 beginVA,endVA,顶点VA?如何 vertexVA 是否将顶点插入 弗吉尼亚州。 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 进行绘制。

    【讨论】:

    • 我已将镶嵌代码作为我帖子的编辑。但是,“重绘而不重新绘制镶嵌数据”是什么意思?我的对象不断重绘,因为我可以在它周围移动。绘图完全一致,没有闪烁,三角形真的不存在。
    • @PierreBdR:有些人为绘图函数的每次迭代重新细分他们的网格;因为你说你存储你的顶点是我的一个愚蠢的问题。
    • mmmh .. 我宁愿不要,因为我要绘制很多多边形,并且使用 _STRIP 或 _FAN 意味着每个条带或扇形调用一次 glDrawElements。
    • @PierreBdR 现代 OpenGL 没有问题:opengl.org/sdk/docs/man3/xhtml/glPrimitiveRestartIndex.xml
    • 确实,我不知道!
    猜你喜欢
    • 1970-01-01
    • 2017-05-29
    • 2017-07-16
    • 1970-01-01
    • 2011-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多