本章内容:自建轻量级静态OpenGL开发框架,认识第三方库的编译与链接方法。

Part I. Introduction

图形学学习初期,在使用C++开发OpenGL项目时,不可避免的需要接触各种第三方依赖包的加载和对其进行开发平台/环境适配等问题。对于大部分C++基础不是特别牢固,或者对于开发平台IDE的工作原理不是特别熟悉的同学来说,这个过程不是特别友好。很容易把大把的时间和精力耗费在对第三方库文件的编译、链接等相关问题的解决上。

针对这种现象,目前有譬如Glitter等项目框架集成了OpenGL各种常用的第三方依赖库,方便了图形学新手的学习。但是这一类集成框架具有以下三个小缺点:

  • 框架体积过于庞大,每开启一个新项目就必须重新复制原有框架(文件体积大于1G),导致不必要的资源冗余。
  • 在集成框架下,如果涉及到其他框架不具备的第三方依赖库,新手很难自行添加导致进度受阻难以进行。
  • 无法比较简单地更改项目名称对于一些具有强迫症的开发人员很不友好。

本文主要致力于提供一种通过链接静态依赖库,自行搭建OpenGL开发框架的方法,以便于图形学新手思路清晰地学会自行加载第三方库,以及对框架架构有一个整体的认识。框架具有体积小(约20MB),可调整性强,各种修改比较自由等优点。

推荐使用本框架配合LearnOpenGL内容学习。


Part II. Preparation

1. 建立框架文件结构。

对于常用的图形学项目而言,文件结构一般如下。

  • ExampleProject(框架根文件夹,可以取任何名字。在此文件夹内创建Xcode新项目)

    • ExampleProject(此文件夹为Xcode项目目录,新建Asserts、Headers、Shaders、Sources文件夹)

      • Asserts(放置所有纹理、模型等资源)
      • Headers(放置所有用户定义头文件)
      • Shaders(放置所有渲染Shader文件)
      • Sources(放置main.cpp与glad.c这一类源程序文件)
    • include(所有第三方库的头文件放置处(.h文件))
    • lib(所有第三方库的lib文件放置处(.a文件))

按照图一建立文件结构,进入下一步。

图一:示例框架结构

2. 下载 Library GLFW

下载取得一个glfw-3-2.3.zip文件,mac下自动解压。

I. GLFW是什么?

  • GLFW为Graphics Library Framework的缩写。

II. GLFW的主要负责什么功能?

  • 创建、管理窗口
  • OpenGL Context
  • 处理手柄、键盘、鼠标输入

III. 为什么要用GLFW?

  • 因为OpenGL并没有提供窗口渲染的方法,必须依赖第三方库创建、管理窗口。

3. 下载适合您的 Library glad

将语言(Language)设置为C/C++,在API选项中,选择3.3以上的OpenGL(gl)版本,将模式(Profile)设置为Core,并且保证生成加载器(Generate a loader)的选项是选中的。现在可以先(暂时)忽略拓展(Extensions)中的内容。都选择完之后,点击生成(Generate)按钮来生成库文件。下载取得一个glad.zip文件,mac下自动解压。

I. glad是什么?

  • glad为OpenGL Loading Library的缩写。

II. glad的主要负责什么功能?

  • 由于OpenGL只是一个标准/规范,具体的实现是由驱动开发商针对特定显卡实现的。而OpenGL驱动版本众多,它大多数函数的位置都无法在编译时确定下来,需要在运行时查询。所以任务就落在了开发者身上,开发者需要在运行时获取函数地址并将其保存在一个函数指针中供以后使用。取得地址的方法因平台而异,在Windows上会是类似这样:
 // 定义函数原型
typedef void (*GL_GENBUFFERS) (GLsizei, GLuint*);
// 找到正确的函数并赋值给函数指针
GL_GENBUFFERS glGenBuffers  = (GL_GENBUFFERS)wglGetProcAddress("glGenBuffers");
// 现在函数可以被正常调用了
GLuint buffer; glGenBuffers(1, &buffer);

  • 你可以看到代码非常复杂,而且很繁琐,我们需要对每个可能使用的函数都要重复这个过程。幸运的是,有些库能简化此过程,其中GLAD是目前最新,也是最流行的库。

III. 为什么要用glad?

  • 一定程度上,glad能够用于在开发中取代glew(OpenGL Extension Wrangler Library)。glad是一个比较新的Lib,比较推荐XD。

4. 下载 Library glm

下载取得一个glm-0.9.9.6.zip文件,mac下自动解压。

I. glm是什么?

  • glm是OpenGL Mathematics的缩写,它是一个只有头文件的库。

II. glm的主要负责什么功能?

  • glm是一个数学函数库,包含图形领域数学常用的向量、矩阵等函数。

III. 为什么要用glm?

  • OpenGL没有自带任何的矩阵和向量函数,所以我们必须定义自己的数学类和函数。glm抽象了所有的数学细节,为我们使用数学函数提供了方便。

5. 下载 Library stb

下载整个仓库获得stb-master.zip,解压压缩包将文件夹重命名为stb。

I. stb是什么?

  • stb是作者名字Sean T. Barrett的首字母缩写(initials),它是一个非常流行的(单)头文件图像(加载)库。

II. stb的主要负责什么功能?

  • 负责加载大部分流行的文件格式的图片作为纹理文件(暂时,它还具有很多其他功能)。

完成这一Part后,目前的状态:框架文件夹ExampleProjectglfw文件夹、glad文件夹、glm文件夹、stb文件夹。以上文件夹可以位于任意路径下。


Part III. Libraries Make, Build and Link

对于我们下载的第三方Libraries,大致可以分为以下三种类型。以下过程均以MacOS下的Xcode平台为例,Windows/Linux环境下整体思路不变。

一、需要自行编译、链接的第三方库:以GLFW为例。

这一类库最显著的特征就是它的目录下面有CMakeLists.txt以及各种cmake文件。这一类库则需要自行编译、链接。对于这一类库,大致需要三个阶段处理。

1. Make Phase

>> cd glfw-3.3 // 进入GLFW文件夹
>> mkdir Build // 新建Build文件夹
>> cd Build //进入Build文件夹
>> cmake -G "Xcode" .. // make

解释: 在GLFW目录下创建一个Build目录(只是为了使文件结构清晰),cmake外层源文件。 同理将"Xcode"替换成诸如"Visual Studio 14 Win64"等可以获得相应平台的make生成文件。

此阶段获得目标开发平台的工程文件——GLFW.xcodeproj

2. Build Phase

打开文件GLFW.xcodeproj,直接Build All。完成编译。

此阶段获得目标开发平台的静态依赖库文件——libglfw3.a,位于Debug文件夹下。此时文件目录结构如下图所示。

图二:glfw文件目录结构

3. Link Phase

添加头文件和静态库到框架内

  • 将头文件文件夹(一般位于Library的include目录下,也可能是别的名称,内部是.h的头文件)移动到include文件夹下。
  • 将依赖库文件(MacOS系统下为.a文件)移动到lib文件夹下

目录结构如下图所示。

图三:示例框架结构

配置 Xcode 寻找路径和链接静态库

打开项目工程文件ExampleProject.xcodeproj,配置IDE的头文件搜索目录、库文件搜索目录、编译源以及链接。

  • 过程[1]:配置 Search Path:

    • Header Search Path: $(SRCROOT)/include
    • Library Search Path: $(SRCROOT)/lib
    • User Header Search Path: $(SRCROOT)/ExampleProject/Headers

解释:
Header Search Path:Xcode搜索使用#include <>的头文件时查找的目录。
Library Search Path:Xcode使用外部依赖包时搜索的路径。
User Header Search Path:Xcode搜索使用#include ""的头文件时查找的目录。

图四:Build Settings配置
  • 过程[2]:配置 Compile Sources:

    • add glad.c
    • add main.cpp

解释: 将.c文件加入编译源文件。

  • 过程[3]:配置 Link Binary With Libraries

    • add libglfw3.a
    • add IOKit.framework
    • add CoreVideo.framework
    • add OpenGL.framework
    • add Cocoa.framework

解释: OpenGL不具有自身创建窗口的功能。GLFW需要依赖MacOS自身的四项framework。所以必须保证这四个framework被配置完成。

图五:Build Phases配置

glmassimpbullet等常用库均用此方法加入框架。

二、不需要需要自行编译的第三方库:以glad为例。

这一类库的特征则为它们的目录由include文件夹(内含.h头文件)和src(或者别的名称)文件夹(内含.c源文件)构成。

引入框架的方法:

  • include文件夹下面所有文件/文件夹加入我们的框架的include文件夹下面(请注意此时你的操作与后面头文件的应用关系#include <glad/glad.h>意味着你把glad头文件文件夹拖进了include里面)。
  • src文件夹下面的源文件加入Sources文件夹内,并执行过程[2]。

三、单头文件库:以stb为例。

这一类库无需编译链接等工作。

引入框架的方法:

  • 将stb整个文件夹我们的框架的include文件夹下。

我们需要在头文件加入一行预处理(preprocessor),预处理器会修改头文件,让其只包含相关的函数定义源码,等于是将这个头文件变为一个 .cpp 文件了。现在只需要在你的程序中包含stb_image.h并编译就可以了。

#define STB_IMAGE_IMPLEMENTATION
#include <stb/stb_image.h>

需要注意的是:

  • 绝对不要在头文件(header (.h) files)中加入这句话#define STB_IMAGE_IMPLEMENTATION 只有 C/C++ file 才可以加入这句 implementation。
  • 这句话必须保证唯一性(UNIQUE),只能添加一次!

Part IV. Have Fun With Graphics

在你成功完成本文提到的四个依赖库的加载后,你的项目文件结构大概会是这个样子的:

此时如果把这些文件加入你的Asserts、Headers、Shaders和Sources文件夹并且同步到Xcode运行的话,那么你就能得到一个2Dgame-Breakout游戏!这是不是比一个黑框框要好玩的多?

按空格键开始,A/D键左右移动。

  • 注意:Xcode默认相对目录不是工程文件所在目录而是可执行文件所在目录。所以请在Product->Scheme->Edit Scheme->Run->Options->Working Directory中勾选并设置当前目录为相对根目录以便文件定位!

Have Fun With Graphics! XD

和opengl的关系_从零开始的图形学学习(零):一切的开始 —— 自建OpenGL开发框架...相关推荐

  1. c++和opengl实现gis_从零开始的图形学学习(零):一切的开始 —— 自建OpenGL开发框架

    本章内容:自建轻量级静态OpenGL开发框架,认识第三方库的编译与链接方法. Part I. Introduction 图形学学习初期,在使用C++开发OpenGL项目时,不可避免的需要接触各种第三方 ...

  2. matlab数组平方的计算自定义函数_从零开始的matlab学习笔记——(38)简单数论计算函数:取整,gcd,lcm,质数,全排列...

    matlab应用--求极限,求导,求积分,解方程,概率统计,函数绘图,三维图像,拟合函数,动态图,傅里叶变换,随机数,优化问题....更多内容尽在个人专栏:matlab学习 翻了翻优化工具箱,发现内容 ...

  3. matlab 线性规划_从零开始的matlab学习笔记——(37)线性规划——后传

    matlab应用--求极限,求导,求积分,解方程,概率统计,函数绘图,三维图像,拟合函数,动态图,傅里叶变换,随机数,优化问题....更多内容尽在个人专栏:matlab学习 呼,终于将matlab的优 ...

  4. matlab将图片旋转的代码_从零开始的matlab学习笔记——(27)图像旋转与动态图...

    matlab应用--求极限,求导,求积分,解方程,函数绘图,三维图像,拟合函数....更多内容尽在个人专栏:matlab学习 昨天思考了一下,因为笔者的GUI只是刚刚入门,如果直接说的话也说不了多少东 ...

  5. matlab做三次拉格朗日插值多项式_从零开始的matlab学习笔记——(24)曲线拟合...

    matlab应用--求极限,求导,求积分,解方程,函数绘图,三维图像,拟合函数....更多内容尽在个人专栏:matlab学习 才发现这个数据插值的返回值不是个函数表达式,是一系列点集,不能使用poly ...

  6. matlab for循环_从零开始的matlab学习笔记——(5)循环

    上一节的内容有点多,所以循环我就放在了这一篇来说说.matlab的循环和c语言很相似,也是分为for循环和while循环. while循环: while condition 代码1 end 代码2 c ...

  7. matlab无穷积分求解_从零开始的matlab学习笔记——(8)积分

    上节说了说求导,这节就顺带着说一说求积分,凑个完整. 不定积分: 定积分的代码和极限求导都差不多: syms x f; f=(3-x^2)^3; ans1=int(f,x) pretty(ans1) ...

  8. matlab meshgrid函数_从零开始的matlab学习笔记——(28)立体图切面与三视图

    matlab应用--求极限,求导,求积分,解方程,概率统计,函数绘图,三维图像,拟合函数,动态图....更多内容尽在个人专栏:matlab学习 这一节我们说一说立体图的切面问题 slice函数 sli ...

  9. matlab max函数_从零开始的matlab学习笔记——(14)一些有用的函数(上):最值,平均数,中位数...

    matlab应用--求极限,求导,求积分,解方程....更多内容尽在个人专栏:matlab学习 上一节说了说符号运算中的多项式,这一节我们来看看几个非常有用的函数 最值: 最大值max(),最小值mi ...

  10. matlab 1到无穷_从零开始的matlab学习笔记——(6)符号计算与极限

    上一节总算是把那些无聊的内容给说完了,从这节开始我们将接触到matlab许多强悍的功能.按理说我应该先把图像绘制部分记录完,再记录求极限内容.但是图像绘制内容有些多,而求极限功能感觉用处很大(尤其是对 ...

最新文章

  1. Can't toast on a thread that has not called Looper.prepare()
  2. PL/SQL Developer 和 instantclient客户端快速安装配置(图文)
  3. httplistener java_Java监听器listener的介绍
  4. 阿里云ubuntu服务器安装使用mysql并配置远程连接记录
  5. glut相关函数说明
  6. 单片机编程软件 UV4启动界面修改(没啥卵用系列)
  7. 西门子cpu指示灯含义_CPU中的指示灯亮的意思
  8. 一种身份证号码的编码压缩方法
  9. C++之vector 初始化指定大小容量
  10. java线程生命周期
  11. 使用文本编辑器来写Python代码
  12. 电脑哔哩哔哩播放器调整为html5,谷歌浏览器插件哔哩哔哩(Bilibili)播放器扩展Extension for Bilibili Player关闭弹幕、截图、画中画...
  13. 最简单最适合纯小白的postman使用方法(测试接口的不二利器)(从介绍到下载到使用的详细教程)
  14. 2. Python函数式编程中的字符串,元组,函数的分类,高阶函数,一篇文章都介绍一遍
  15. 墨画子卿第三章第9节:是一个人
  16. 近千只股票跌停 沪指暴跌281点创历史之最
  17. 关于数据跳线制作的标准规范的理解
  18. python爬虫分布图_13天搞定Python分布爬虫!成为炙手可热的爬虫工程师
  19. GBase 8s 数据库类型
  20. 【ICPC-75】uva 112 Tree Summing

热门文章

  1. Gateway配合sentinel自定义限流_使用Sentinel实现gateway网关及服务接口限流
  2. delphi acropdf打印多个pdf_将多个PDF文件整合成一个文件
  3. iphone怎么重启_手机卡死了,又不能拆电池!你会怎么处理?
  4. TypeScript:初体验
  5. 谷粒商城:14.全文检索ElasticSearch
  6. 怎么锁定计算机密码忘了怎么办,电脑在控制面板被锁密码忘记怎么开呢?
  7. Ubuntu18.04 orb-slam3编译出现的错误 undefined reference to symbol ‘_ZN3MPI8Datatype4FreeEv‘ libmpi_cxx.so
  8. 眼底图像血管增强与分割--(1)匹配滤波算法原理及实现
  9. 支持中国西安申办ICCV2025,见证计算机视觉蓬勃发展的20年| Vote for ICCV2025 Xi'an China...
  10. 给定一个整数数组 nums ,找出一个序列中乘积最大的连续子序列(该序列至少包含一个数)。