OpenGL没有办法直接绘制非凸多边形,但是可以通过gluTessVertex()这种OpenGL的“细分”的方法对非凸多边形进行绘制。具体原理是:
GLUtesselator, 能将任意多边形,简化为三角形或凸多边形的组合,从而使OpenGL能绘制出任意形状的多边形。
1. gluNewTess(); //创建一个新的分格化对象2. gluTessCallback(); //注册回调函数,完成分格化的一些操作,照着写就行了。
3. gluTessProperty(); //可有可无的,设置一些分格化的属性值
4. gluTessBeginPolygon(); //开始画多边形
draw polygon... //在这里画多边形,一个一个点画就可以,最后一个点会和第一个点自动连接起来
gluTessEdnPolygon(); //结束画多边形
5. gluDeleteTess(); //删除分格化对象
但是实际操作过程中一定要注意一个问题:
多变形上的点要保证在gluTessEndPolygon()执行之前空间不被释放,一般地,在开始gluTessBeginContour()之前多边形的点就应该已经指定了!!!
否则会出现绘制不出图像的现象,因为OpenGL没有读取到点的信息。以下是我在MFC框架View中用OpenGL绘制任意多边形的方法,大家有兴趣的可以看一下。
void CALLBACK PolyLine3DBegin(GLenum type)
{
glBegin(type);
}
void CALLBACK PolyLine3DVertex(GLdouble * vertex)
{
const GLdouble *pointer = (GLdouble *)vertex;
glColor3d(1.0, 0, 0);//在此设置颜色
glVertex3dv(pointer);
}
void CALLBACK PolyLine3DEnd()
{
glEnd();
}
void DrawFloor(DataFloor* floor)
{
if (!floor) return;
std::vector<glm::vec3>& boundary_pts = *floor->GetBoundaryPtsToFloor();//这里获取点的座标
size_t amount_pts = boundary_pts.size();
if (amount_pts < 3)
return;
GLdouble(*quad)[3];
quad = new GLdouble[amount_pts][3];//申请动态内存
for (int i = 0; i < amount_pts; i++)//初始化所有的点到GLdouble(*quad)[3]中
{
glm::vec3 pt = boundary_pts.at(i);
quad[i][0] = pt.x;
quad[i][1] = pt.y;
quad[i][2] = pt.z;
}
GLfloat curColor[4];
glGetFloatv(GL_CURRENT_COLOR, curColor);
glColor3ub((GLubyte)220, (GLubyte)220, (GLubyte)220);
GLUtesselator* tess = gluNewTess();
if (!tess) return;
gluTessCallback(tess, GLU_TESS_BEGIN, (void (CALLBACK*)())&PolyLine3DBegin);
gluTessCallback(tess, GLU_TESS_VERTEX, (void (CALLBACK*)())&PolyLine3DVertex);
gluTessCallback(tess, GLU_TESS_END, (void (CALLBACK*)())&PolyLine3DEnd);
gluTessBeginPolygon(tess, NULL);
gluTessBeginContour(tess);
for (int i = 0; i< amount_pts; i++)
{//绘制Tess“细分”出的点
gluTessVertex(tess, quad[i], quad[i]);
}
gluTessEndContour(tess);
gluTessEndPolygon(tess);
glColor3f(curColor[0], curColor[1], curColor[2]);
delete[] quad;//释放内存
}
效果如下:
之前我有转载两篇关于“Tess”细分的原理以及细节解释的文章,有兴趣的朋友可以看一下。