学了一个月的opengl,从入门到窒息。
如果觉得本文写的看不懂,具体可以参考LearnOpengl
1 opengl基础知识
opengl ,并不是一个API,而是一个组织规范,由Khronos组织制定并维护的规范(Specification)。OpenGL规范严格规定了每个函数该如何执行,以及它们的输出值。至于内部具体每个函数是如何实现(Implement)的,将由OpenGL库的开发者自行决定(注:这里开发者是指编写OpenGL库的人)。因为OpenGL规范并没有规定实现的细节,具体的OpenGL库允许使用不同的实现,只要其功能和结果与规范相匹配(亦即,作为用户不会感受到功能上的差异)。
OpenGL自身是一个巨大的状态机(State Machine):一系列的变量描述OpenGL此刻应当如何运行。OpenGL的状态通常被称为OpenGL上下文(Context)。我们通常使用如下途径去更改OpenGL状态:设置选项,操作缓冲。最后,我们使用当前OpenGL上下文来渲染。
使用OpenGL时,建议使用OpenGL定义的基元类型。比如使用float时我们加上前缀GL(因此写作GLfloat)。int、uint、char、bool等等也类似。OpenGL定义的这些GL基元类型的内存布局是与平台无关的,而int等基元类型在不同操作系统上可能有不同的内存布局。使用GL基元类型可以保证你的程序在不同的平台上工作一致。
C++基元类型 | opengl基元类型 |
int | GLint |
float | GLfloat |
unit | GLuint |
char | GLchar |
bool | GLbool |
2 opengl的安装配置
2.1依赖安装
sudo apt-get install build-essential
sudo apt-get install libgl1-mesa-dev
sudo apt-get install libglu1-mesa-dev
sudo apt-get install freeglut3-dev
2.2GLFW安装配置
GLFW是一个专门针对OpenGL的C语言库,它提供了一些渲染物体所需的最低限度的接口。它允许用户创建OpenGL上下文,定义窗口参数以及处理用户输入,这正是我们需要的。
sudo apt-get install cmake xorg-dev libglu1-mesa-dev
(1)下载GLFW的source package
(2)编译
cd glfw-3.2.1
mkdir build
cd build
cmake ..
make
sudo make install
2.3GLEW安装
GLEW是OpenGL Extension Wrangler Library的缩写
(1)下载GLEW并解压
(2)编译
cd glew-2.1.0
make
sudo make install
2.3makefile配置
CC=g++
ELF=main
SRC=$(shell find -name '*.cpp')
OBJ=$(SRC:.cpp=.o)
LIBS=-lGLEW -lglfw3 -lGL -lX11 -lXrandr -lXi -ldl -lpthread -lm -lrt -lXxf86vm -lXcursor -lXinerama
$(ELF):$(OBJ)
$(CC) $(SRC) $(LIBS) -o $(ELF)
$(OBJ):
clean:
rm -f $(OBJ) $(ELF)
3窗口
3.1GLFW
GLFW用来创建窗口
使用前需要包含头文件
// GLEW
#define GLEW_STATIC
#include <GL/glew.h>
// GLFW
#include <GLFW/glfw3.h>
在包含GLFW的头文件之前需要先包含GLEW的头文件,否则会报错
3.2GLEW
GLEW是用来管理OpenGL的函数指针的,所以在调用任何OpenGL的函数之前我们需要初始化GLEW。
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK)
{
std::cout << "Failed to initialize GLEW" << std::endl;
return -1;
}
在初始化GLEW之前设置glewExperimental变量的值为GL_TRUE,这样做能让GLEW在管理OpenGL的函数指针时更多地使用现代化的技术,如果把它设置为GL_FALSE的话可能会在使用OpenGL的核心模式时出现一些问题。
3.3视口
在我们开始渲染之前还有一件重要的事情要做,我们必须告诉OpenGL渲染窗口的尺寸大小,这样OpenGL才只能知道怎样相对于窗口大小显示数据和坐标。我们可以通过调用glViewport函数来设置窗口的维度(Dimension):
GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", nullptr, nullptr);
if (window == nullptr)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
int width, height;
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
3.4游戏循环(Game Loop)
在程序中添加一个while循环,在我们让GLFW退出前一直保持运行
while(!glfwWindowShouldClose(window))
{
glfwPollEvents();
glfwSwapBuffers(window);
}
- glfwWindowShouldClose函数在我们每次循环的开始前检查一次GLFW是否被要求退出,如果是的话该函数返回true然后游戏循环便结束了,之后为我们就可以关闭应用程序了。
- glfwPollEvents函数检查有没有触发什么事件(比如键盘输入、鼠标移动等),然后调用对应的回调函数(可以通过回调方法手动设置)。我们一般在游戏循环的开始调用事件处理函数。
- glfwSwapBuffers函数会交换颜色缓冲(它是一个储存着GLFW窗口每一个像素颜色的大缓冲),它在这一迭代中被用来绘制,并且将会作为输出显示在屏幕上。
3.5释放资源
当游戏循环结束后我们需要正确释放/删除之前的分配的所有资源。我们可以在main函数的最后调用glfwTerminate函数来释放GLFW分配的内存。
glfwTerminate();
return 0;
3.6渲染
我们要把所有的渲染(Rendering)操作放到游戏循环中,因为我们想让这些渲染指令在每次游戏循环迭代的时候都能被执行。在每个新的渲染迭代开始的时候我们总是希望清屏,否则我们仍能看见上一次迭代的渲染结果。
glClearColor(0.2f, 0.3f, 0.3f, 1.0f); //设置清空屏幕所用的颜色
glClear(GL_COLOR_BUFFER_BIT);//清空颜色缓冲区GL_COLOR_BUFFER_BIT
//当调用glClear函数,清除颜色缓冲之后,整个颜色缓冲都会被填充为glClearColor里所设置的颜色
调用glClear函数来清空屏幕的颜色缓冲,它接受一个缓冲位(Buffer Bit)来指定要清空的缓冲,可能的缓冲位有GL_COLOR_BUFFER_BIT,GL_DEPTH_BUFFER_BIT和GL_STENCIL_BUFFER_BIT。
glClearColor函数是一个状态设置函数,而glClear函数则是一个状态应用的函数。
3.7窗口代码
/ GLEW
#define GLEW_STATIC
#include <GL/glew.h>
// GLFW
#include <GLFW/glfw3.h>
int main()
{
//初始化GLFW
glfwInit(); //成功返回GLFW_TRUE(1);失败返回GLFW_FALSE(0)
//配置GLFW窗口的hint(选项)。参数一是配置的hint名称,使用GLFW常量(以GLFW_开头)指定;第二个是我们要把该hint设置成的值,该值随要设置的hint而异。
//在本PC机中配置的opengl为4.6.0 因此设定主版本号为4,副版本号为6,设置opengl模式为核心模式,且无法改变窗口大小
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); //GLFW_CONTEXT_VERSION_MAJOR 主版本号
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5; //GLFW_CONTEXT_VERSION_MINOR 副版本号
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); //GLFW_OPENGL_PROFILE OpenGL模式
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); //GLFW_RESIZABLE 窗口是否可调整大小
//创建窗口对象,第一个参数为窗口的宽;第二个参数为窗口的高;第三个为窗口的名称
GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", nullptr, nullptr);
if (window == nullptr)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
//通知GLFW将窗口的上下文设置为当前线程的主上下文。
glfwMakeContextCurrent(window);
//初始化GLEW
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK)
{
std::cout << "Failed to initialize GLEW" << std::endl;
return -1;
}
//视口设置
int width, height;
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
//Game loop
while (!glfwWindowShouldClose(window))//检查一次GLFW是否被要求退出
{
//检查是否触发什么事件,有的话调用对应的回调函数
glfwPollEvents();
//clear
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// 渲染指令
...
// 交换颜色缓冲
glfwSwapBuffers(window);
}
return 0;
}