前言:前一部分了解了OpenGL环境搭建和基本API以后,咱们先来作一个小小的练习,使用固定管线来绘制一个可移动的三角形,同时详细解释一下一些经常使用方法的含义
复制代码
搭建Xcode环境,这里再也不作过多赘述了windows
传送门:juejin.im/post/5d67e1…数组
(注:完整代码在文章的最后面) 一、首先来到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;
}
复制代码
下面来一一分析对应函数和方法的意思,bash
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 初始化模板缓冲区oop
glutInitWindowSize(800,600) 初始化一个GLUT窗口并设置窗口大小 glutCreateWindow("Triangle") 设置窗口的标题post
glutReshapeFunc(ChangeSize) 注册绑定重塑函数,当窗口第一次建立或者窗口大小发生变化,须要界面重绘时,系统会自动调用这个已经注册过的自定义函数ChangeSize glutDisplayFunc(RenderScene) 注册绑定显示函数,当屏幕发生渲染或者你使用代码强制渲染,须要界面重绘的时候,系统会自动调用这个已经注册绑定过的自定义函数RenderSize测试
glutSpecialFunc(SpecialKeys); 当你使用特殊键位的时候好比键盘的上下左右键的时候,就会走到这个方法里,在这个函数中作特殊键位区分的时候,这些特殊键位都有对应的枚举值好比上(GLUT_KEY_UP) 下(GLUT_KEY_DOWN)左(GLUT_KEY_LEFT)右(GLUT_KEY_RIGHT),我找了一些,这个简单了解一下就好了ui
#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,函数在调用以后,在主窗口被关闭以前都不会返回,一个应用程序只须要调用一次,这个函数负责处理咱们全部的消息,直到咱们关闭程序为止。
二、接着引入固定管线着色器和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的静态库版本并须要添加一个宏
三、重塑函数的实现,在窗口大小改变的时候,接受新的宽度和高度
void changeSize(int w,int h)
{
glViewport(0, 0, w, h);
}
复制代码
glViewPort这个函数就是设置视口,x,y 参数表明窗口中视图的左下角坐标,而宽度、高度是像素为表示,一般x,y 都是为0,调用glViewPort会调用从新渲染RenderScene
四、接着定义一个着色器管理变量和一个批次类,GLBatch是GLTools的一个简单的容器类
GLBatch triangleBatch;
GLShaderManager shaderManager;
复制代码
五、接下来,咱们须要设置渲染环境和顶点数据
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图元只有点、线、三角形,如今画点,线以及多边形都没问题了,圆形就须要经过这三个作处理一下了
六、接下来咱们须要设置渲染
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下,有一个红色的三角形
七、开始设置移动,设置移动以前须要把顶点坐标设置为全局变量,这样好处理,把下面顶点数组放到全局
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;
}
复制代码
效果以下: