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”細分的原理以及細節解釋的文章,有興趣的朋友可以看一下。