1. 概述
为啥学习openGL,因为在开发QT 3D场景时,看见官方有个boxes的demo,想学习一下.
本文主要解决两个问题:
- OpenGL到底是什么鬼?
- 如何创建一个使用OpenGL的窗口?
2. OpenGL到底是什么鬼?
笔者也算是一个入门的C++程序员了,一下决心要学习OpenGL之后就直接上谷歌搜了OpenGL的官网(当然这是要翻越万里长城的),想下一个API就上手。然而在官网上溜了一大圈,楞是没找到一个下载API的地方,倒是在各种显卡厂商的官网上都转了一圈,灰头土脸。
在网上找了很多资料之后,终于明白了一点,这也是非常重要的一点,就是:OpenGL并不是一个API(API这个应该懂吧,搞编程的人都知道。什么?你说你不是搞编程的?那你看这篇文章,还不速速出门右转。)库,而是一组规范,这组规范是由Khronos Group来维护的。(别问我Khronos Group是什么鬼,对于只能写入门文字的笔者来说,这也是第一次看到。)
这组规范定义了一组函数,这组函数传入的是什么参数,传出的是什么结果。由于只是这样的一组规范,所以只要合乎规范,谁都能以不同的方式实现函数。这也就是在官网上找不到API库的原因了,通常这些API是由显卡厂商实现的。顺便说一句,如果装了VS,VS里自带有OpenGL的库(至少笔者的VS2013里有)。
状态机
OpenGL本身就是一个大状态机:有很多变量可以设置以便我们控制其操作。OpenGL的状态通常被称为上下文(context)。我们在操作OpenGL的时候就是通过改变其状态来改变其运行的上下文,这样OpenGL就能给我们想要的结果了。
3. 如何创建一个使用OpenGL的窗口?
3.1. 所需工具
GLFW库+Ubuntu16.04+GLAD源码
GLFW是一个开源的跨平台窗口库,它封装了与操作系统相关的创建窗口的过程,让我们的窗口创建只需要调用少量的函数就能实现。(妈妈再也不用担心我不会创建窗口了)
Ubuntu,基础运行系统平台,类似于Windows系统,属于一个操作系统,只不过Ubuntu是开源操作系统,不收取版权费用,最最关键的是它没有哪些烦人的打补丁操作,有时候运气不好打补丁失败还要回滚,运气差点还要重载系统…
GLAD源码是用来封装调用OpenGL库中的函数的,让我们调用OpenGL函数的时候只需要用熟悉的函数调用方式,不需要创建一个函数指针,然后加载dll中的函数地址,然后再调用。说的有点抽象啊,举个例子就知道了。原本我们的代码要是这个样子:
typedef void (*GL_GENBUFFERS)(GLsizei, GLuint*);
GL_GENBUFFERS glGenBuffers = (GL_GENBUFFERS)wglGetProcAddress("glGenBuffers");
glGenBuffers(1, &buffer); //这里才是调用函数的位置,上面只是获取函数地址
有了GLAD源码之后,我们就只需要这样子就行了:
glGenBuffers(1,&buffer); //省去了获取函数地址的操作
3.2. 环境打造:
3.2.1 ubuntu 环境搭建
安装openGL库及依赖
sudo apt-get install build-essential
sudo apt-get install libgl1-mesa-dev
sudo apt-get install libglu1-mesa-dev
3.2.2 GLFW库
第一步:下载GLFW
CSDN本地资源包:
- 下载方式1:
CSDN本地资源包 : glfw-3.3.3.tar.gz
- 下载方式2:
官网地址是:http://www.glfw.org/download.html(你需要翻墙才能访问)
选择下载源文件,文件包名为glfw-3.2.1.zip
第二步:下载CMake,编译glfw的源码
Ubuntu下安装CMake超级简单:
sudo apt-get install cmake
第三步:下载GLAD
下载方式1:
CSDN资源 : glad.zip
下载方式2:
GLFW的源码是需要通过CMake来编译的,所以我们刚才需要安装一个CMake.
官网地址:http://glad.dav1d.de/(继续翻),选择好需要的版本和模式
点击页面最下方右下角的GENERATE按钮,在随后弹出的页面中,点击glad.zip进行下载
第四步:编译并运行
gitee整合后代码:
https://gitee.com/pengrui2009/open-gl-study.git
git clone https://gitee.com/pengrui2009/open-gl-study.git
cd open-gl-study/OpenGL
cd assimp-3.3.1 && mkdir build && cd build && cmake .. && make
cd glfw-3.3.3 && mkdir build && cd build && cmake .. && make
cd glm-0.9.8.0 && mkdir build && cd build && cmake .. && make
cd ../
mkdir third_party
mkdir third_party/include
mkdir third_party/library
cp OpenGL/glfw-3.3.3/build/src/libglfw3.a ./third-party/library
cp -a OpenGL/glfw-3.3.3/include/GLFW third-party/include
cp -a OpenGL/assimp-3.3.1/build/code/libassimp.so* third-party/library/
cp -a OpenGL/assimp-3.3.1/include/assimp third-party/include
cp -a OpenGL/glm-0.9.8.0/glm third-party/include
cp -a OpenGL/glad/include/* third-party/include
#将glad.c文件放置在工作根目录下
cp -a OpenGL/glad/src/glad.c .
完成之后,我们的OpenGL基础编译环境就搭建完成了.
第六步:创建一个测试验证文件
新建cpp文件,取名为main.cpp,在main函数中加入如下代码
#include <iostream>
#include "glad/glad.h"
#include "GLFW/glfw3.h"
void framebuffer_size_callback(GLFWwindow *window, int width, int height)
{
glViewport(0, 0, width, height);
}
void processInput(GLFWwindow *window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
{
glfwSetWindowShouldClose(window, true);
}
}
int main()
{
glfwInit();
//指定OpenGL的主版本号
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
//指定OpenGL的子版本号
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
//使用OpenGL的核心模式(可编程渲染管道的模式)
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
//创建窗口
GLFWwindow *window = glfwCreateWindow(1280, 720, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
//如果出错,则终止进程
glfwTerminate();
return -1;
}
//将窗口的上下文环境设置为当前主线程的上下文环境
glfwMakeContextCurrent(window);
//初始化glad
if(!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
//注册窗口回调函数
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
//渲染循环
//检测是否关闭窗口
while(!glfwWindowShouldClose(window))
{
//处理输入事件
processInput(window);
glClearColor(1.0f, 1.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glfwSwapBuffers(window);
glfwPollEvents();
}
//终止进程
glfwTerminate();
return 0;
}
其中framebuffer_size_callback和processInput是两个处理消息的函数
framebuffer_size_callback函数:用于当窗口大小改变时,改变OpenGL视口的区域大小
processInput函数:处理输入事件
第七步: 编译
编写Makefile,内容如下
all:
gcc -c -o glad.o glad.c third-party/library/libglfw3.a -Ithird-party/include -Ithird-party/library -lGL -lm -ldl -lpthread -lX11
g++ -c -o brave_world.o brave_world.cpp third-party/library/libglfw3.a -Ithird-party/include -Lthird-party/library/ -Iparty/include -lGL -lm -ldl -lpthread -lX11 -std=c++11
g++ -o brave_world brave_world.o glad.o third-party/library/libglfw3.a -Ithird-party/include -Lthird-party/library/ -lassimp -lGL -lm -ldl -lpthread -lX11
clean:
-rm -fr *.o
make all
第八步:运行
./brave_world
4. 运行效果
效果如下:
5. 总结
好了,到此为止,我们已经成功创建了一个使用OpenGL的窗口,万里长征终于走出了第一步。歇口气,休息一会再学下一章!
本章节工程源代码:
https://gitee.com/pengrui2009/open-gl-study/tree/master/chapter1
6. 参考资料:
1.learnopengl.com(这是一个非常不错的网站,笔者就是在这个网站上学的,这一系列的文章大部分是参考这里的内容,强烈推荐想学的小伙伴去这里学)
2. 这里主要参考了闪电的蓝熊猫的博客,只是适配了Ubuntu系统平台, 链接:https://www.jianshu.com/p/d83a519ae2d0