本节是OpenGL学习的第七个课时,下面以四边形为例介绍绘制OpenGL动画的相关知识:
(1)绘制几种不同的四边形:
1)四边形(GL_QUADS)
OpenGL的GL_QUADS图元用于绘制四边形,它根据每四个顶点绘制一个四边形。
注意:在使用四边形时必需记住四边形的四个角必须位于同一个平面中(不存在弯曲的四边形)。
2)四边形带(GL_QUAD_STRIP)
该图元指定一个连接的四边形带。它们都保持相同方向的环绕。
3)通用多边形GL_POLYGON
我们可以用它绘制任意数量的多边形。与四边形一样,多边形的所有顶点也必须位于同一平面中。如果想//代码效果参考:http://www.jhylw.com.cn/360236639.html
越过这个规则,可以采用一种变通的方法,使用GL_TRIANGLE_FAN代替GL_POLYGON。4)多边形的创建规则
1.所有的多边形都必须是平面的。也就是说,多边形的所有顶点必须位于同一个平面中。在空间中,多边形不能扭曲或弯曲。
2.多边形的边必须不相交,多边形必须是凸的。
OpenGL施加这些限制的原因:为了使用一些非常快速的算法对多边形进行渲染。
5)细分和边界
尽管OpenGL只能绘制凸多边形,但我们仍然能够创建非凸的多边形,那就是把两个或多个多边形排列在一起。
我们使用OpenGL命令glPolygonMode可以把绘图模式切换到线框模式,这样就能看到组成较大表面区域的每一个较小的三角形。另外,我们还可以通过glEdgeFlag命令来通知OpenGL哪些线段属于边界线(围绕形状边缘的直线),哪些线段不属于边界线(形状内部的直线),这些形状内部的直线将不可见。这个功能通过使用win API的函数glEdgeFlag()完成。
void glEdgeFlag( GLboolean flag);
Each vertex of a polygon, separate triangle, or separate quadrilateral specified between a glBegin/glEnd pair is marked as the start of either a boundary or nonboundary edge. If the current edge flag is true when the vertex is specified, the vertex is marked as the start of a boundary edge. Otherwise, the vertex is marked as the start of a nonboundary edge. glEdgeFlag sets the edge flag bit to GL_TRUE if flag is GL_TRUE and to GL_FALSE otherwise.
glEdgeFlag (GLboolean flag)表示一个顶点是否应该被认为是多边形的一条边界边的起点。如果当前flag值为true,这个节点就被标记为边界的起点。否则,该节点就被标记为非边界的起点。
flag : Specifies the current edge flag value, either GL_TRUE or GL_FALSE. The initial value is GL_TRUE.
flag : 指定当前边的标记值,为GL_TRUE或GL_FALSE。初始值为GL_TRUE。flag为GL_TRUE后面的点都被认为是边界上的点,flag为GL_FALSE则之后的点不是边界上的点。
(2)实例:
1)用凸边形堆砌凹边形:
#include
#pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
#define false 0
#define true 1
void SetupRC()
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glColor3f(.0f, 0.0f, 1.0f);
}
void RenderScene()
{
glClear(GL_COLOR_BUFFER_BIT);
// OpenGL命令,使用线框模式
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
//总体图形是由6个三角形堆砌而成的凹边形
glBegin(GL_TRIANGLES);
//第一个三角形作为实例讲解:在设为true的顶点都可以作为凹边形边界的起点,所以有两条直线BC,CA。没有AB直线的原因是A不能作为线的起点。
glEdgeFlag(false);
glVertex2f(-20.0f, 0.0f);//A
glEdgeFlag(true);
glVertex2f(20.0f, 0.0f);//B
glVertex2f(0.0f, 40.0f);//C
glVertex2f(-20.0f, 0.0f);
glVertex2f(-60.0f, -20.0f);
glEdgeFlag(false);
glVertex2f(-20.0f, -40.0f);
glEdgeFlag(true);
glVertex2f(-20.0f, -40.0f);
glVertex2f(0.0f, -80.0f);
glEdgeFlag(false);
glVertex2f(20.0f, -40.0f);
glEdgeFlag(true);
glVertex2f(20.0f, -40.0f);
glVertex2f(60.0f, -20.0f);
glEdgeFlag(false);
glVertex2f(20.0f, 0.0f);
//中间的两个三角形的边统统不要
glVertex2f(-20.0f, 0.0f);
glVertex2f(-20.0f, -40.0f);
glVertex2f(20.0f, 0.0f);
glVertex2f(-20.0f, -40.0f);
glVertex2f(20.0f, -40.0f);
glVertex2f(20.0f, 0.0f);
glEdgeFlag(true);//这个函数的功能是恢复画线到初始状态
//结束绘制三角形
glEnd();
glFlush();
}
void ChangeSize(GLsizei w, GLsizei h)
{
GLfloat nRange = 100.0f;
GLfloat aspectRatio;
if (0 == h){
h = 1;
}
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
aspectRatio = (GLfloat)w / (GLfloat)h;
if (w <= h) {
glOrtho(-nRange, nRange, -nRange / aspectRatio, nRange / aspectRatio, -nRange, nRange);
}
else{
glOrtho(-nRange aspectRatio, nRange aspectRatio, -nRange, nRange, -nRange, nRange);
}
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int main(int argc, char argv【】)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(400, 300);
glutCreateWindow("用glEdgeFlag函数和凸边形拼接非凸多边形");
glutDisplayFunc(RenderScene);
glutReshapeFunc(ChangeSize);
SetupRC();
glutMainLoop();
return 0;
}
如果不堆砌的话效果是这样的:(测试时不用注释glEdgeFlag语句,只需将语句#define false 0改为#define false 1)
2)给上述实例增加动画效果,并自定义显示模式:
#include
#include
//用于存取获取屏幕的高宽分辨率
GLint SCREEN_WIDTH = 0;
GLint SCREEN_HEIGHT = 0;
//初始状态程序的窗口大小
GLint windowWidth = 400;
GLint windowHeight = 300;
//用于设置旋转动画
GLfloat xRotAngle = 0.0f;
GLfloat yRotAngle = 0.0f;
#define MODE_SOLID 1
#define MODE_LINE 2
#define MODE_POINTS 3
GLint iMode = MODE_SOLID;//多边形的填充方式
GLboolean bEdgeFlag = GL_TRUE;//控制边的显示与否
//受支持的点大小范围
GLfloat sizes【2】;
//受支持的点大小增量
GLfloat step;
//菜单回调函数
void processMenu(int value){
switch (value){
case 1:
iMode = MODE_SOLID;
break;
case 2:
iMode = MODE_LINE;
break;
case 3:
iMode = MODE_POINTS;
break;
case 4:
bEdgeFlag = GL_TRUE;
break;
case 5:
bEdgeFlag = GL_FALSE;
break;
default:
break;
}
//重新绘制
glutPostRedisplay();
}
//显示回调函数
void renderScreen(void){
GLfloat x, y, z, angle;
int i;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glRotatef(xRotAngle, 1.0f, 0.0f, 0.0f);
glRotatef(yRotAngle, 0.0f, 1.0f, 0.0f);
//设置多边形正面和背面的填充模式
if (MODE_SOLID == iMode)
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
if (MODE_LINE == iMode)
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
if (MODE_POINTS == iMode)
glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
x = 0.0f;
y = 0.0f;
z = 0.0f;
//进行平滑处理
glEnable(GL_POINT_SMOOTH);
glHint(GL_POINT_SMOOTH, GL_NICEST);
glEnable(GL_LINE_SMOOTH);
glHint(GL_LINE_SMOOTH, GL_NICEST);
glEnable(GL_POLYGON_SMOOTH);
glHint(GL_POLYGON_SMOOTH, GL_NICEST);
//绘制坐标系
if (MODE_POINTS != iMode){
glColor3f(1.0f, 1.0f, 1.0f);
glBegin(GL_LINES);
glVertex3f(-80.0f, 0.0f, 0.0f);
glVertex3f(80.0f, 0.0f, 0.0f);
glVertex3f(0.0f, -80.0f, 0.0f);
glVertex3f(0.0f, 80.0f, 0.0f);
glVertex3f(0.0f, 0.0f, -80.0f);
glVertex3f(0.0f, 0.0f, 80.0f);
glEnd();
glColor3f(1.0, 0.0, 0.0);
glPushMatrix();
glTranslatef(80.0f, 0.0f, 0.0f);
glRotatef(90.0f, 0.0f, 1.0f, 0.0f);
glutWireCone(3, 6, 10, 10);
glPopMatrix();
glPushMatrix();
glTranslatef(0.0f, 80.0f, 0.0f);
glRotatef(-90.0f, 1.0f, 0.0f, 0.0f);
glutWireCone(3, 6, 10, 10);
glPopMatrix();
glPushMatrix();
glTranslatef(0.0f, 0.0f, 80.0f);
glRotatef(90.0f, 0.0f, 0.0f, 1.0f);
glutWireCone(3, 6, 10, 10);
glPopMatrix();
glColor3f(1.0f, 1.0f, 1.0f);
}
glColor3f(0.0f, 0.0f, 0.5f);
glBegin(GL_TRIANGLES);
glPointSize(sizes【1】);
glEdgeFlag(bEdgeFlag);
glVertex2f(-20.0f, 20.0f);
glEdgeFlag(GL_TRUE);
glVertex2f(20.0f, 20.0f);
glVertex2f(0.0f, 60.0f);
glVertex2f(-20.0f, 20.0f);
glVertex2f(-60.0f, 0.0f);
glEdgeFlag(bEdgeFlag);
glVertex2f(-20.0f, -20.0f);
glEdgeFlag(GL_TRUE);
glVertex2f(-20.0f, -20.0f);
glVertex2f(0.0f, -60.0f);
glEdgeFlag(bEdgeFlag);
glVertex2f(20.0f, -20.0f);
glEdgeFlag(GL_TRUE);
glVertex2f(20.0f, -20.0f);
glVertex2f(60.0f, 0.0f);
glEdgeFlag(bEdgeFlag);
glVertex2f(20.0f, 20.0f);
glEdgeFlag(GL_TRUE);
glEdgeFlag(bEdgeFlag);
glVertex2f(-20.0f, 20.0f);
glVertex2f(-20.0f, -20.0f);
glVertex2f(20.0f, 20.0f);
glVertex2f(-20.0f, -20.0f);
glVertex2f(20.0f, -20.0f);
glVertex2f(20.0f, 20.0f);
glEdgeFlag(GL_TRUE);
glEnd();
glPopMatrix();
glutSwapBuffers();
}
void setupRC(void){
glClearColor(0.4f, 0.4, 0.4, 1.0f);
glColor3f(0.0f, 1.0f, 0.0f);
//使能深度测试,深度测试开启之后能够透过物体看到其他物体的色彩
glEnable(GL_DEPTH_TEST);
//获取受支持的点大小范围
glGetFloatv(GL_POINT_SIZE_RANGE, sizes);
//获取受支持的点大小增量
glGetFloatv(GL_POINT_SIZE_GRANULARITY, &step);
printf("point size range:%f-%f\n", sizes【0】, sizes【1】);
printf("point step:%f\n", step);
}
void changSize(GLint w, GLint h){
GLfloat ratio;
//设置坐标系范围大小为x(-100.0f,100.0f)、y(-100.0f,100.0f)、z(-100.0f,100.0f)
GLfloat coordinatesize = 100.0f;
if ((w == 0) || (h == 0))
return;//就是使窗体改变操作无效
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
ratio = (GLfloat)w / (GLfloat)h;
if (w[span style="color: rgba(0, 0, 0, 1)">h)
glOrtho(-coordinatesize, coordinatesize, -coordinatesize / ratio, coordinatesize / ratio, -coordinatesize, coordinatesize);
else
glOrtho(-coordinatesizeratio, coordinatesize*ratio, -coordinatesize, coordinatesize, -coordinatesize, coordinatesize);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void specialKey(int key, int x, int y){
if (key == GLUT_KEY_UP){
xRotAngle -= <span style="color: