为什么说使用 Linux 系统学习 OpenGL 更方便
前言
上一篇随笔介绍了我的电脑,同时也介绍了 Ubuntu 20.10 系统的安装和美化。这一篇,我将正式开始 OpenGL 之旅。使用 Ubuntu 来进行开发,不仅仅只是因为我对 Linux 桌面比较熟悉,其实我对 Windows 也很熟悉,主要还是因为在 Linux 系统下搭建 OpenGL 的开发环境确实是太方便了。在 Windows 下开发 OpenGL,每用到一个库,我们都要单独去搜索和下载,然后在 Visual Studio 中进行设置,很繁琐。在 Ubuntu 中,安装这些库,就是一条命令的事,下面详细论述。
搭建 OpenGL 的开发环境
学 OpenGL,C/C++ 应该是首选,所以先安装 C/C++ 的开发环境,无论是选择 GCC,还是选择 CLang,在 Ubuntu 中就是一条命令的事,我这里选 GCC。在 Ubuntu 中,可以直接安装 build-essential,更省事。命令如下:
sudo apt install build-essential
OpenGL 不提供和 GUI 相关的 API,所以 OpenGL 不能处理诸如创建窗口、处理用户的键盘鼠标输入这样的任务。这时,我们需要 GLFW。使用 GLFW 库,我们可以简化搭建 OpenGL 程序框架的任务,同时还可以轻松获得跨平台的功能。安装 GLFW 也是一条命令的事:
sudo apt install libglfw3 libglfw3-dev
除此之外,我们还需要 GLEW。有了GLEW 扩展库,就再也不用为找不到函数的接口而烦恼了,因为GLEW能自动识别平台所支持的全部 OpenGL 高级扩展涵数。安装命令如下:
sudo apt install libglew2.1 libglew-dev
另外,在写 OpenGL 程序的过程中,会经常需要进行向量、矩阵的计算,所以有一个顺手的数学库是很重要的,我这里选择 GLM。安装命令如下:
sudo apt install libglm-dev
学会了 OpenGL 的基本概念后,当然会忍不住想加载个 3D 模型看看效果,这时候,就可以考虑使用 Assimp 库了。安装命令如下:
sudo apt install assimp-utils libassimp5 libassimp-dev
assimp-utils 包提供了一个assimp命令,使用该命令可以显示 Assimp 库支持哪些格式的 3D 模型文件,也可以使用该命令显示 3D 模型文件的详细信息,如下图:

当然,3D 的东西,还是应该用可视化的方式看起来更直观一些。好在,Linux 中可用的 3D 建模动画软件有 Blender。安装起来也只是一条命令的事:
sudo apt install blender
下面,让大家看一下我的老婆,用的就是 Blender:


最简单的 OpenGL 程序框架
下面,开始写我们的第一个 OpenGL 程序,如下:
#include <iostream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
const int SCR_WIDTH = 1920;
const int SCR_HEIGHT = 1080;
int main(int argc, char** argv){
glfwInit();
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "StudyOpenGL", nullptr, nullptr);
if (window == NULL)
{
std::cerr << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
if(glewInit() != GLEW_OK){
std::cerr << "Failed to initalize GLEW" << std::endl;
return -1;
}
while (!glfwWindowShouldClose(window))
{
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}
这段程序比较短,使用任何编辑器如 vim、gedit 等等都可以。当后面程序变长之后,我选择使用 Visual Studio Code。我们将这个文件保存为 FirstStep.cpp。编译执行的命令也很简单:
g++ FirstStep.cpp -o FirstStep -lGL -lGLEW -lglfw
./FirstStep
就可以看到我们的第一个 OpenGL 窗口了,目前,它还只是空洞洞的漆黑一片,如下图:

因为我是 4K 屏,所以即使定义了SCR_WIDTH = 1920和SCR_HEIGHT = 1080,窗口看起来也不是特别大。上面那个程序是纯 C 版的,等程序变大之后,会在 main() 函数之外遗留很多全局的变量和函数,不是那么清爽,所以常规会使用 C++ 封装一下,建立一个 App 类,以后要添加鼠标键盘输入的功能也在这个类里面加,建立新程序时,只需要继承这个类就可以了。App 类的内容如下:
#ifndef __APP_HPP__
#define __APP_HPP__
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
class App{
private:
const int SCR_WIDTH = 1920;
const int SCR_HEIGHT = 1080;
public:
static App* the_app;
App(){
}
virtual void init(){
}
virtual void display(){
}
virtual void run(App* app){
if(the_app != NULL){ //同一时刻,只能有一个App运行
std::cerr << "The the_app is already run." << std::endl;
return;
}
the_app = app;
glfwInit();
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "StudyOpenGL", NULL, NULL);
if (window == NULL)
{
std::cerr << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return;
}
glfwMakeContextCurrent(window);
if(glewInit() != GLEW_OK){
std::cerr << "Failed to initalize GLEW" << std::endl;
return;
}
init(); //用来准备各种数据
while (!glfwWindowShouldClose(window))
{
display(); //这里才是渲染图形的主战场
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
return;
}
};
App* App::the_app = NULL;
#define DECLARE_MAIN(a) \
int main(int argc, const char ** argv) \
{ \
a *app = new a; \
app->run(app); \
delete app; \
return 0; \
}
#endif
把这个文件保存在 include 目录下,命名为 app.hpp,然后,把之前的 FirstStep.cpp 改成如下内容:
#include "../include/app.hpp"
class MyApp : public App {
private:
public:
void init(){
}
void display(){
}
~MyApp(){
}
};
DECLARE_MAIN(MyApp)
编译运行,结果是一样的。以后,只需要把初始化数据的代码放到 init() 方法中,把渲染图形的代码放到 display() 方法中即可。程序运行时,init() 方法只调用一次,而 display() 方法每渲染一帧图像就调用一次。
OK,到这里,我们的环境就搭建好了。在下一篇随笔中,我们争取使用 OpenGL 渲染一点有用的东西。
版权申明
该随笔由京山游侠在2021年01月27日发布于博客园,引用请注明出处,转载或出版请联系博主。QQ邮箱:1841079@qq.com
为什么说使用 Linux 系统学习 OpenGL 更方便的更多相关文章
- Linux系统学习笔记:文件I/O
Linux支持C语言中的标准I/O函数,同时它还提供了一套SUS标准的I/O库函数.和标准I/O不同,UNIX的I/O函数是不带缓冲的,即每个读写都调用内核中的一个系统调用.本篇总结UNIX的I/O并 ...
- Linux系统学习优缺点
Linux是一套操作系统,按照鸟哥的说法Linux提供了一个完整的操作系统当中最底层的硬件控制与资源管理的完整架构,这个架构是沿袭Unix良好的传统而来的,功能强大而且稳定性卓越.其实Torvalds ...
- 谈谈我对Linux系统学习的历程回顾
众所周知,Windows 和Linux 是目前最流行的2个操作系统.Windows系统适合普通用户,它的优势是图形化界面,简单易用,使用起来门槛很低,很容易上手,所以,windows占有了大多数普 ...
- 说一说本人对linux系统学习的方法和经验
摘要: 相信大伙都听说过linux系统,然而对于这个系统,总使让新手感觉茫然,诺达的系统.下面是一段百度中的介绍: 相信大伙都听说过linux系统,然而对于这个系统,总使让新手感觉茫然,诺达的系统.下 ...
- Linux系统学习笔记(1)
学习地址:http://www.runoob.com/linux/linux-tutorial.html 1.学习Windows和Linux哪个比较难? 前期是Windows容易学习,后期是Linux ...
- 网工的Linux系统学习历程
偶遇篇作为一名通过思科CCNP认证的网络工程师,专注于网络技术.但在日常的工作中,难免不接触到服务器,对于大多数服务器来说,鉴于稳定性等因素的考虑,基本使用的都是Linux系统,包括RHEL.Cent ...
- 老司机浅谈linux系统学习技巧
Linux起源于20世纪70年代,是一种优秀的操作系统系统.初次接触到linux这个系统是在大学期间,这样才发现除了windows外的另外一个有趣系统.开始抱着好奇的心态去了解,随着深入学习,笔者被它 ...
- Linux 系统学习梳理_【All】
第一部分---基础学习 00.Linux操作系统各版本ISO镜像下载 00.Linux系统下安装Vmware(虚拟机) 00.Linux 系统安装[Redhat] 00.Linux 系统安装[Cent ...
- Linux系统学习之 一:新手必须掌握的Linux命令1
2018-10-03 16:04:12 一.常用系统工作命令 1.wget 命令 作用:用于在终端中下载网络文件. 格式:wget [参数] 下载地址 参数及作用: -b : 后台下载模式 -d:显示 ...
随机推荐
- js笔记6
1.函数都有返回值,人为return,返回什么就是什么,否则,他的返回值就是undefined 而方法的本质也是函数,所以也有返回值 document.getElementById()返回的是获取的标 ...
- mysql_my.cnf文件详解
以下是 my.cnf 配置文件参数解释:#*** client options 相关选项 ***##以下选项会被MySQL客户端应用读取.注意只有MySQL附带的客户端应用程序保证可以读取这段内容.如 ...
- Datahub 0.8.5发布! 通用的元数据搜索和发现工具
近期Datahub 发布了最新的版本0.8.5,作为LinkedIn开源的通用的元数据搜索和发现工具.Datahub近一年来有了巨大的发展,也成为了很多公司进行元数据管理的调研方向并进行使用的选择. ...
- 企业如何通过CRM系统使销售周期缩短
企业为什么要缩短销售周期?因为这意味着可以节约更多开支,从而达到企业利润最大化.但是有不少企业尤其是B2B行业,销售周期都在三个月以上.通过调查发现,很多企业在客户信息和销售管道上缺乏管理和策略.Zo ...
- Hadoop0.20.2中MapReduce读取gb2312文件出现乱码问题
单位用的是Linux系统的字符编码是gb2312,所以生成的文件都是按照默认编码生成的.给我的文件也都是gb2312的,在hadoop中运行mapreduce出现乱码,在网上查资料说是因为hadoop ...
- 多线程笔记-CancellationToken(取消令牌)
介绍 为什么需要CancellationToken?因为Task没有方法支持在外部取消Task,只能通过一个公共变量存放线程的取消状态,在线程内部通过变量判断线程是否被取消,当Cancella ...
- 5.Java流程控制
所有的流程控制语句都可以相互嵌套.互不影响 一.用户交互Scanner Scanner对象 之前我们学的基本语法中我们并没有实现程序和人的交互,但是Java给我们提供了这样一个工具类,我们可以获取用户 ...
- python使用笔记21--发邮件
发邮件需要第三方模块 pip install yamail 1 #import yagmail #--别人写的,发中文附件的时候是乱码 2 import yamail #牛牛基于yagmail改的 3 ...
- c++ 进制转换源代码
#include<stdio.h> int main() { char ku[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C ...
- [刘阳Java]_Spring IoC原理_第2讲
Spring IoC(DI)是Spring框架的核心,所有对象的生命周期都是由它们来管理.对于弄懂Spring IOC是相当关键,往往我们第一次接触Spring IOC大家都是一头雾水.当然我们这篇文 ...