前言:前一部分了解了OpenGL环境搭建和基本API之后,我们先来做一个小小的练习,使用固定管线来绘制一个可移动的三角形,同时详细解释一下一些常用方法的含义
一、搭建OpenGL在Mac下的环境
搭建Xcode环境,这里不再做过多赘述了
传送门:https://www.jianshu.com/p/05555148d567
二、实战开始
(注:完整代码在文章的最后面)
1、首先来到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);
glutCreateWindow("Triangle");
glutReshapeFunc(ChangeSize);
glutDisplayFunc(RenderScene);
glutSpecialFunc(SpecialKeys);
GLenum err = glewInit();
if(GLEW_OK != err) {
fprintf(stderr,"glew error:%s\n",glewGetErrorString(err));
return 1;
}
SetupRC();
glutMainLoop();
return 0;
}
下面来一一分析对应函数和方法的意思,
gltSetWorkingDirectory(argv[0]) : 是”GLTools“用来设置当前工作目录的函数,实际上在windows中是不必要的,因为工作目录默认就是与程序的可执行程序的目录相同。但是在Mac OSX环境中,这个程序将当前工作文件夹改为应用程序捆绑包中的"/Resource"文件夹.'GLUT'的优先设定会自动设定为这个,这样写也是为了更加安全。
glutInit(&argc, argv): 初始化GLUT库,这个函数只是传入命令参数并且初始化glut库
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL): 设置显示模式。其中GLUT_DOUBLE 指的是初始化双缓冲窗口显示模式,GLUT_RGBA RGBA颜色显示模式,GLUT_DEPTH 初始化深度测试显示模式,可以用于开启深度测试,GLUT_STENCIL 初始化模板缓冲区
glutInitWindowSize(800,600) 初始化一个GLUT窗口并设置窗口大小
glutCreateWindow("Triangle") 设置窗口的标题
glutReshapeFunc(ChangeSize) 注册绑定重塑函数,当窗口第一次创建或者窗口大小发生变化,需要界面重绘时,系统会自动调用这个已经注册过的自定义函数ChangeSize
glutDisplayFunc(RenderScene) 注册绑定显示函数,当屏幕发生渲染或者你使用代码强制渲染,需要界面重绘的时候,系统会自动调用这个已经注册绑定过的自定义函数RenderSize
glutSpecialFunc(SpecialKeys); 当你使用特殊键位的时候比如键盘的上下左右键的时候,就会走到这个方法里,在这个函数中做特殊键位区分的时候,这些特殊键位都有对应的枚举值比如上(GLUT_KEY_UP) 下(GLUT_KEY_DOWN)左(GLUT_KEY_LEFT)右(GLUT_KEY_RIGHT),我找了一些,这个简单了解一下就行了
#define GLUT_KEY_F1 1
#define GLUT_KEY_F2 2
#define GLUT_KEY_F3 3
#define GLUT_KEY_F4 4
#define GLUT_KEY_F5 5
#define GLUT_KEY_F6 6
#define GLUT_KEY_F7 7
#define GLUT_KEY_F8 8
#define GLUT_KEY_F9 9
#define GLUT_KEY_F10 10
#define GLUT_KEY_F11 11
#define GLUT_KEY_F12 12
/* directional keys */
#define GLUT_KEY_LEFT 100
#define GLUT_KEY_UP 101
#define GLUT_KEY_RIGHT 102
#define GLUT_KEY_DOWN 103
#define GLUT_KEY_PAGE_UP 104
#define GLUT_KEY_PAGE_DOWN 105
#define GLUT_KEY_HOME 106
#define GLUT_KEY_END 107
#define GLUT_KEY_INSERT 108
GLenum err = glewInit(); 初始化一个GLEW库,确保OpenGL API对程序完全可用,在试图做任何渲染之前,要检查确定驱动程序的初始化过程中没有任何问题
SetupRC() 自定方法,设置我们的渲染环境
glutMainLoop() 运行循环,类似OC的Runloop,函数在调用之后,在主窗口被关闭之前都不会返回,一个应用程序只需要调用一次,这个函数负责处理我们所有的消息,直到我们关闭程序为止。
2、接着引入固定管线着色器和OpenGL一些基本库文件
#include "GLShaderManager.h"
#include "GLTools.h"
#include <glut/glut.h>
GLShaderManager.h 这个移入了GLTool着色器管理器类shader manager,没有着色器,我们就不能再OpenGL核心框架进行着色,着色器管理器不仅允许我们创建并管理着色器,还提供了一组”存储着色器“,他们能够进行一些基本的渲染操作。
GLTools.h GLTool.h头文件包含了大部分GLTool中类似C语言的独立函数
GLUT/GLUT.h 在Mac 系统下,需要#include <glut/glut.h> ; 在windows和Linux上,我们使用freeglut的静态库版本并需要添加一个宏
3、重塑函数的实现,在窗口大小改变的时候,接受新的宽度和高度
void changeSize(int w,int h)
{
glViewport(0, 0, w, h);
}
glViewPort这个函数就是设置视口,x,y 参数代表窗口中视图的左下角坐标,而宽度、高度是像素为表示,通常x,y 都是为0,调用glViewPort会调用重新渲染RenderScene
4、接着定义一个着色器管理变量和一个批次类,GLBatch是GLTools的一个简单的容器类
GLBatch triangleBatch;
GLShaderManager shaderManager;
5、接下来,我们需要设置渲染环境和顶点数据
void SetupRC()
{
glClearColor(0.0f,0.0f,1.0f,1.0f);
shaderManager.InitializeStockShaders();
GLfloat vVerts[] = {
-0.5f,0.0f,0.0f,
0.5f,0.0f,0.0f,
0.0f,1.0f,0.0f,
};
triangleBatch.Begin(GL_TRIANGLES,3);
triangleBatch.CopyVertexData3f(vVerts);
triangleBatch.End();
}
glClearColor 设置清屏颜色,设置到颜色缓冲区里面,是一个状态基,可以理解为窗口的背景色
shaderManager.InitializeStockShaders() 初始化一个着色器管理器
GLfloat vVerts[] = {
-0.5f,0.0f,0.0f,
0.5f,0.0f,0.0f,
0.0f,1.0f,0.0f,
};
定义一个一维数组,里面存储三角形的三个顶点的坐标,每个顶点有三个数(x,y,z)
其中
triangleBatch.Begin(GL_TRIANGLES,3); 第一个参数GL_TRIANGLES指的是选择三角形的连接方式,第二个参数3代表3个顶点
triangleBatch.CopyVertexData3f(vVerts);把顶点数据copy进去,然后triangleBatch.End();表示设置完成
这里拓展一下便于理解,如果是画四边形SetUpRC中的顶点坐标需要修改成
如果是要绘制四边形,需要修改顶点数组,然后修改连接方式如下
void SetupRC()
{
glClearColor(0.0f,0.0f,1.0f,1.0f);
shaderManager.InitializeStockShaders();
GLfloat vVerts[] = {
-0.5f,-0.5f,0.0f,
-0.5f,0.5f,0.0f,
0.5f,0.5f,0.0f,
0.5f,-0.5f,0.0f,
};
triangleBatch.Begin(GL_TRIANGLE_FAN,4);
triangleBatch.CopyVertexData3f(vVerts);
triangleBatch.End();
}
对比一下,顶点数组变了,然后连接方式由GL_TRIANGLES变为GL_TRIANGLE_FAN,顶点个数由3个变为4个
顶点数组的变化很明显,就不细说了
连接方式和顶点个数变了
//三角形的
triangleBatch.Begin(GL_TRIANGLES,3);
//四边形的
triangleBatch.Begin(GL_TRIANGLE_FAN,4);
这里再拓展一下,OpenGL图元只有点、线、三角形,现在画点,线以及多边形都没问题了,圆形就需要通过这三个做处理一下了
6、接下来我们需要设置渲染
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();
}
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT) 每次渲染前需要清除特定缓冲区比如深度缓冲区,颜色缓冲区
shaderManager.UseStockShader(GLT_SHADER_IDENTITY,vRed) 不同的着色器,参数都是不一样的,但是函数名都是这个,绘制简单的三角形,用单元着色器就行了,所以选GLT_SHADER_IDENTITY,并设置绘制颜色
triangleBatch.Draw() 开始颜色渲染
glutSwapBuffers() 交换缓冲区,把渲染的内容提交上去
执行一下,就能看到蓝色背景的windows下,有一个红色的三角形

7、开始设置移动,设置移动之前需要把顶点坐标设置为全局变量,这样好处理,把下面顶点数组放到全局
GLfloat vVerts[] = {
-0.5f,0.0f,0.0f,
0.5f,0.0f,0.0f,
0.0f,1.0f,0.0f,
};
把这段坐标换成下面这段,然后把边长减小点,便于查看效果
//blockSize 边长
GLfloat blockSize = 0.1f;
//三角形的3个点坐标
GLfloat vVerts[] = {
-blockSize,0.0f,0.0f,
blockSize,0.0f,0.0f,
0.0f,blockSize,0.0f,
};
然后开始实现SpecialKeys函数,这里拓展一下,顶点较少可以使用更新顶点坐标这种移动方式,顶点较多的复杂图形,可以使用矩阵进行移动
void SpecialKeys (int key , int x, int y){
GLfloat stepSize = 0.1f;
GLfloat blockX = vVerts[0];
GLfloat blockY = vVerts[1];
if (key == GLUT_KEY_UP) blockY += stepSize;
if (key == GLUT_KEY_DOWN) blockY -= stepSize;
if (key == GLUT_KEY_LEFT) blockX -= stepSize;
if (key == GLUT_KEY_RIGHT) blockX += stepSize;
//更新点的坐标 ABC
vVerts[0] = blockX;
vVerts[1] = blockY;
vVerts[3] = blockX + 2 * stepSize;
vVerts[4] = blockY;
vVerts[6] = blockX + stepSize;
vVerts[7] = blockY + stepSize;
triangleBatch.CopyVertexData3f(vVerts);
glutPostRedisplay();
}
其中设置blockX和blockY只是找了第一个点作为移动坐标参照物,然后相对第一个点的坐标换算出剩余两个点的坐标,比如A(-0.1,0,0) B(0.1,0,0),换算成A(blockX,0,0)那此时的B就是(block + 2 * 0.1,0, 0), vVerts[0]这里面的下标0,代表一维数组中的第一个点的x坐标,只上下左右移动,只需要改三个点对应的x,y坐标就行了, 三个点想x和y的坐标对应的下标分别是0,1和3,4和6,7,这样思路就很清楚了。
triangleBatch.CopyVertexData3f(vVerts); 这个将顶点数组通过GLBatch帮助类,将顶点数据传输到存储着色器中
glutPostRedisplay()这个是手动触发渲染函数。
然后直接运行,就能够得到一个可以用键盘控制上下左右移动的三角形。
完整代码如下
//
// main.cpp
//
// Created by battleMage on 2019/8/11.
// Copyright © 2019 battleMage. All rights reserved.
//
#include "GLShaderManager.h"
#include "GLTools.h"
#include <glut/glut.h>
GLBatch triangleBatch;
GLShaderManager shaderManager;
//blockSize 边长
GLfloat blockSize = 0.1f;
//三角形的3个点坐标
GLfloat vVerts[] = {
-blockSize,0.0f,0.0f,
blockSize,0.0f,0.0f,
0.0f, blockSize,0.0f,
};
void ChangeSize(int w,int h){
glViewport(0,0, w, h);
}
void SpecialKeys (int key , int x, int y){
GLfloat stepSize = 0.1f;
GLfloat blockX = vVerts[0];
GLfloat blockY = vVerts[1];
if (key == GLUT_KEY_UP) blockY += stepSize;
if (key == GLUT_KEY_DOWN) blockY -= stepSize;
if (key == GLUT_KEY_LEFT) blockX -= stepSize;
if (key == GLUT_KEY_RIGHT) blockX += stepSize;
//更新点的坐标 ABC
vVerts[0] = blockX;
vVerts[1] = blockY;
vVerts[3] = blockX + 2 * stepSize;
vVerts[4] = blockY;
vVerts[6] = blockX + stepSize;
vVerts[7] = blockY + stepSize;
triangleBatch.CopyVertexData3f(vVerts);
glutPostRedisplay();
}
void SetupRC(){
glClearColor(0.0f,0.0f,1.0f,1.0f);
shaderManager.InitializeStockShaders();
triangleBatch.Begin(GL_TRIANGLES,3);
triangleBatch.CopyVertexData3f(vVerts);
triangleBatch.End();
}
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();
}
int main(int argc,char* argv[]){
gltSetWorkingDirectory(argv[0]);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
glutInitWindowSize(800,600);
glutCreateWindow("Triangle");
glutReshapeFunc(ChangeSize);
glutDisplayFunc(RenderScene);
glutSpecialFunc(SpecialKeys);
GLenum err = glewInit();
if(GLEW_OK != err) {
fprintf(stderr,"glew error:%s\n",glewGetErrorString(err));
return 1;
}
SetupRC();
glutMainLoop();
return 0;
}
效果如下:



网友评论