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

回到顶部