计算机图形与OpenGL学习二(输出图元6:OpenGL的显示表)

OpenGL显示表

【注】以下的显示列表概论为转载

1、显示列表概论

  16.1.1 显示列表的优势

  OpenGL显示列表的设计能优化程序运行性能,尤其是网络性能。它被设计成命令高速缓存,而不是动态数据库缓存。也就是说,一旦建立了显示列表,就不能修改它。因为若显示列表可以被修改,则显示列表的搜索、内存管理的执行等开销会降低性能。
  采用显示列表方式绘图一般要比瞬时方式快,尤其是显示列表方式可以大量地提高网络性能,即当通过网络发出绘图命令时,由于显示列表驻留在服务器中,因而使网络的负担减轻到最小。另外,在单用户的机器上,显示列表同样可以提高效率。因为一旦显示列表被处理成适合于图形硬件的格式,则不同的OpenGL实现对命令的优化程度也不同。例如旋转矩阵函数glRotate*(),若将它置于显示列表中,则可大大提高性能。因为旋转矩阵的计算并不简单,包含有平方、三角函数等复杂运算,而在显示列表中,它只被存储为最终的旋转矩阵,于是执行起来如同硬件执行函数glMultMatrix()一样快。一般来说,显示列表能将许多相邻的矩阵变换结合成单个的矩阵乘法,从而加快速度。

  16.1.2 显示列表的适用场合
  并不是只要调用显示列表就能优化程序性能。因为调用显示列表本身时程序也有一些开销,若一个显示列表太小,这个开销将超过显示列表的优越性。下面给出显示列表能最大优化的场合:

·       矩阵操作
大部分矩阵操作需要OpenGL计算逆矩阵,矩阵及其逆矩阵都可以保存在显示列表中。

·       光栅位图和图像
程序定义的光栅数据不一定是适合硬件处理的理想格式。当编译组织一个显示列表时,OpenGL可能把数据转换成硬件能够接受的数据,这可以有效地提高画位图的速度。

·       光、材质和光照模型
当用一个比较复杂的光照环境绘制场景时,可以为场景中的每个物体改变材质。但是材质计算较多,因此设置材质可能比较慢。若把材质定义放在显示列表中,则每次改换材质时就不必重新计算了。因为计算结果存储在表中,因此能更快地绘制光照场景。

·       纹理
因为硬件的纹理格式可能与OpenGL格式不一致,若把纹理定义放在显示列表中,则在编译显示列表时就能对格式进行转换,而不是在执行中进行,这样就能大大提高效率。

·     多边形的图案填充模式
即可将定义的图案放在显示列表中。

-------------------------------------------这里开始为原创-----------------------------------------------------------------------

【创建和命名显示表】

使用glNewList(listID,listMode);

扫描二维码关注公众号,回复: 1631399 查看本文章

         .

         .

     gkEndList();

来创建显示表,类似于glBegin(),glEnd()。

listID:一个唯一的正整数,作为表的标识。为避免重用标识造成冲突,可使用glGenLists(num)产生num连续个未使用的标识,并从中选取一个,如果系统不能产生所要数量的连续标识,返回0。

listMode:符号常量GL_COMPILE(以后执行,储存该表)或GL_COMPILE_AND_EXECUTE(立即执行,并存储)之一。

【执行OpenGL显示表】

使用glCallList(listID)可执行一个显示表。

【实例】

  实例描述:在xy平面建立以(200,200)为中心坐标、半径为150的圆周上六个等距顶点描述的规则所产生的六边形的显示表。

分析:

①要产生的是在圆周上的六边形,因此需要确定六边形的六个顶点位置。

②使用极坐标来确定顶点位置

具体程序实现我们留在之后结合重定型函数一起完成

【删除OpenGL显示表】

删除连续的一组显示表,调用函数

glDeleteLists(startId,nLists);

startId:给出最前面的显示表标识

nLists:要删除的显示表总数

【OpenGL显示窗口重定形函数】

生成图形显示后,我们经常用鼠标将显示窗口进行拖动或者改变显示窗口大小,这可能会引起对象形状的改变。所以我们需要使用窗口重定形函数,以适应窗口尺寸改变。

其函数为:

glutReshapeFunc(winReshapeFcn);

winReshapeFcn是接受新窗口宽度和过程的过程名(实际上是一个函数引用)


【实例完整程序】

#include<GL/glut.h>
#include<math.h>
#include<Windows.h>
#include<iostream>
#include<stdlib.h>
using namespace std;
const double TWO_PI = 6.2831;
GLsizei winWidth = 400, winHeight = 400;
GLuint regHex;//显示表标识
class screenPt
{
private:
	GLint x, y;
public:
	screenPt()
	{
		x = y = 0;
	}
	void setCords(GLint x, GLint y)
	{
		this->x=x;
		this->y = y;
	}
	GLint getX() const
	{
		return x;
	}
	GLint getY() const
	{
		return y;
	}

};
static void init(void)
{
	//初始化函数,并加入表
	screenPt hexVertex, circCtr;//hexVertex顶点对象,circCtr圆心顶点对象
	circCtr.setCords(winWidth / 2, winHeight / 2);
	GLint k;
	GLdouble theta;
	GLint x, y;
	glClearColor(1.0, 1.0, 1.0, 0.0);//设置为白色背景
	regHex = glGenLists(1);//获得一个标识
	glNewList(regHex, GL_COMPILE);
	glColor3f(1.0, 0.0, 0.0);//红色填充
	glBegin(GL_POLYGON);
	for (k = 0; k < 6; ++k)
	{

		theta = TWO_PI*(k / 6.0);
		hexVertex.setCords(circCtr.getX() + 150 * cos(theta), circCtr.getY() + 150 * sin(theta));
		cout << "第" << k << "个点的坐标为(" << hexVertex.getX() << "," << hexVertex.getY() << ")" << endl;
		glVertex2i(hexVertex.getX(), hexVertex.getY());
	}
	glEnd();
	glEndList();
}

void regHexagon(void)
{
	//六边形函数
	glClear(GL_COLOR_BUFFER_BIT);
	glCallList(regHex);//显示表
	glFlush();
}

void winReshapeFcn(int newWidth, int newHeight)
{
	//窗口重定形函数
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();//将当前的用户坐标系的原点移到了屏幕中心:类似于一个复位操作
	gluOrtho2D(0.0, (GLdouble)newWidth, 0.0, (GLdouble)newWidth);
	glClear(GL_COLOR_BUFFER_BIT);


} int main(int argc, char**argv)
{
	glutInit(&argc, argv);
	winWidth = 400;
	winHeight = 400;
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(winWidth, winHeight);
	glutCreateWindow("Example");
	init();
	glutDisplayFunc(regHexagon);
	glutReshapeFunc(winReshapeFcn);
	glutMainLoop();
	return 0;
}

当然也可以不用类与对象来表示顶点,代码可以改成这样,比较简便,效果一致

for (k = 0; k < 6; ++k)
	{

		theta = TWO_PI*(k / 6.0);
		x = 200 + 150 * cos(theta);
		y= 200 + 150 * sin(theta);
		glVertex2i(x, y);
	}

猜你喜欢

转载自blog.csdn.net/lhs322/article/details/79759091