OpenGL 小案例 - 绘制图形
注:本文旨在记录笔者的学习过程,仅代表笔者个人的理解,如果有表述不准确的地方,欢迎各位指正!因为涉及到的概念来源自网络,所以如有侵权,也望告知!
前言
在理解了OpenGL的基本概念之后,笔者尝试通过一个小案例进一步了解OpenGL绘制图形的过程。如果还有对基本概念不够了解的同学,可以参看笔者的另一篇文章:OpenGL 常⻅的专业名词
正文
概览
首先来看一下main函数实现,这部分的内容主要是初始化窗口、注册回调、设置渲染环境、开启事件循环。
int main(int argc,char *argv[]) { /* `GLTools`函数`glSetWorkingDrectory`用来设置当前工作目录。实际上在Windows中是不必要的,因为工作目录默认就是与程序可执行执行程序相同的目录。但是在Mac OS X中,这个程序将当前工作文件夹改为应用程序捆绑包中的`/Resource`文件夹。`GLUT`的优先设定自动进行了这个中设置,但是这样中方法更加安全。 */gltSetWorkingDirectory(argv[0]);
//初始化GLUT库,这个函数只是传说命令参数并且初始化glut库 glutInit(&argc, argv);
/* 初始化双缓冲窗口,其中标志GLUT_DOUBLE、GLUT_RGBA、GLUT_DEPTH、GLUT_STENCIL分别指 双缓冲窗口、RGBA颜色模式、深度测试、模板缓冲区 --GLUT_DOUBLE`:双缓存窗口,是指绘图命令实际上是离屏缓存区执行的,然后迅速转换成窗口视图,这种方式,经常用来生成动画效果; --GLUT_DEPTH`:标志将一个深度缓存区分配为显示的一部分,因此我们能够执行深度测试; --GLUT_STENCIL`:确保我们也会有一个可用的模板缓存区。 */ glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
//GLUT窗口大小、窗口标题 glutInitWindowSize(600, 600); glutCreateWindow("Triangle"); /* GLUT 内部运行一个本地消息循环,拦截适当的消息。然后调用我们不同时间注册的回调函数。我们一共注册2个回调函数: 1)为窗口改变大小而设置的一个回调函数 2)包含OpenGL 渲染的回调函数 */ //注册重塑函数 glutReshapeFunc(changeSize);
//注册显示函数
glutDisplayFunc(RenderScene); //注册特殊函数
glutSpecialFunc(SpecialKeys);
/* 初始化一个GLEW库,确保OpenGL API对程序完全可用。 在试图做任何渲染之前,要检查确定驱动程序的初始化过程中没有任何问题
*/ GLenum status = glewInit(); if (GLEW_OK != status) { printf("GLEW Error:%sn",glewGetErrorString(status)); return 1; }
//设置我们的渲染环境 setupRC();
glutMainLoop();
return 0;}
设置渲染环境
这个部分主要是初始化一个渲染管理器,采用固定管线渲染。
//定义一个,着色管理器GLShaderManager shaderManager;//简单的批次容器,是GLTools的一个简单的容器类。GLBatch triangleBatch;
//blockSize 边长GLfloat blockSize = 0.1f;
//正方形的4个点坐标GLfloat vVerts[] = { -blockSize,-blockSize,0.0f, blockSize,-blockSize,0.0f, blockSize,blockSize,0.0f, -blockSize,blockSize,0.0f};void setupRC() { //设置清屏颜色(背景颜色) glClearColor(1.0f, 1.0f, 1.0f, 1);
//没有着色器,在OpenGL 核心框架中是无法进行任何渲染的。初始化一个渲染管理器。 shaderManager.InitializeStockShaders();
//修改为GL_TRIANGLE_FAN ,4个顶点 triangleBatch.Begin(GL_TRIANGLE_FAN, 4); triangleBatch.CopyVertexData3f(vVerts); triangleBatch.End();}
事件循环
GLUT 内部运行一个本地消息循环,拦截适当的消息,然后调用我们不同时间注册的回调函数,与iOS中的runloop机制类似。
重塑事件:当窗口大小变化时,同步调整OpenGL的视口大小。
/* 在窗口大小改变时,接收新的宽度&高度。 */void changeSize(int w,int h) { /* x,y 参数代表窗口中视图的左下角坐标,而宽度、高度是像素为表示,通常x,y 都是为0 */ glViewport(0, 0, w, h);}
显示事件:清除缓存区状态,通过固定着色器绘制图形数据,执行缓存区的切换。
void RenderScene(void) {//清除一个或者一组特定的缓存区 /* 缓冲区是一块存在图像信息的储存空间,红色、绿色、蓝色和alpha分量通常一起分量通常一起作为颜色缓存区或像素缓存区引用。 OpenGL 中不止一种缓冲区(颜色缓存区、深度缓存区和模板缓存区) 清除缓存区对数值进行预置 参数:指定将要清除的缓存的 GL_COLOR_BUFFER_BIT :指示当前激活的用来进行颜色写入缓冲区 GL_DEPTH_BUFFER_BIT :指示深度缓存区 GL_STENCIL_BUFFER_BIT:指示模板缓冲区 */ glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); GLfloat vRed[] = {1.0f,0.0f,0.0f,0.0f}; //平移 M3DMatrix44f mTransfromMatrix; m3dTranslationMatrix44(mTransfromMatrix, xPos, yPos, 0.0f); //将矩阵结果 提交给固定着色器(平面着色器)中绘制 shaderManager.UseStockShader(GLT_SHADER_FLAT,mTransfromMatrix,vRed); //提交着色器 triangleBatch.Draw(); //执行交换缓存区 glutSwapBuffers();}
特殊事件:注册键盘响应,可以控制图形进行位移变换,最后触发glutPostRedisplay()进行重绘,类似iOS的setNeedsDisplay。
GLfloat xPos = 0.0f;GLfloat yPos = 0.0f;void SpecialKeys(int key, int x, int y){ GLfloat stepSize = 0.025f; if (key == GLUT_KEY_UP) { yPos += stepSize; } if (key == GLUT_KEY_DOWN) { yPos -= stepSize; } if (key == GLUT_KEY_LEFT) { xPos -= stepSize; } if (key == GLUT_KEY_RIGHT) { xPos += stepSize; } //碰撞检测 if (xPos < (-1.0f + blockSize)) { xPos = -1.0f + blockSize; } if (xPos > (1.0f - blockSize)) { xPos = 1.0f - blockSize; } if (yPos < (-1.0f + blockSize)) { yPos = -1.0f + blockSize; } if (yPos > (1.0f - blockSize)) { yPos = 1.0f - blockSize; } glutPostRedisplay();}
以上是 OpenGL 小案例 - 绘制图形 的全部内容, 来源链接: utcz.com/a/30128.html