。
GLUtesselator *pTess = gluNewTes(); //注意不是GLUtessellator 少了个l
…
gluDeleteTess(pTess);
所有的曲面细分函数的第一个参数都是镶嵌器对象。这样就允许我们构造多个镶嵌器,并在需要的时候很方便的进行切换,这也使得镶嵌器只影响当前的工作对象。
镶嵌器分解多边形并渲染的步骤如下:
每个多边形由一个或多个轮廓组成。上图左边的多边形就只有一个轮廓,右边的有个洞所以有两个轮廓。曲线细分的工作是到步骤8才进行的。曲线细分会带来一定性能的开销。如果图形是静态的最好是把函数调用放到显示列表中。
在曲面细分的过程中,镶嵌器会调用一系列你提供的回调函数。这些回调函数指定了顶点的信息以及开始和结束图元。注册回调函数的原型如下:
void gluTessCallback(GLUTesselator *tobj, GLenum which, void (*fn)());
第一个参数是镶嵌器对象,第二个指定回调函数的类型,第三个是回调函数指针。
例如:
typedef GLvoid (_stdcall *CallBack)();
gluTessCallback(pTess, GLU_TESS_BEGIN, (CallBack)glBegin);
gluTessCallback(pTess, GLU_TESS_VERTEX, (CallBack)glVertex3dv);
gluTessCallback(pTess, GLU_TESS_END, (CallBack)glEnd);
上面三个函数分别指定了,新图元开始的回调函数,为每一个顶点调用glVertex3dv,以及结束的回调函数。上面只是简单的指定了OpenGL的函数,你也可以自定一个回调函数,里面实现你想要的功能。还可以注册出错时的回调函数:
void gluTessBeginPolygon(GLUTesselator *tobj, void *data);
第一个参数为镶嵌器对象指针,第二个参数是指向曲面细分处理相关联的用户自定义数据,这个数据可以用回调函数在细分的过程中发送回来。一般情况下,这个参数常常设置为NULL. 完成一个多边形后调用下面的函数开始细分。
void gluTessEndPolygon(GLUTesslator *tobj);
下面两个函数开始和结束轮廓,对应于步骤4和6:
void gluTessBeginContour(GLUTesselator *tobj);
void gluTessEndContour(GLUTesselator *tobj);
在这两个函数中,添加轮廓的顶点:
void gluTessVertex(GLUTesselator *tobj, GLdouble v[3], void *data);
v参数包含了用于镶嵌器计算的真实的顶点数据,data参数是指向顶点数据的指针,传给指定的GLU_VERTEX的回调函数。第二个参数可以包含除了顶点之外的一些信息如颜色,法线等。如果我们自己定义了GLU_VERTEX的回调函数,那么就可以使用data的数据了。
一个佛罗里达州的简单轮廓,这个州里面还有个奥基乔比湖的轮廓。通过右键菜单,我们可以在简单的画线环绕模式,外围轮廓曲线细分模式,和复杂模式之间切换。
这里面有个新函数gluTessProperty(pTess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD);这个指定了轮廓线为奇数的是填充的,轮廓线是偶数的是镂空的。我们的湖的轮廓线在里面,是第二个轮廓线,所以是镂空的。
代码如下:
用线环绕的模式:

单轮廓模式:

包含湖的轮廓
