OpenGL:填充非凸多边形

时间:2021-05-11 09:23:30

OpenGL多边形填充时默认为凸多边形


void MyDraw()
{
glColor3f(1.0, 1.0, 1.0);
glBegin(GL_POLYGON);
glVertex2i(380, 380);
glVertex2i(320, 410);
glVertex2i(180, 280);
glVertex2i(90, 330);
glVertex2i(50, 310);
glVertex2i(50, 150);
glVertex2i(90, 130);
glVertex2i(180, 180);
glVertex2i(320, 50);
glVertex2i(380, 80);
glEnd();
glFlush();
}
填充结果:

OpenGL:填充非凸多边形




OpenGL中认为合法的多边形必须是凸多边形,凹多边形、自交多边形、带孔的多边形等非凸的多边形在OpenGL中绘制会出现出乎意料的结果。例如,在大多数系统中,只有多边形的凸包被填充,而在有些系统中,并非所有的凸包都被填充。OpenGL之所以对合法多边形类型做出限制,是为了更方便地提供能够对符合条件的多边形进行快速渲染的硬件。简单多边形可被快速地渲染,而复杂多边形难以快速检测出来。为了最大限度的提高性能,OpenGL假定多边形是简单的。

OpenGL:填充非凸多边形


非凸多边形最简单的填充方法最简单的应该是GLU 网格化对象GLUtesselator

就是GLUtesselator, 能将任意多边形,简化为三角形或凸多边形的组合,从而使OpenGL能绘制出任意形状的多边形。

1. gluNewTess();                 //创建一个新的分格化对象
2. gluTessCallback();            //注册回调函数,完成分格化的一些操作,照着写就行了。
3. gluTessProperty();            //可有可无的,设置一些分格化的属性值
4. gluTessBeginPolygon();        //开始画多边形
    draw polygon...              //在这里画多边形,一个一个点画就可以,最后一个点会和第一个点自动连接起来
    gluTessEdnPolygon();         //结束画多边形
5. gluDeleteTess();              //删除分格化对象


#include <stdio.h>
#include <stdlib.h>
#include <GL/glut.h>


GLdouble quad[12][3] = { {-2,3,0}, {-2,0,0}, {2,0,0}, { 2,3,0},
{-1,2,0}, {-1,1,0}, {1,1,0}, { 1,2,0}
, {-0.5,1,0}, {-0.5,2,0}, {0.5,2,0}, { 0.5,1,0} };

void myIdle(void)
{
glutPostRedisplay();
}

//------------------------------------------------------------OnDraw()
//

void CALLBACK vertexCallback(GLvoid *vertex)
{
const GLdouble *pointer;
pointer = (GLdouble *) vertex;
glColor3dv(pointer+3);//在此设置颜色
glVertex3dv(pointer);
}

void CALLBACK beginCallback(GLenum which){
glBegin(which);
}

void CALLBACK endCallback (){
glEnd();
}

void CALLBACK errorCallback(GLenum errorCode){
const GLubyte *estring;
estring = gluErrorString(errorCode);
fprintf(stderr, "Tessellation Error: %s\n", estring);
exit(0);
}
void CALLBACK combineCallback(GLdouble coords[3],
GLdouble *vertex_data[4],
GLfloat weight[4], GLdouble **dataOut )
{
GLdouble *vertex;
int i;
vertex = (GLdouble *) malloc(6 * sizeof(GLdouble));
vertex[0] = coords[0];
vertex[1] = coords[1];
vertex[2] = coords[2];
for (i = 3; i < 7; i++)
vertex[i] = weight[0] * vertex_data[0][i]
+ weight[1] * vertex_data[1][i]
+ weight[2] * vertex_data[2][i]
+ weight[3] * vertex_data[3][i];
*dataOut = vertex;
}

void OnDraw() {

// clear the screen & depth buffer
glClear(GL_COLOR_BUFFER_BIT);

// clear the previous transform
glLoadIdentity();


GLUtesselator* tobj = gluNewTess();
if (!tobj) return;

gluTessCallback(tobj, GLU_TESS_VERTEX, (void (CALLBACK *)())vertexCallback);
gluTessCallback(tobj, GLU_TESS_BEGIN, (void (CALLBACK *)())beginCallback);
gluTessCallback(tobj, GLU_TESS_END, (void (CALLBACK *)())endCallback);
gluTessCallback(tobj, GLU_TESS_ERROR, (void (CALLBACK *)())errorCallback);
gluTessCallback(tobj, GLU_TESS_COMBINE, (void (CALLBACK *)())combineCallback);

//glShadeModel(GL_FLAT);

//gluTessProperty(tobj,GLU_TESS_WINDING_RULE,GLU_TESS_WINDING_POSITIVE); //GLU_TESS_WINDING_ODD

gluTessBeginPolygon(tobj,NULL);

gluTessBeginContour(tobj);
gluTessVertex(tobj, quad[0], quad[0]);
gluTessVertex(tobj, quad[1], quad[1]);
gluTessVertex(tobj, quad[2], quad[2]);
gluTessVertex(tobj, quad[3], quad[3]);
gluTessEndContour(tobj);

gluTessBeginContour(tobj); // inner quad (hole)
gluTessVertex(tobj, quad[4], quad[4]);
gluTessVertex(tobj, quad[5], quad[5]);
gluTessVertex(tobj, quad[6], quad[6]);
gluTessVertex(tobj, quad[7], quad[7]);
gluTessEndContour(tobj);

gluTessBeginContour(tobj); // inner quad (hole)
gluTessVertex(tobj, quad[8], quad[8]);
gluTessVertex(tobj, quad[9], quad[9]);
gluTessVertex(tobj, quad[10], quad[10]);
gluTessVertex(tobj, quad[11], quad[11]);
gluTessEndContour(tobj);


gluTessEndPolygon(tobj);

gluDeleteTess(tobj);
glutSwapBuffers();
}

//------------------------------------------------------------OnInit()
//
void OnInit()
{
//glClearColor(1,1,1,0);
}

//------------------------------------------------------------OnExit()
//
void OnExit() {
}


//------------------------------------------------------------OnReshape()
//
void OnReshape(int w, int h)
{
// prevents division by zero when minimising window
if (h==0)
h=1;

// set the drawable region of the window
glViewport(0,0,w,h);

// set up the projection matrix
glMatrixMode(GL_PROJECTION);
glLoadIdentity();

// just use a perspective projection
//gluPerspective(45,(float)w/h,0.1,100);
if(w<=h)
glOrtho(-4.0,4.0,-4.0*(GLfloat)h/(GLfloat)w,4.0*(GLfloat)h/(GLfloat)w,0.0,100.0);
else
glOrtho(-4.0,4.0,-4.0*(GLfloat)h/(GLfloat)w,4.0*(GLfloat)h/(GLfloat)w,0.0,100.0);

// go back to modelview matrix so we can move the objects about
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}

//------------------------------------------------------------main()
//
int main(int argc,char** argv) {

// initialise glut
glutInit(&argc,argv);

// request a depth buffer, RGBA display mode, and we want double buffering
glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE);

// set the initial window size
glutInitWindowSize(480,480);

// create the window
glutCreateWindow("filling");

// run our custom initialisation
OnInit();

// set the function to use to draw our scene
glutDisplayFunc(OnDraw);

// set the function to handle changes in screen size
glutReshapeFunc(OnReshape);
//glutIdleFunc(&myIdle);

// set the function to be called when we exit
atexit(OnExit);

// this function runs a while loop to keep the program running.
glutMainLoop();

return 0;
}

OpenGL:填充非凸多边形


简单版:

#include <stdio.h>
#include <stdlib.h>
#include <GL/glut.h>

GLdouble quad[12][3] = { {5,5,0}, {15,5,0}, {15,-5,0}, { 5,-5,0},
{0,5,0}, {-15,10,0}, {-5,-10,0}, { -10,5,0}
, {-0.5,1,0}, {-0.5,2,0}, {0.5,2,0}, { 0.5,1,0} };
void myIdle(void)
{
glutPostRedisplay();
}

//------------------------------------------------------------OnDraw()
//
void CALLBACK PolyLine3DBegin(GLenum type)
{
glBegin(type);
}

void CALLBACK PolyLine3DVertex ( GLdouble * vertex)
{
const GLdouble *pointer;
pointer = (GLdouble *) vertex;
glColor3d(1.0,0,0);//在此设置颜色
glVertex3dv(pointer);
}

void CALLBACK PolyLine3DEnd()
{
glEnd();
}
GLUtesselator* tesser()
{
GLUtesselator * tess;
tess=gluNewTess();
gluTessCallback(tess,GLU_TESS_BEGIN,(void (CALLBACK*)())&PolyLine3DBegin);
gluTessCallback(tess,GLU_TESS_VERTEX,(void (CALLBACK*)())&PolyLine3DVertex);
gluTessCallback(tess,GLU_TESS_END,(void (CALLBACK*)())&PolyLine3DEnd);
return tess;
}

/////////////////////////////////////////////////////////////////////////////////




void OnDraw() {

glClear(GL_STENCIL_BUFFER_BIT);

GLUtesselator* tess = tesser();
if (!tess) return;
gluTessBeginPolygon(tess,NULL);

gluTessBeginContour(tess);
for(int i=0;i<4;i++)
gluTessVertex(tess, quad[i], quad[i]);
gluTessEndContour(tess);

gluTessBeginContour(tess);
for(int i=4;i<8;i++)
gluTessVertex(tess, quad[i], quad[i]);
gluTessEndContour(tess);

gluTessEndPolygon(tess);
glutSwapBuffers();
}

//------------------------------------------------------------OnInit()
//
void OnInit()
{
//glClearColor(1,1,1,0);
}

//------------------------------------------------------------OnExit()
//
void OnExit() {
}


//------------------------------------------------------------OnReshape()
//
void OnReshape(int w, int h)
{
// prevents division by zero when minimising window
if (h==0)
h=1;

// set the drawable region of the window
glViewport(0,0,w,h);

// set up the projection matrix
glMatrixMode(GL_PROJECTION);
glLoadIdentity();

// just use a perspective projection
//gluPerspective(45,(float)w/h,0.1,100);
if(w<=h)
glOrtho(-20.0,20.0,-20.0*(GLfloat)h/(GLfloat)w,20.0*(GLfloat)h/(GLfloat)w,0.0,100.0);
else
glOrtho(-20.0,20.0,-20.0*(GLfloat)h/(GLfloat)w,20.0*(GLfloat)h/(GLfloat)w,0.0,100.0);

// go back to modelview matrix so we can move the objects about
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}

//------------------------------------------------------------main()
//
int main(int argc,char** argv) {

// initialise glut
glutInit(&argc,argv);

// request a depth buffer, RGBA display mode, and we want double buffering
glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE);

// set the initial window size
glutInitWindowSize(480,480);

// create the window
glutCreateWindow("fill tess");

// run our custom initialisation
OnInit();

// set the function to use to draw our scene
glutDisplayFunc(OnDraw);

// set the function to handle changes in screen size
glutReshapeFunc(OnReshape);
//glutIdleFunc(&myIdle);

// set the function to be called when we exit
atexit(OnExit);

// this function runs a while loop to keep the program running.
glutMainLoop();

return 0;
}
OpenGL:填充非凸多边形



Reference:

其他填充方法:

http://www.cnblogs.com/mazhenyu/archive/2010/05/18/1738487.html

函数简介:

http://hi.baidu.com/zhujianzhai/item/6ed52336d67e7b9ab80c03eb

http://bbs.csdn.net/topics/100086684

各种填充算法详细讲解:

http://blog.csdn.net/orbit/article/details/7368996