OpenGL 绘制二维图形

OpenGL 绘制二维图形




注:本文程序建立在OpenGL MFC单文档环境配置


在讲解绘制图形之前,先分享一下我在绘制图形的过程中,遇到的一个问题。
四月份中旬,同学找我做一个关于三维绘图的毕业设计。一开始我是拒绝的,原因很简单,我不会。
后来他给我一份报酬,好吧,我妥协了。但是问题来了,我连最基本的环境配置都不会,当时自己也苦于毕业设计。
没有充分的时间,环境配置无论是从博客上还是书上,都没能搭建成功。
直至前几天,我无意间发现了一个函数:SwapBuffers(wglGetCurrentDC());
才让我从困顿中走出来,至于我同学的毕设,我最后从网上找了一个模板……

SwapBuffers(wglGetCurrentDC()):
SwapBuffers命令是把前台和后台的缓冲区指针进行交换,把前台的内容变成后台缓冲的内容,把后台的缓冲区内容换到前台,并且不对换过来的后台buffer做清理,所以每帧都glClear一次,然后再绘制,而后再SwapBuffers。

使用说明:
每次绘图需要在OnDraw(CDC* pDC)中调用,例如:
void CStepinGLView::OnDraw(CDC* pDC)
{
	CStepinGLDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	// TODO: 在此处为本机数据添加绘制代码
	DrawCube();
	
	SwapBuffers(wglGetCurrentDC());
}

好了,废话就说到这。


1.绘制点

void CStepinGLView::DrawScene(void)
{
	glClearColor(1.0f,1.0f,1.0f,0.0f);         //设置窗口为白色
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
	glColor3f(1.0f,0.0f,0.0f);                //颜色为红色

	//绘制点
	GLfloat fPointSize[2];
	glGetFloatv(GL_POINT_SIZE_RANGE,fPointSize);  //获取点的大小范围   fPointSize[0]储存点的大小最小值,1存储最大值
	glPointSize(fPointSize[1] / 2.0f);
	glBegin(GL_POINTS);
	glVertex2f(0.0f,0.0f);
	glVertex2f(0.5f,0.5f);
	glVertex2f(-0.5f,0.5f);
	glVertex2f(0.5f,-0.5f);
	glVertex2f(-0.5f,-0.5f);
	glEnd();
}
此段代码中: glGetFloatv(GL_POINT_SIZE_RANGE,fPointSize); 

glGetFloatv第一个参数必须是OpenGL常量,第二个参数是一个数组的地址。函数按第一个参数的指示向第二个参数所指的地址传输数据。fPointSize[0]存储点的大小的最小值,fPointSize[1]存储点的大小的最大值。

运行截图:


2.绘制直线和线型

void CStepinGLView::DrawLineStipple(void)
{
	glClearColor(1.0f,1.0f,1.0f,0.0f);         //设置窗口为白色1. 1. 1.  黑色0. 0. 0.
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glColor3f(1.0f,0.0f,0.0f);                //颜色为红色

	GLfloat fLineWidth[2];
	glGetFloatv(GL_LINE_WIDTH_RANGE,fLineWidth);
	glLineWidth(fLineWidth[1] / 6.0f);

	glBegin(GL_LINES);
	glVertex2f(-0.8f,0.8f);
	glVertex2f(0.8f,0.8f);
	glEnd();
	
	//glEnable(GL_LINE_STRIP);     //第一次使用此类型,输出都是直线
	glEnable(GL_LINE_STIPPLE);     //glEnable()启用函数  ,此句执行后 执行画虚线

	glLineStipple(1,0x00FF);     //设置直线的当前点画模式
	glBegin(GL_LINES);
	glVertex2f(-0.8f,0.4f);
	glVertex2f(0.8f,0.4f);
	glEnd();

	glLineStipple(1,0x0F0F);     //设置直线的当前点画模式
	glBegin(GL_LINES);
	glVertex2f(-0.8f,0.0f);
	glVertex2f(0.8f,0.0f);
	glEnd();

	glLineStipple(2,0x0101);     //设置直线的当前点画模式
	glBegin(GL_LINES);
	glVertex2f(-0.8f,-0.4f);
	glVertex2f(0.8f,-0.4f);
	glEnd();

	glLineStipple(1,0x1C47);     //设置直线的当前点画模式
	glBegin(GL_LINES);
	glVertex2f(-0.8f,-0.8f);
	glVertex2f(0.8f,-0.8f);
	glEnd();

	glDisable(GL_LINE_STIPPLE);
	glFinish();
}

OpenGL不仅能画实线,而且可以绘制点画线(Stippled Lines)等其他类型的直线。

为了绘制点画线,必须先自定义点画线的线型,然后通过 glLineStipple() 函数让OpenGL获取所定义的线型。

线型是通过二进制来描述的,1代表一个实点,0则表示在该像素处不画直线,即不填充像素。

例如:

0000000011111111;   //对应16进制0x00FF,表示空白线和长折线
0000111100001111;   //0x0F0F,表示空白线及短折线
0000000100000001;   //0x0101,表示点
0001110001000111;   //0x1c47,表示折线点折线
调用glLineStipple()函数,让OpenGL知道已改变的线型。第一个参数数据类型为GLint,表示线型模式重复因子;第二个参数为GLushort,表示所定义的线型。重复因子说明了用二进制表示的点的重复次数。如果重复因子是2,一个01010101的线型模式事实上被当成0011001100110011线型来处理。


为了对所定义的线型获取OpenGL的支持,必须事先启动改变线型的机制:

glEnable(GL_LINE_STIPPLE);     //glEnable()启用函数  ,此句执行后 执行画虚线

要注意,当不再使用自定义线型时,将其关闭:

glDisable(GL_LINE_STIPPLE);

程序运行截图:



3.绘制不闭合折线

void CStepinGLView::DrawLineStrip(void)
{
	glClearColor(1.0f,1.0f,1.0f,0.0f);         //设置窗口为白色1. 1. 1.  黑色0. 0. 0.
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glColor3f(1.0f,0.0f,0.0f);                //颜色为红色

	GLfloat fLineWidth[2];
	glGetFloatv(GL_LINE_WIDTH_RANGE,fLineWidth);
	glLineWidth(fLineWidth[1] / 6.0f);

	glBegin(GL_LINE_STRIP);               //绘制不闭合折线
	glVertex2f(-0.8f,0.6f);
	glVertex2f(0.8f,0.6f);

	glVertex2f(-0.8f,0.2f);
	glVertex2f(0.8f,0.2f);

	glEnd();
}
程序运行截图:



4.绘制闭合折线

void CStepinGLView::DrawLineLoop(void)
{
	glClearColor(1.0f,1.0f,1.0f,0.0f);         //设置窗口为白色1. 1. 1.  黑色0. 0. 0.
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glColor3f(1.0f,0.0f,0.0f);                //颜色为红色

	GLfloat fLineWidth[2];
	glGetFloatv(GL_LINE_WIDTH_RANGE,fLineWidth);
	glLineWidth(fLineWidth[1] / 6.0f);

	glBegin(GL_LINE_LOOP);               //绘制闭合折线
	glVertex2f(-0.8f,0.6f);
	glVertex2f(0.8f,0.6f);

	glVertex2f(-0.8f,0.2f);
	glVertex2f(0.8f,0.2f);

	glVertex2f(-0.8f,0.0f);
	glVertex2f(0.8f,0.0f);
	glEnd();
}
程序运行截图:



5.绘制多边形

void CStepinGLView::DrawPolygons(void)
{
	glClearColor(1.0f,1.0f,1.0f,0.0f);         //设置窗口为白色1. 1. 1.  黑色0. 0. 0.
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glColor3f(1.0f,0.0f,0.0f);                //颜色为红色

	glLineWidth(2.0f);
	glPolygonMode(GL_FRONT,GL_LINE);
	glPolygonMode(GL_BACK,GL_FILL);

	glFrontFace(GL_CCW);

	glBegin(GL_POLYGON);
	glVertex2f(-0.3f,0.3f);
	glVertex2f(-0.7f,-0.2f);
	glVertex2f(-0.3f,-0.4f);
	glVertex2f(0.4f,-0.4f);
	glVertex2f(0.8f,-0.2f);
	glVertex2f(0.4f,0.3f);
	glEnd();
}

在OpenGL中,一个多边形(polygon)至少有3个顶点。直线不能相交,多边形应构成单连通的凸区域。

一个多边形有前面和后面之分,并且前面和后面可以有不同的属性。比如,可以指定一个多边形的前面为红色而后面为蓝色。


一个多边形的前面和后面是需要指定的,可以通过定义其顶点顺序来确定。

如果顶点的排序顺序是逆时针的,则该多边形是前面的,如果顶点的排序属性是顺时针的,则该多边形是后面的。

事实上,这是可以改变的。OpenGL提供了一个灵活的函数:

glFrontFace()。该函数参数只能是GL_CW或GL_CCW;

GL_CW表示按顺时针顺序定义的多边形是前面的;

GL_CCW表示按逆时针顺序定义的多边形是前面的;


多边形是封闭的线段构造的形状,它与用GL_LINE_LOOP 绘制的闭合折线有本质的区别。一个多边形可以进行填充,也可以不填充。这样就需要对多边形的绘制模式作出说明。可以采用:

glPolygonMode() :该函数有两个参数;

第一个参数:GL_FRONT、GL_BACK、GL_FRONT_AND_BACK  ,分别指多边形前面、后面或前后两面;

第二个参数:GL_POINT、GL_LINE、GL_FILL  ,分别指 在多边形的顶点画点,画多边形框架,填充多边形;


程序运行截图:



6.绘制三角形

void CStepinGLView::DrawTriangles(void)
{
	glClearColor(1.0f,1.0f,1.0f,0.0f);         //设置窗口为白色
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glColor3f(1.0f,0.0f,0.0f);                //颜色为红色

	//glTranslatef( -1.5f, 0.0f, -6.0f);        //左移1.5单位,并移入屏幕6.0
	glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
	glLineWidth(1.0f);

	glBegin(GL_TRIANGLES);
	glVertex2f(-0.5f, 0.4f);
	glVertex2f(-0.6f, -0.5f);
	glVertex2f(0.5f, -0.5f);

	glVertex2f(-0.5f, 0.8f);
	glVertex2f(-0.5f, 0.6f);
	glVertex2f(0.5f, 0.5f);
	glEnd();

}

程序运行截图:



7.绘制三角形片

void CStepinGLView::DrawTriangleStrip(void)     //绘制三角形片
{
	glClearColor(1.0f,1.0f,1.0f,0.0f);         //设置窗口为白色1. 1. 1.  黑色0. 0. 0.
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glColor3f(1.0f,0.0f,0.0f);                //颜色为红色

	glLineWidth(1.0f);
	glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);

	glBegin(GL_TRIANGLE_STRIP);
	glVertex2f(-0.8f,0.3f);
	glVertex2f(-0.8f,-0.3f);
	glVertex2f(-0.3f,-0.3f);
	glVertex2f(0.0f,-0.3f);
	glVertex2f(0.3f,0.5f);
	glEnd();
}

采用顶点描述三角形时,前三个顶点描述了第一个三角形,第四个顶点可延伸出一个三角形。

在定义三角形片中,第一个三角形的顶点的排序顺序是十分重要的,它决定了整个三角形片是前面还是后面的。

当glFrontFace()函数的参数采用GL_CCW时,第一个三角形按逆时针顺序定义时,其前面是面向我们的。



三角形片中顶点被处理的顺序,如下图:



程序运行截图:



8.绘制三角形扇

void CStepinGLView::DrawTriangleFan(void)    //绘制三角形扇
{
	glClearColor(1.0f,1.0f,1.0f,0.0f);         //设置窗口为白色1. 1. 1.  黑色0. 0. 0.
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glColor3f(1.0f,0.0f,0.0f);                //颜色为红色

	glLineWidth(1.0f);
	glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);

	glBegin(GL_TRIANGLE_FAN);
	glVertex2f(-0.5f,-0.3f);
	glVertex2f(0.3f,0.0f);
	glVertex2f(0.3f,0.3f);
	glVertex2f(0.4f,0.6f);
	glVertex2f(-0.0f,0.6f);

	glEnd();
}

三角形扇的绘制中,前三个顶点定义了第一个三角形,每增加一个顶点,便增加一个三角形;




程序运行截图:



9.绘制四边形

void CStepinGLView::DrawQuadrilaterala(void)     //四边形
{
	glClearColor(1.0f,1.0f,1.0f,0.0f);         //设置窗口为白色1. 1. 1.  黑色0. 0. 0.
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glColor3f(1.0f,0.0f,0.0f);                //颜色为红色

	glLineWidth(1.0f);
	glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);

	glBegin(GL_QUADS);
	glVertex2f(-0.6f,0.8f);
	glVertex2f(-0.6f,-0.6f);
	glVertex2f(0.5f,0.0f);
	glVertex2f(0.6f,0.5f);
	glEnd();
}
程序运行截图:



10.绘制四边形片

void CStepinGLView::DrawQuadStrip(void)   //四边形片
{
	glClearColor(1.0f,1.0f,1.0f,0.0f);         //设置窗口为白色1. 1. 1.  黑色0. 0. 0.
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glColor3f(1.0f,0.0f,0.0f);                //颜色为红色

	glLineWidth(1.0f);
	glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);

	glBegin(GL_QUAD_STRIP);
	glVertex2f(-0.8f,0.3f);
	glVertex2f(-0.7f,0.6f);
	glVertex2f(-0.6f,0.1f);
	glVertex2f(-0.3f,0.6f);
	glVertex2f(-0.1f,-0.2f);
	glVertex2f(0.0f,0.6f);
	glVertex2f(0.3f,-0.4f);
	glVertex2f(0.6f,0.5f);
	glEnd();
}

绘制示意图:


程序运行截图:



11.边的可见性

void CStepinGLView::DrawNonConvex(void)   //凹多边形
{
	glClearColor(1.0f,1.0f,1.0f,0.0f);         //设置窗口为白色1. 1. 1.  黑色0. 0. 0.
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glColor3f(1.0f,0.0f,0.0f);                //颜色为红色

	glLineWidth(1.0f);
	glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);

	glBegin(GL_POLYGON);
	glEdgeFlag(TRUE);
	glVertex2f(-0.3f,0.3f);
	glEdgeFlag(FALSE);
	glVertex2f(-0.1f,-0.1f);
	glEdgeFlag(TRUE);
	glVertex2f(0.0f,-0.1f);
	glVertex2f(0.0f,0.3f);
	glEnd();

	glBegin(GL_POLYGON);
	glEdgeFlag(TRUE);
	glVertex2f(-0.1f,-0.1f);
	glVertex2f(-0.2f,-0.4f);
	glEdgeFlag(FALSE);
	glVertex2f(0.0f,-0.4f);
	glVertex2f(0.0f,-0.1f);
	glEnd();

	glBegin(GL_POLYGON);
	glEdgeFlag(FALSE);
	glVertex2f(0.0f,-0.1f);
	glEdgeFlag(TRUE);
	glVertex2f(0.0f,-0.4f);
	glVertex2f(0.4f,-0.4f);
	glVertex2f(0.45f,0.1f);
	glEnd();
}

要绘制如图所示的凹多边形,可以通过绘制两个组合的四边形。一个四边形的顶点是(1,2,3,4),另一个四边形的顶点是(3,4,5,6)。但是想产生左图,就需要隐藏3---4这条边。


OpenGL通过 glEdgeFlag() 函数来说明边的可见性。

TRUE  表可见,FALSE   表不可见。


程序运行截图:



12.由面创建三维形状

void CStepinGLView::DrawCube(void)    //绘制立方体
{
	glClearColor(1.0f,1.0f,1.0f,0.0f);         //设置窗口为白色1. 1. 1.  黑色0. 0. 0.
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	
	glColor3f(1.0f,0.2f,0.5f);                //颜色为红色
    glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
	glLineWidth(1.5f);
	glColor3f(0.2f,0.5f,1.0f);
	
	glPushMatrix();
	glRotatef(70.0f,0.0f,1.0f,0.0f);      //将盒子绕Y轴70度
	glRotatef(55.0f,0.0f,0.0f,1.0f);      //将盒子绕Z轴55度
	
	glBegin(GL_POLYGON);   //前面
	glVertex3f(-0.5f,0.5f,0.5f);
	glVertex3f(-0.5f,-0.5f,0.5f);
	glVertex3f(0.5f,-0.5f,0.5f);
	glVertex3f(0.5f,0.5f,0.5f);
	glEnd();

	//为了省事,我直接把前面的矩阵复制下来
	//直接修改最后一位参数,结果绘制出的图形不对
	//原因:点的顺序输入不对,造成
	glBegin(GL_POLYGON);   //后面
	glVertex3f(-0.5f,0.5f,-0.5f);
	glVertex3f(0.5f,0.5f,-0.5f);
	glVertex3f(0.5f,-0.5f,-0.5f);
	glVertex3f(-0.5f,-0.5f,-0.5f);
	glEnd();

	glBegin(GL_POLYGON);   //左面
	glVertex3f(-0.5f,-0.5f,0.5f);
	glVertex3f(-0.5f,0.5f,0.5f);
	glVertex3f(-0.5f,0.5f,-0.5f);
	glVertex3f(-0.5f,-0.5f,-0.5f);
	glEnd();

	glBegin(GL_POLYGON);   //右面
	glVertex3f(0.5f,-0.5f,0.5f);
	glVertex3f(0.5f,-0.5f,-0.5f);
	glVertex3f(0.5f,0.5f,-0.5f);
	glVertex3f(0.5f,0.5f,0.5f);
	glEnd();

	glBegin(GL_POLYGON);   //底面
	glVertex3f(-0.5f,-0.5f,0.5f);
	glVertex3f(0.5f,-0.5f,0.5f);
	glVertex3f(0.5f,-0.5f,-0.5f);
	glVertex3f(-0.5f,-0.5f,-0.5f);
	glEnd();

	glBegin(GL_POLYGON);   //顶面
	glVertex3f(-0.5f,0.5f,0.5f);
	glVertex3f(0.5f,0.5f,0.5f);
	glVertex3f(0.5f,0.5f,-0.5f);
	glVertex3f(-0.5f,0.5f,-0.5f);
	glEnd();

	glPopMatrix();
}


请注意,从外部看,每个面都是前面的。因此, 立方体的背面、左面、和底面的顶点顺序必须是顺时针的

在用多边形描述一个三维物体时,多边形的前后面区分是十分重要的。如果一个面本来是前面的却当成后面来处理很可能产生不良效果,特别是对其进行光照的时候。


程序运行截图:



  • 7
    点赞
  • 66
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值