通过OpenGL使⽤固定存储着色器,绘制最基本的图形三⻆形
效果如下:
案例分析
OpenGL工程环境搭建,参见OpenGL 环境搭建。
- 工具类引入
- 着色器管理类
#include<GLShaderManager.h>
通过管理着色器,在OpenGL(核心框架)进行着色。
1.创建并管理着色器
2.提供一组“存储着色器”
3.进行基本的渲染操作
- GLTools函数
#include<GLTools.h>
GLTool.h头文件包含了大部分GLTool中类似C语言的独立函数
- freeglut静态库
在Mac 系统下,
#include<glut/glut.h>
在Windows 和 Linux上,使用freeglut的静态库版本并且需要添加一个宏
- 定义全局变量
- 着色管理器
//定义一个着色管理器
GLShaderManager shaderManager;
- 批次容器
//三角形批次容器,是GLTools的一个简单的容器类。
GLBatch triangleBatch;
- 自定义函数
- 设置OpenGL 视口
void changeSize(int w,int h)
用于改变窗口大小,需要在main
中通过glutReshaperFunc(函数名)
注册为重塑函数。
当新建窗口及窗口尺寸发生调整时自动触发。
/*
在窗口大小改变时,接收新的宽度&高度。
*/
void changeSize(int w,int h)
{
/*
x,y 参数代表窗口中视图的左下角坐标,而宽度、高度是像素为表示,通常x,y 都是为0
*/
glViewport(0, 0, w, h);
}
- 配置图形顶点数据
void setupRC()
1.设置窗口背景颜色
2.初始化存储着色器
3.设置图形顶点数据
4.将数据传递给着色器
void setupRC()
{
//1. 设置窗口背景颜色, 存在于帧缓存区中的颜色缓存区
glClearColor(0.38f, 0.40f, 0.70f, 1);
//2. 初始化存储着色器
//此处采用固定管线渲染,也可以尝试用OpenGLSL编写着色器
//没有着色器,在OpenGL 核心框架中是无法进行任何渲染的。
shaderManager.InitializeStockShaders();
//3. 设置图形顶点数据, 每个顶点有三个坐标:xyz
//在OpenGL中,三角形是一种基本的3D图元绘图原素。
GLfloat vVerts[] = {
-0.5f,0.0f,0.0f,
0.5f,0.0f,0.0f,
0.0f,0.5f,0.0f
};
//4. 利用GLBatch批次类,将数据传递到着色器
triangleBatch.Begin(GL_TRIANGLES, 3);
triangleBatch.CopyVertexData3f(vVerts);
triangleBatch.End();
}
- 绘制图形
void RenderScene(void)
需要在main
中通过glutDisplayFunc(函数名)
注册为显示函数。
1.清除特定缓存区
2.指定图形绘制的画笔颜色
3.颜色传递到存储着色器
4.提交着色器,进行绘制
5.将后台缓冲区进行渲染,然后结束后交换给前台
void RenderScene(void)
{
//1.清除一个或者一组特定的缓存区
/*
缓冲区是一块存在图像信息的储存空间,红色、绿色、蓝色和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);
//2.设置一组浮点数来表示图形绘制的画笔颜色(RGBA)
GLfloat vRed[] = {1.0,0.5,0.2,0.8f};
//3.传递到存储着色器,即GLT_SHADER_IDENTITY着色器,这个着色器只是使用指定颜色以默认笛卡尔坐标第在屏幕上渲染几何图形
shaderManager.UseStockShader(GLT_SHADER_IDENTITY,vRed);
//4.提交着色器,进行绘制
triangleBatch.Draw();
//在开始的设置openGL 窗口的时候,我们指定要一个双缓冲区的渲染环境。这就意味着将在后台缓冲区进行渲染,渲染结束后交换给前台。这种方式可以防止观察者看到可能伴随着动画帧与动画帧之间的闪烁的渲染过程。缓冲区交换平台将以平台特定的方式进行。
//5. 将后台缓冲区进行渲染,然后结束后交换给前台
glutSwapBuffers();
}
- main函数
int main(int argc,char *argv[])
程序入口函数
在main中做绘制前的准备工作:
1.初始化GLUT库
2.初始化双缓冲窗口
3.设置窗口大小及标题
4.注册回调函数
5.检查驱动程序初始化是否正常
6.设置渲染环境
7.运行本地消息循环
int main(int argc,char *argv[])
{
//1. 初始化GLUT库,这个函数只是传说命令参数并且初始化glut库
glutInit(&argc, argv);
/*
2. 初始化双缓冲窗口,其中标志GLUT_DOUBLE、GLUT_RGBA、GLUT_DEPTH、GLUT_STENCIL分别指
双缓冲窗口、RGBA颜色模式、深度测试、模板缓冲区
--GLUT_DOUBLE`:双缓存窗口,是指绘图命令实际上是离屏缓存区执行的,然后迅速转换成窗口视图,这种方式,经常用来生成动画效果;
--GLUT_DEPTH`:标志将一个深度缓存区分配为显示的一部分,因此我们能够执行深度测试;
--GLUT_STENCIL`:确保我们也会有一个可用的模板缓存区。
*/
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
//3. GLUT窗口大小、窗口标题
glutInitWindowSize(800, 600);
glutCreateWindow("三角形");
/*
GLUT 内部运行一个本地消息循环,拦截适当的消息。然后调用我们不同时间注册的回调函数。我们一共注册2个回调函数:
1)为窗口改变大小而设置的一个回调函数
2)包含OpenGL 渲染的回调函数
*/
//4.1 注册重塑函数
glutReshapeFunc(changeSize);
//4.2 注册显示函数
glutDisplayFunc(RenderScene);
/*
初始化一个GLEW库,确保OpenGL API对程序完全可用。
5. 在试图做任何渲染之前,要检查确定驱动程序的初始化过程中没有任何问题
*/
GLenum status = glewInit();
if (GLEW_OK != status) {
printf("GLEW Error:%s\n",glewGetErrorString(status));
return 1;
}
//6. 设置渲染环境
setupRC();
//7. 开启运行循环
glutMainLoop();
return 0;
}