【问题标题】:OpenGL tessellation of a car made from a polygon由多边形制成的汽车的 OpenGL 镶嵌
【发布时间】:2012-01-09 07:38:33
【问题描述】:

我正在学习使用 openGL,有人告诉我,因为我的轮拱是凹形的,所以我必须对它们进行镶嵌。所以这是我的前轮拱代码......

GLdouble car[7][2] = { {-1.93,0.3}, {-1.95,0.4}, {-2.2,0.6}, {-2.6,0.6}, {-2.82,0.4}, {-2.8,0.3}, {-2.78,0.0} };
GLUtesselator *tess = gluNewTess(); // create a tessellator

glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureLib[textureindex]);

glBegin(GL_POLYGON);

glTexCoord2f( 0.0 , 0.0 ); glVertex2f(-1.0 , 0.0 );
glTexCoord2f(-0.97, 0.0 ); glVertex2f(-1.97, 0.0 );

// Wheel arch
gluTessBeginContour(tess);
{
    gluTessVertex(tess, car[0], car[0]);
    gluTessVertex(tess, car[1], car[1]);
    gluTessVertex(tess, car[2], car[2]);
    gluTessVertex(tess, car[3], car[3]);
    gluTessVertex(tess, car[4], car[4]);
    gluTessVertex(tess, car[5], car[5]);
    gluTessVertex(tess, car[6], car[6]);
}
gluTessEndContour(tess);

这辆车看起来像这样:

{我也知道纹理是错误的atm)但是你可以看到即使镶嵌了前轮拱也没有改变,所以我猜我镶嵌错了..或者需要更多的镶嵌..还是什么?如果有人可以帮助我解决我在轮拱上遇到的这个巨大问题并纠正它,我将永远感激不尽,因为我一直在努力克服这一点。谢谢:)

整个drawBody函数代码可以在这里找到:http://pastebin.com/s9RpzMsd

更新:感谢所有帮助:感谢镶嵌帮助,我的对象现在看起来像这样。现在只是纹理:)

更新 2:好的,所以我使用了与 PeterT 建议的大致相同的代码,这就是它最终的结果(必须对其进行更改才能编译。如果错误请指出)

glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureLib[textureindex]);

GLUtesselator *tess = gluNewTess(); // create a tessellator

gluTessCallback(tess, GLU_TESS_VERTEX,
               (void (__stdcall *)  ()) &putvertex);
gluTessCallback(tess, GLU_TESS_BEGIN,
               (void (__stdcall *)  ()) &glBegin);
gluTessCallback(tess, GLU_TESS_END,
               (void (__stdcall *)  ()) &glEnd);


gluTessBeginPolygon(tess, NULL);
gluTessBeginContour(tess);
    for(int i=0; i<29;i++)
        gluTessVertex(tess, car[i], car[i]);
        //call gluTessVertex for EVERY vertex in the polygon here 
    gluTessEndContour(tess);
gluTessEndPolygon(tess);
glDisable(GL_TEXTURE_2D);

putvertex 代码为:

void CALLBACK putvertex(GLdouble *verts)
{
//filled according to you texture coordinates:
GLdouble scalefacx = 1.0;
GLdouble scalefacy = 1.0;
GLdouble offsetx = -1.0;
GLdouble offsety = 0.0;
glVertex2dv(verts);
glTexCoord2d(verts[0]*scalefacx - offsetx,verts[1]*scalefacy - offsety);
}

然后看起来像这样:

我是不是哪里出错了? :/

感谢您的帮助,最终图像如下所示:

再次感谢您的帮助!尤其是彼得 :)

【问题讨论】:

    标签: opengl polygon tessellation


    【解决方案1】:

    您不能只对多边形的一部分进行细分,它会起作用,您需要对整个多边形进行细分,如下所示:

       //fix for windows C++:
       #ifndef CALLBACK
       #define CALLBACK
       #endif
    
       tobj = gluNewTess();
       gluTessCallback(tobj, GLU_TESS_VERTEX,
                       (GLvoid (CALLBACK*) ()) &glVertex3dv);
       gluTessCallback(tobj, GLU_TESS_BEGIN,
                       (GLvoid (CALLBACK*) ()) &glBegin);
       gluTessCallback(tobj, GLU_TESS_END,
                       (GLvoid (CALLBACK*) ()) &glEnd);
    
       gluTessBeginPolygon(tobj, NULL);
          gluTessBeginContour(tobj);
             for(int i=0; i<7;i++)
               gluTessVertex(tobj, car[i], car[i]);
             //call gluTessVertex for EVERY vertex in the polygon here 
          gluTessEndContour(tobj);
       gluTessEndPolygon(tobj);
    

    此外,您需要将顶点的所有 3 个组件指定为 GLdouble。所以它会是这样的(当然仍然缺少一些顶点):

    GLdouble car[7][3] = { {-1.93,0.3,0.0}, {-1.95,0.4,0.0}, {-2.2,0.6,0.0}, {-2.6,0.6,0.0}, {-2.82,0.4,0.0}, {-2.8,0.3,0.0}, {-2.78,0.0,0.0} };
    

    为了给每个顶点一个纹理坐标,你需要编写你自己的函数,它接受一个void *(它将包含一个指向顶点的x、y、z坐标的指针)并调用glVertexglTexCoord.

    您还应该避免每帧都进行细分,因此您应该将gluTessBeginPolygongluTessEndPolygon 之间的调用保存在显示列表中,或者更好地让您的GLU_TESS_VERTEX 函数将顶点保存在VBO 中。

    您可能还需要定义GLU_TESS_COMBINE 回调,查看herehere 了解详细信息和更多示例代码。

    edit2:实际上纹理并不是那么容易。这是一些旧的不推荐使用的代码,它可能仍然适用于您,但非常不可靠,尤其是在您使用着色器时。如需更现代的版本,请查看this Thread。您应该删除 glTexCoord2d() 调用,这必须进入绘图函数:

    //adjust these values to the object/texture size
    GLfloat scalex = 1.0;
    GLfloat scaley = 1.0;
    GLfloat offsetx= 0.0;
    GLfloat offsety= 0.0;
    
    //GLdouble gens[4] = {1.0,0.0,0.0,0.0};
    //GLdouble gent[4] = {0.0,1.0,0.0,0.0};
    glEnable(GL_TEXTURE_GEN_S);
    glEnable(GL_TEXTURE_GEN_T);
    
    glTexGend(GL_S,GL_TEXTURE_GEN_MODE,GL_OBJECT_LINEAR);
    glTexGend(GL_T,GL_TEXTURE_GEN_MODE,GL_OBJECT_LINEAR);
    //glTexGendv(GL_S,GL_OBJECT_PLANE,gens);
    //glTexGendv(GL_T,GL_OBJECT_PLANE,gent);
    glMatrixMode(GL_TEXTURE);
    glLoadIdentity();
    glScalef(scalex,scaley,1.0f);
    glTranslatef(offsetx,offsety,0.0);
    
    //do the normal rendering
    glMatrixMode(GL_MODELVIEW);
    glClear(GL_COLOR_BUFFER_BIT);
    ...
    

    另外,请记住,除了小测试之外,对每一帧进行细分仍然不是一个好主意,而是将它与前面所述的显示列表或 VBO 一起使用会更有效。

    【讨论】:

    • 使用上面的代码我得到这个错误... 1>e:\usb\uni work\graphics\coursework\coursework\main.cpp(170): error C2664: 'gluTessCallback' : cannot将参数 3 从 'GLvoid (__cdecl *)(void)' 转换为 'void (__stdcall *)(void)'
    • @MikeTarrant 好的,我编辑了我的答案,以便它在 C++ 下编译并支持带纹理的 2d 元素。
    • @MikeTarrant 是的,任何有点复杂的东西都不适用于该方法,我更新了帖子以提供更通用的方法。
    • @MikeTarrant 啊,是的,画完车身后,您需要调用glDisable(GL_TEXTURE_GEN_S); glDisable(GL_TEXTURE_GEN_T); 以及glMatrixMode(GL_TEXTURE); glLoadIdentity();glMatrixMode(GL_MODELVIEW);。还要记住从putvertex 函数中删除glTexCoord 调用。
    • @MikeTarrant 嗯,这很奇怪,当然你应该在调用gluTessBeginPolygon 之前保留glBindTexture
    【解决方案2】:

    gluTesselator 不会从凹多边形生成单个凸多边形,因为这在数学上是不可能的。它发出多个原始组(GL_POLYGON、GL_TRIANGLE、GL_TRIANGLE_STRIP、GL_TRIANGLE_FAN),这就是您需要传递给 OpenGL 的内容。为 glBegin 和 glEnd 添加 tesselator 回调。

    【讨论】:

    • GL_Triangles 没有产生相同的图像,已经尝试过,tesselator 确实有效:)
    • @datenwolf 根据文档 gluTesselator 可以喷出GL_TRIANGLE_FANGL_TRIANGLE_STRIPS 以及其他如果它认为更有效的话。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-03-21
    • 1970-01-01
    • 2015-02-17
    • 2019-03-14
    • 2021-03-29
    • 2018-09-29
    • 1970-01-01
    相关资源
    最近更新 更多