案例练习:在窗口绘制一个三角形
进行次案例练习之前,请确保已经搭建好 OpenGL环境 !
并导入头文件
// 着色器管理类
#include "GLShaderManager.h"
// 工具类
#include "GLTools.h"
#include <GLUT/GLUT.h>
首先熟悉相关函数
main 函数
int main(int argc,char* argv[])
{
gltSetWorkingDirectory(argv[0]);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
glutInitWindowSize(800,600); //glut窗口大小
glutCreateWindow("三角形"); //glut窗口标题
glutReshapeFunc(ChangeSize); //注册重塑函数
glutDisplayFunc(RenderScene);//注册显示函数
/**
初始化一个GLEW库,确保OpenGL API对程序完全可用。
在试图做任何渲染之前,要检查确定驱动程序的初始化过程中没有任何问题
*/
GLenum err = glewInit();
if(GLEW_OK != err) {
fprintf(stderr,"glew error:%s\n",glewGetErrorString(err));
return 1;
}
SetupRC(); //设置渲染环境(准备工作)
glutMainLoop(); // 类似于iOS Runloop 运行循环
return 0;
}
main函数是程序的入口函数
-
gltSetWorkingDirectory(argv[0]);
设置当前工作目录(针对Mac OS X) -
glutInit(&argc, argv);
初始化glut库 -
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
初始化显示模型。其中
--
GLUT_DOUBLE
:双缓存窗口,是指绘图命令实际上是离屏缓存区执行的,然后迅速转换成窗口视图,这种方式,经常用来生成动画效果;
--GLUT_DEPTH
:深度测试,标志将一个深度缓存区分配为显示的一部分,因此我们能够执行深度测试;
--GLUT_STENCIL
:模板缓冲区,确保我们也会有一个可用的模板缓存区。
-
glutReshapeFunc
和glutDisplayFunc
GLUT 内部运行一个本地消息循环,拦截适当的消息。然后调用我们不同时间注册的回调函数。 我们一共注册2个回调函数: 1)为窗口改变大小而设置的一个回调函数 2)包含OpenGL 渲染的回调函数
-
SetupRC();
设置渲染环境(做准备工作) -
glutMainLoop();
类似于iOS Runloop 运行循环
main函数主要流程大致如下:
初始化glut库(glutInit
) ——>初始化窗口(glutInitDisplayMode
)——>设置窗口大小和标题(glutInitWindowSize
glutCreateWindow
)——>注册自定义函数(glutReshapeFunc
glutDisplayFunc
)——>初始化glew库——>设置渲染环境(SetupRC
)——>开启glut运行循环(glutMainLoop
)
至此main函数内部的具体实现完毕,其中我们注册了2组回调函数。
ChangeSize函数
// 重塑函数
void ChangeSize(int w,int h)
{
/**
x,y 参数代表窗口中视图的左下角坐标,w,h 宽高(像素)。通常x,y 都是为0
*/
glViewport(0,0, w, h);
}
该函数是我们自定义的函数。是在main函数中,通过glutReshapeFunc(ChangeSize);
注册的重塑函数。当触发条件达成时自动调用此函数
该函数触发的条件是:
1.初次创建窗口的时候
2.窗口尺寸发生调整的时候
RenderScene函数
void RenderScene(void)
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
GLfloat vRed[] = {1.0f,0.0f,0.0f,1.0f}; //设置一组浮点数来表示红色
shaderManager.UseStockShader(GLT_SHADER_IDENTITY,vRed);
triangleBatch.Draw();//提交着色器
glutSwapBuffers(); // 将后台缓冲区进行渲染,然后结束后交换给前台
}
该函数也是我们自定义的函数。是在main函数中,通过glutDisplayFunc(RenderScene);
注册的显示函数。
该函数的触发条件
1.系统自动触发
2.开发者手动调用函数触发(glutPostRedisplay()
)
该函数处理的业务一般为
1.清理缓存区(颜色、深度、模板)
2.使用存储着色器
3.绘制图形
-
glClear
清楚一个或一组特定的缓存区。缓冲区是一块存在图像信息的储存空间,红色、绿色、蓝色和alpha分量通常一起作为颜色缓存区或像素缓存区引用。
OpenGL 中不止一种缓冲区(颜色缓存区、深度缓存区和模板缓存区)
清除缓存区的目的是对数值进行预置。GL_COLOR_BUFFER_BIT :指示颜色缓冲区 GL_DEPTH_BUFFER_BIT :指示深度缓存区 GL_STENCIL_BUFFER_BIT:指示模板缓冲区
-
shaderManager.UseStockShader(GLT_SHADER_IDENTITY,vRed);
使用单元着色器进行绘制,画笔颜色为vRed。 -
triangleBatch.Draw();
批次类绘制 -
glutSwapBuffers();
交换缓冲区 。 在开始的设置openGL窗口的时候,我们指定要一个双缓冲区的渲染环境。这就意味着将在后台缓冲区进行渲染,渲染结束后交换给前台。这种方式可以防止观察者看到可能伴随着动画帧与动画帧之间的闪烁的渲染过程。缓冲区交换平台将以平台特定的方式进行。
还有一组函数是我们最初在main函数中主动调用的
SetupRC()函数
void SetupRC()
{
glClearColor(0.0f,1.0f,0.0f,1.0f); //设置屏幕颜色(背景颜色)
//初始化一个渲染管理器。没有着色器,在OpenGL 核心框架中是无法进行任何渲染的。
shaderManager.InitializeStockShaders();
GLfloat vVerts[] = {
-0.4f,-0.2f,0.0f,
0.4f,-0.2f,0.0f,
0.0f,0.5f,0.0f,
};
//批次类处理
triangleBatch.Begin(GL_TRIANGLES,3); // 指定图元装配类型以及顶点个数
triangleBatch.CopyVertexData3f(vVerts); //拷贝顶点数据
triangleBatch.End();
}
该函数主要为我们的渲染做一些准备工作,如
- 设置窗口背景颜色
- 初始化存储着色器shaderManager。
没有着色器,在OpenGL 核心框架中是无法进行任何渲染的。- 设置图形顶点数据
此案例为渲染三角形,其中数组vVert包含所有三角形3个顶点的(x,y,z)笛卡尔坐标对。- 利用GLBatch 批次类,将数据传递到着色器
绘制三角形的整体流程大致如下:
![](https://img.haomeiwen.com/i2598443/82d3aab94341b0db.png)
至此,我们的三角形案例就做好了,我们运行来看一下结果
![](https://img.haomeiwen.com/i2598443/4294c3715d3bcd2f.png)
网友评论