OpenGL 填充非凸多边形

Posted sownchz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenGL 填充非凸多边形相关的知识,希望对你有一定的参考价值。

分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!http://www.captainbed.net

OpenGL多边形填充时默认为凸多边形
void display()
{
	glClear(GL_COLOR_BUFFER_BIT);
	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();
	glLineWidth(2.0);
	glColor3f(1.0, 0.0, 0.0);
	glBegin(GL_LINE_LOOP);
	{
		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假定多边形是简单的。

技术图片

      非凸多边形最简单的填充方法最简单的应该是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>

#pragma comment(lib,"glut32.lib")

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 = (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
", 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 model view matrix so we can move the objects about
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}
//------------------------------------------------------------	main()
//
int main(int argc,char** argv)
{
	// initialize 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;
}
简单版:
#include <stdio.h>
#include <stdlib.h>
#include <GL/glut.h>

#pragma comment(lib,"glut32.lib")

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 = (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 model view matrix so we can move the objects about
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}
//------------------------------------------------------------	main()
//
int main(int argc, char** argv)
{

	// initialize 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 initialization
	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;
}
技术图片

 



 

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

http://blog.csdn.net/yangtrees/article/details/9040257

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!http://www.captainbed.net

以上是关于OpenGL 填充非凸多边形的主要内容,如果未能解决你的问题,请参考以下文章

片段着色器中未使用纹理数据 - OpenGL

OpenGL研究3.0 多边形区域填充

计算机图形学输出图元_10_多边形填充区_7_OpenGL多边形填充区函数(上)

OpenGL + GLUT没有填充最左边的多边形?

计算机图形学输出图元_11_OpenGL多边形填充区函数(上)

计算机图形学输出图元_10_多边形填充区_8_OpenGL顶点数组