老程序员分享:OpenGL学习进程(10)第七课:四边形绘制与动画基础

简介: 老程序员分享:OpenGL学习进程(10)第七课:四边形绘制与动画基础

本节是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:

相关文章
|
5月前
|
存储 缓存 NoSQL
Redis系列学习文章分享---第十三篇(Redis多级缓存--JVM进程缓存+Lua语法)
Redis系列学习文章分享---第十三篇(Redis多级缓存--JVM进程缓存+Lua语法)
82 1
|
5月前
|
网络协议 程序员 开发工具
程序员必知:Xinetd超级守护进程
程序员必知:Xinetd超级守护进程
50 0
|
5月前
|
存储 数据安全/隐私保护 Windows
逆向学习Windows篇:进程句柄操作详解
逆向学习Windows篇:进程句柄操作详解
189 0
|
6月前
|
Java 调度
【JAVA学习之路 | 提高篇】进程与线程(Thread)
【JAVA学习之路 | 提高篇】进程与线程(Thread)
|
6月前
|
消息中间件 Unix Linux
Linux的学习之路:17、进程间通信(1)
Linux的学习之路:17、进程间通信(1)
57 1
|
6月前
|
自然语言处理 Java Linux
【Linux】开始学习进程替换吧!
通过学习进程替换,我们可以体会到多语言混搭的快乐,可以从C语言直接蹦到python ,也可以从c++里运行java代码。是不是很厉害!这是通过调度多个进程的效果,联系我们之前学习的进程,进程控制等概念。我们可以想要运行其他代码可以通过创建子进程来实现,但是这样也肯定是同一种语言,如果想要运行其他语言,那是不是有种方法可以调度一个进程来当做子进程呢??? 我们开始今天的学习吧!
37 0
|
6月前
|
人工智能 Linux Shell
Linux的学习之路:13、进程替代
Linux的学习之路:13、进程替代
47 0
|
6月前
|
存储 Linux 调度
Linux的学习之路:12、地址空间(续)与进程的创建、终止和等待
Linux的学习之路:12、地址空间(续)与进程的创建、终止和等待
37 0
|
6月前
|
XML 小程序 Java
【Android App】三维投影OpenGL ES的讲解及着色器实现(附源码和演示 超详细)
【Android App】三维投影OpenGL ES的讲解及着色器实现(附源码和演示 超详细)
126 0
|
缓存 C++
Opengl ES之FBO
Opengl ES连载系列
151 0