OpenGL绘制图形以及绘制动画(一)

刚开始接触OpenGL,有点小激动,终于绘制出一个图形了,哇

通过绘制,大概明白OpenGL的框架。主要掌握的是这个。

通过代码加注释理解程序,简单粗暴。

<span style="font-size:18px;"><span style="font-size:18px;">#include<windows.h>
#include<gl/glut.h>
#include<gl/gl.h>
#include<gl/glu.h>
//头文件/表示在gl目录下的.h头文件



//函数用于在窗口中绘制需要的图形
//只是一个场景scene 并不会真正绘制到图形中去。
void RenderScene(void)
{
	//用当前清除颜色缓冲区,即设定窗口的背景颜色
	// 清除viewport的缓冲区
	//大概就是清除下面所要画的区域的缓冲区
	glClear(GL_COLOR_BUFFER_BIT);


	//设置当前绘图使用的GGB颜色  red
	glColor3f(1.0f,0.0f,0.0f);

	//使用当前的颜色绘制一个填充的矩形
	//绘制矩形,窗口坐标系是左下角(0,0),x向右,y向上
	//qt使用的是右上角(0,0)
	glRectf(100.0f,150.0f,150.0f,100.0f);

	//强制刷新OpenGL命令队列
	glFlush();
	/*
	简单地说glFlush()就是强制刷新,OpenGL是使用一条渲染管线[3]  线性处理命令的,一般情况下,
	我们提交给OpenGL的指令并不是马上送到驱动程序[4]  里执行的,而是放到一个缓冲区里面,
	等这个缓冲区满了再一次过发到驱动程序里执行;很多时候只有几条指令是填充不满那个缓冲区的,
	就是说这些指令根本没有被发送到驱动里,所以我们要调用glFlush来强制把这些指令送到驱动里进行处理。
	*/
}
//函数ChangeSize是窗口大小改变时调用的登记函数
//GLsizeiGLsizei 是32位整数
void ChangeSize(GLsizei w, GLsizei h)
{
	//窗口的高度y不为0
	//去掉调试之后,还没发现有什么区别
	if (h == 0)  
		h = 1;


	//定义视区并指明尺寸
	//一般是充满整个屏幕
	glViewport(0,0,w,h); 

	/*
        glMatrixMode设置当前矩阵模式:
	GL_MODELVIEW, 对模型视景矩阵堆栈应用随后的矩阵操作.
        GL_PROJECTION, 对投影矩阵应用随后的矩阵操作.
        GL_TEXTURE, 对纹理矩阵堆栈应用随后的矩阵操作.
	与glLoadIdentity()一同使用
	glLoadIdentity():将当前的用户坐标系的原点移到了屏幕中心:类似于一个复位操作
	*/
	//重置坐标系统,使投影变换复位
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();


	//建立修建空间的范围
	//glOrtho是在3D笛卡儿坐标空间定义
	if (w <= h)
		glOrtho(0.0f, 250.0f, 0.0f, 250.0f*h / w, 1.0f, -10.f);
	else
		glOrtho(0.0f, 250.0*w/h, 0.0f, 250.0f, 1.0f, -1.0f);

	//告诉OpenGL将来的所有变换都会影响模型
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}


//函数setupRC用于初始化,常用来设置场景渲染状态
void SetupRC(void)
{

	//这个函数用于设置清除窗口时使用的颜色,即设定窗口内的背景颜色
	//最后一个参数是alpha,主要用于混合的特殊效果,如半透明效果等
	//其实就是使用某种颜色 清空当前的所有颜色,或者说填充整个窗口
	glClearColor(0.0f,1.0f,0.0f,1.0f);
}

//主函数基本都是glut的框架
void main(void )
{
	//初始化GLUT库OpenGL窗口的显示模式
	//glutInitDisplayMode sets the initial display mode
	//创建窗口时使用单缓冲区GLUT_SINGLE并使用RGB颜色模式
	//一般双模式GLUT_DOUBLE是用于动画效果的场合
	//这是两个默认的参数
	glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);


	//创建一个名为GLRect的窗口
	glutCreateWindow("GLRect");


	//callback 
	//glutDisplayFunc sets the display callback for the current window
	//设置当前窗口的显示回调函数和窗口再整形回调函数
	
	//这样当要绘制窗口,就会调用自定义RenderScene函数  比如添加一个图形
	glutDisplayFunc(RenderScene); 

	//这样改变窗口,就会调用ChangeSize函数    比如放大或者缩小窗口
	// glutReshapeFunc(void (*func)(int width, int height));
	//The width and height parameters of the callback specify the new window size in pixels
	//回调函数会指定对应窗口的大小,然后通过参数传递给width,height.  大概是这个意思吧。
	//除了窗口大小改变会调用回调函数之外,当第一次创建窗口的时候,回调函数也会被调用。
	glutReshapeFunc(ChangeSize);
        
        //可以通过调式加深对这两个回调函数的理解。

    //SetupRC并不是GLUT的框架,是自定义的函数, 其作用是进行OpenGL初始化
	//OpenGL的初始化必须在渲染之前执行
	SetupRC();


	//启动主程序GLUT事件处理循环
	//该函数让GLUT框架开始运行,所有设置的回调函数开始工作,
	//直到用户终止程序为止
	//也就是说,SetupRC是在渲染之前执行的。
	glutMainLoop();
}</span></span>





个人理解。

修建区是绘制在视觉区上,视觉区绘制在窗口上。

类似qt图形项item绘制在场景scene, scene绘制在视觉区(view) 最后view在绘制在窗口上。


总结一下,一个OpenGL程序的基本结构主要包括以下几个部分。

(1)定义窗口:包括制定窗口的大小、位置、显示模式以及设置各种回调函数。

(2)初始化设置:清除各种缓冲区,并设置各种OpenGL状态,

           例如设置背景色,打开光照,设置文理等等

(3)绘制场景:利用OpenGL函数绘制场景中的各种物体。

(4)变换:指定场景中需要显示的范围并指定由修建区到视区的变换。

(5)结束运行:清除命令缓冲区,执行OpenGL命令。

<span style="font-size:18px;">#include<windows.h>
#include<gl/glut.h>
#include<gl/gl.h>
#include<gl/glu.h>
#include<stdio.h>

/*
   这个程序在上面那个基础上增加了
   定时器:glutTimerFunc(unsigned int millis, void (*func)(int value), int value);
   重绘标志:glutPosRedisplay();

   定时器第一个参数是每隔millis毫秒便调用func函数,并且创一个value参数进去
   因为一个定时器只被调用一次,所以需要多次调用定时器

   完美结束
*/
//参数指定正方形的位置和大小
GLfloat x1 = 100.0f;
GLfloat y1 = 150.0f;
GLsizei rsize = 50; //int

//正方形运动变化的步长
GLfloat xstep = 1.0f;
GLfloat ystep = -10.0f;

//窗口的大小
GLfloat windowWidth;
GLfloat windowHeight;

void RenderScene(void)
{
	glClear(GL_COLOR_BUFFER_BIT);
	glColor3f(1.0f,0.0f,0.0f);

	glRectf(x1, y1, x1 + rsize, y1 + rsize);

	//清空命令缓冲区并交换帧缓存
	glutSwapBuffers();

}

void ChangeSize(GLsizei w, GLsizei h)
{
	if (h == 0)
		h = 1;


	glViewport(0,0,w,h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	printf("%d  %d\n", w, h);
	if (w <= h)
	{
		windowWidth = 250.0f;
		windowHeight = 250.0f*h / w;	
	}
	else
	{
		windowWidth = 250.0f*h / w;
		windowHeight = 250.0f;
	}
	glOrtho(0.0f,windowWidth,0.0f,windowHeight,1.0f,-1.0f);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

void TimerFunction(int value)
{
	//处理到达窗口边界的正方形,使之反弹
	if (x1 > windowWidth  - rsize || x1 < 0) xstep = -xstep;
	if (y1 > windowHeight - rsize || y1 < 0) ystep = -ystep;

	if (x1 > windowWidth - rsize)   x1 = windowWidth - rsize - 1;
	if (y1 > windowHeight - rsize)  y1 = windowHeight - rsize-1;

	x1 += xstep;
	y1 += ystep;

	/*
	glutPostRedisplay 标记当前窗口需要重新绘制。通过glutMainLoop下一次循环时,
	窗口显示将被回调以重新显示窗口的正常面板。多次调用glutPostRedisplay,
	在下一个显示回调只产生单一的重新显示回调
	*/
	glutPostRedisplay(); //标志重新绘制
	glutTimerFunc(50,TimerFunction,1);
	

}

void SetupRC(void)
{
	//设置窗口清除色为蓝色
	glClearColor(0.0f,0.0f,1.0f,1.0f);
}

void  main(void)
{
	//使用双缓存技术
	glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
	glutCreateWindow("Bounce");

	glutDisplayFunc(RenderScene);
	glutReshapeFunc(ChangeSize);

	//定时器  每33毫秒触发一次
	glutTimerFunc(50,TimerFunction,1);
	

	SetupRC();
	glutMainLoop();
}</span>




版权声明:本文为qq_33850438原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。