LearnGL - 01 - CreateWindow

LearnGL - 学习笔记目录

本人才疏学浅,如有什么错误,望不吝指出。

学习资料参考了:LearnOpenGL.CN,这也是我目前觉得最好的资料,而且这个有中文翻译的版本。

OpenGL的学习资料所搜看过一些,要么是收费,要么是教程质量没那么好。
(在线资料收费就不太应该,完全是阻碍知识传播,你编辑好发布成书籍拿去卖都还好,大家都愿意的)

学习目的:

  • 工作需要,之前面试有也考量的点;
  • 顺便看看OpenGL的一些简单使用;

我之前自学图形学是在去年2019.5月初,买了一本《Unity Shader 入门精要》,学了大概一半的时候。觉得对图形学相见恨晚,感觉之前学的都是渣渣。

激动之下我就停下来,为了验证知识点的正确性,巩固图形基础知识的理解,我就用C#写了个:软渲染器。(确实收获很大,先是写了一个:用C# Bitmap作为画布写个3D软渲染器,后面再写了一个精简便于理解的:C# 实现精简版的栅格化渲染器

《Unity Shader 入门精要》这本书感觉写的真心好,表达能力非常棒。
由于作者考虑书是面向入门、初学者级别的,在每个知识点都讲得循序渐进,考虑的非常细致,对入门读者知识的消化好很多。

后面在看完此书后,由于其他事情的原因,在2019.9~2020.2中旬都没有学习图形这块资料。

2020.2中旬由于国内新冠病毒爆发,就待在家一直学习图形方面的内容;到2020.5初,又中断了图形方面的学习,停下来复习回C/C++,或是学习一些规划中未来需要用到的非图形的内容,图形学方面的内容断断续续地学习。


所以我之前学习图形学是直接跳过OpenGL或是DirectX的。

现在需要学习OpenGL,然后大量资料的代码、工程都是C/C++、VS的。所以我决定还是复习会C/C++。

因为复习了C/C++,我又去学习了解了:CMake、汇编(只是了解,没系统学)、和栈帧功能。

当时感觉还不满足,所以我又去买了《程序员的自我修养》- 俞甲子、石凡、潘爱民著的。
(此书我断断续续读了好几天,接触了之前没了解的内容,还是收获不断的)


顺便说说: 图形学 的内容是 不会过时 的,因为用计算机模拟不了另一个完整的虚拟世界,完整的模拟这个现实世界的内容,与重新创建一个真实的世界没有什么区别,可想而知难度有多大,能做出来,你就是神 一样的存在,所以需要用取巧的、看起来像的方法来快速的替代显示。

可以看出:图形学中,不需要是否与现实生活中的物理、原理一致,只要最终肉眼看起来效果像是对的,那么就是对的。

除非说,我们用另一种方式来替代图形学,让人可以不用肉眼看都可以知道图像信息 ---- 脑电波的生物电信号控制

那个时候就不叫图形学了,应该叫:人类脑电波生物电信号学科

因为我们用肉眼 (眼球接收了光子信息) 到的光子转为生物电信号,再通过神经传到了大脑,大脑根据每个 传感器 的位置接收的信号转换为一幅 图像

所以,如果我们只要实现一个设备,此传感器设备可替代眼球接收光子信息,并编码为脑电波生物电信号,并连接到大脑,将生物电信号传到大脑。那么这个设备即可替代眼睛。
(想象一下,如果还可以将:人类的七情六欲、各种感官的生物电信号模拟后都编码传到大脑,那就和:《黑客帝国》、《刀剑神域》里的世界一样了,但这是非常危险的,因为控制不好,或是可以控制到某种程度的时候,即可以控制一个人的脑死亡)


那么就不废话了,开始记录学习OpenGL的笔记吧。(没什么技术含量,都是搬运内容)

下面是在Window上使用VS2019构建GLFW的静态库提供给自己的OpenGL工程使用引发的一系列步骤,笔记尽量详细,详细到小白都可看懂。


GLFW

GLFW是国外的一个开源项目,它提供了OpenGL窗体交互封装。
对于学习OpenGL的同学,就不需要过多学习操作系统如何构架窗体的内容了。

GLFW 官网:https://www.glfw.org/

进去官网后点击:Download就好,提供了源码与预编译好的二进制文件。

但这里建议选择源码的,因为作为一个库项目,不同的操作系统,不同的编译器出来的预编译库文件,都会不兼容。

所以下载源码包:Source Package 就好,或是点击GitHub下载提供的仓库
在这里插入图片描述

下载好的GLFW我们最终需要的是:

  • include 目录 里的头文件
  • 编译出来的 glfw3.lib静态库文件

后面会详细讲到怎么用。


CMake

之前查阅了一些关于CMake的资料,了解了为何会有这个CMake的存在。然后看了一下相关资料(下面的资料)

CMake 入门学习:

发现CMake学习成本不低,但如果要制作一些跨平台工程的话,学习它还是很有必要的。

但是,这里我就不深入学习了,了解最简单的使用就好了。

好在:GLFW GitHub上的工程里也提供 CMake的相关构建资料。
在下载好的GLFW,解压打开,你会开到有个:CMakeList.txt
在这里插入图片描述

此文件正式CMake需要构建工程用的。

首先得去下载CMake,我这里用的是Window版的。

在这里插入图片描述
所以我就直接下载Windows 64位安装包的
在这里插入图片描述

为了简单起见,使用CMake GUI(也有Command Line的)。
在这里插入图片描述

启动后界面长这样:
在这里插入图片描述

只需要关注:Where is source Code与:Where to build the binaries即可。

  • Where is source Code : 是源码目标,准确的说是:带有CMakeList.txt 的源码目录。
  • Where to build the binaries : CMake 会将构建出来的工程导出到 “Where to build the binaries” 对应所在的目标。

为了GLFW GitHub工程保持原有干净。

所以新建一个 build 目录,专门存放导出来的工程内容。
在这里插入图片描述

设置好两个目录。
在这里插入图片描述

点击“Configure”按钮。

在这里插入图片描述
第一次点击,会弹出一个向导界面
在这里插入图片描述

Visual Studio 选择2019(这里按自己需要选择)。
下面列出所有的CMake 3.17.2 可以生成的Project类型有:
在这里插入图片描述

然后VS工程构建平台选择:Win32 即可。
在这里插入图片描述
选择好 Win32 后,点击“Finish”按钮后会看到下面的CMake的检测日志信息。
在这里插入图片描述

这时在点击 “Generate” 按钮。
在这里插入图片描述
没什么意外的话,就可以看到:Generating done 的日志提示。

此时,意味着VS2019的GLFW源码工程构建好了,并导出到刚刚上面设置的build目录了。

build目录下的内容如下:
在这里插入图片描述
xxx.sln 看着眼熟,就是VS的解决方案文件。


Building GLFW

有了GLFW的VS解决方案,接着就是打开构建好工程,得到.lib静态链接库就完事了。

鼠标右键 GLFW.sln->打开方式->Microsoft Visual Studio 2019(这里选择你刚刚CMake选择的构建版本)
在这里插入图片描述

打开解决方案后,再解决方案鼠标右键->生成解决方案
在这里插入图片描述

查看glfw构建的目录

在这里插入图片描述
在这里插入图片描述
这样后续我们的OpenGL学习工程上就可以链接此静态库文件了。(上面我导出的是Debug版本的,你也可以到处Release的)

此外,GLFW解决方案中提供了多个测试用例(Examples、Tests)项目,方便使用者更快了解如何使用。

每个测试用例都可以“设置为启动项”后,再运行即可查看效果。
在这里插入图片描述

如果你查看了官方的GLFW开源项目的 测试用例的源码,你会看到到处都有#include <glad/gl.h>之类的包含处理(注意:GLFW设置了 系统包含文件的目录 添加了 glad 的,所以使用的是<>尖括号,后面我自己的OpenGL学习工程将glad放在的是 用户附加包含目录,所以使用的是""双引号来包含,如:#include"glad/gl.h")。


GLAD

上面#include <glad/gl.h>有提到GLAD,GLAD的简介:GL/GLES/EGL/GLX/WGL Loader-Generator based on the official specs.

就是提供了对GL/GLES/EGL/GLX/WGL的官方规范的函数装载,与枚举的声明头文件。

它就是提供了一个对C语言的OpenGL库的函数原型对外的声明。除了函数原型声明,还有大量的OpenGL状态值(枚举值)的定义。

这样就不用我们手动的一个一个对C语言编写的OpenGL库来装载函数了。

GLAD的GitHub仓库,它是一个Web服务,提供了Web HMTL界面供用户选择需要的,界面如下:
在这里插入图片描述

需要的选项:

  • Language : C/C++
  • Specification : OpenGL
  • API : gl : version 4.5(这里之所以选择 4.5,是因为我的计算机目前最高支持 4.5,其实可以更新到4.6,但是没有必要,因为手头上学习资料只有 4.5 的,我之前选择 4.6 的有些API都删减了,如:glCreateVertexArray在4.5是有的,在4.6就没有了,如果你想与References 问题提到的版本来学习就选择:3.3版。后面我在查阅文档时,发现其他版本的 OpenGL 是有 matrix state 的管理接口的,当是选了 4.5 就没了?其实不是,而是下面的 Profile 决定的
  • Profile : Core(如果选择 Core 核心的 Profile 那么有些为了兼容前面版本的 OpenGL 接口都会不存在,所以没什么意外,还是使用 Compatibility 兼容模式的 Profile 吧
  • Options : Generate a loader

确定好选项后,点击“GENERATE” 按钮
在这里插入图片描述

点击下载:glad.zip
可以看到glad.zip内文件结构如下:

glad.zip
	|
	+--->include
	|	|
	|	+--->glad
	|	|		|
	|	|		+--->glad.h
	|	+--->KHR
	|			|
	|			+--->khrplatform.h
	|		
	+--->src
		|
		+--->glad.c

在这里插入图片描述
可以看到有两个目录:

  • include : C++项目中需要包含的头文件
  • src : 项目中需要引用的源文件

OK,到了这里,我们已经有:

  • GLFW 提供了OpenGL需要的窗体交互功能和include头文件接口声明(前面有提到)。并且我们已经生成了glfw3.lib库文件。
  • GLAD 提供了对C语言编写的OpenGL库的各个函数原型定义、装载,还有OpenGL的各个状态值(枚举值的)定义。

那么接下来就可以为我们的项目可用了。

如果细心的同学,可能会发现,GLAD开源项目中使用的GLFW库的API,或是GLFW开源项目中使用的GLAD库的API,都与你下载的不一样,那是因为版本问题。而我的GLAD,GLFW开源库都可能与References中的教程不同,部分API需要自己调整一下就好了。

GLAD 2

上面使用的GLAD 1 版本的内容。

现在有GLAD 2的,也有在线 GLAD 2 BETA WEB 版的。

这个 GLAD 2我是在下载了 glfw 3.3.2 版本的源码版后,看到的 glad的头文件有描述,也有URL,才发现的。


Using GLFW、GLAD

接着我们用VS2019来创建自己的OpenGL 学习用的解决方案:

  • 项目类型:Console控制台的空项目
  • 解决方案 名称:LearnGL
  • 第一个项目:01_CreateWindow
  • 后下面项目:nn_xxxxxx的方式命名即可,nn是项目序号,xxxxxx是项目功能名称

创建好空项目后

我们在 LearnGL 同级目录创建一个“Dependencies”目录,就是依赖文件的文件夹。

Dependencies 放三个子目录:

  • Include : 包含的头文件
  • Lib : 静态库文件
  • Src : c/c++源文件

OK,现在的文件结构是这样子的

OpenGL_Studies
	|
   	+--->Dependencies
   	|		|
   	|		+--->Include // include 内的复制在这里
   	|		+--->Lib
   	|		+--->Src
   	+--->LearnGL

将之前的下载的GLFW的include都复制到Dependencies

// glfw-3.3.2 文件夹
glfw-3.3.2
	|
	+--->include
			|
			+--->GLFW // 将次文件夹复制到上面的Dependecies/Include下
					|
					+--->glfw3.h
					+--->glfw3native.h

复制到Dependencies

OpenGL_Studies
	|
   	+--->Dependencies
   	|		|
   	|		+--->Include
	|		|	|
	|		|	+--->GLFW // 新增
	|		|			|
	|		|			+--->glfw3.h // 新增
	|		|			+--->glfw3native.h // 新增
   	|		+--->Lib
   	|		+--->Src
   	+--->LearnGL

在将之前GLAD下载的zip压缩包里的include里面的内容也复制到Dependencies/Includesrc里面的内容也复制到Dependencies/Src

// glad 文件夹
glad
	|
	+--->include
	|		|
	|		+--->glad //  需要复制的文件夹
	|		|		|
	|		|		+--->glad.h
	|		+--->KHR //  需要复制的文件夹
	|				|
	|				+--->khrplatform.h
	+--->src
			|
			+--->glad.c //  需要复制的文件

复制后

OpenGL_Studies
	|
   	+--->Dependencies
   	|		|
   	|		+--->Include
	|		|	|
	|		|	+--->GLFW
	|		|	|		|
	|		|	|		+--->glfw3.h
	|		|	|		+--->glfw3native.h
	|		|	|
	|		|	+--->glad // 新增
	|		|	|		|
	|		|	|		+--->glad.h // 新增
	|		|	+--->KHR // 新增
	|		|			|
	|		|			+--->khrplatform.h // 新增
   	|		+--->Lib
   	|		+--->Src
	|				|
	|				+--->glad.c // 新增
   	+--->LearnGL

OK,然后在01_CreateWindow项目中配置:

  • VC++目录->包含目录 : Dependencies/Include
  • VC++目录->库目录 : Dependencies/Lib
  • 链接器->输入->附加依赖项:Dependencies/Lib/glfw3.lib
  • 添加引用源文件:Dependencies/Src/glad.c

包含目录、库目录如下图设置

在这里插入图片描述

另外,为了项目管理方便,或去你在别的电脑上下载了你这个项目,那么用 绝对路径 来设置这些 包含依赖 库的路径的话,会很麻烦,所以我们建议使用:相对路径,如下图:
在这里插入图片描述

链接器->输入->附加依赖项
在这里插入图片描述


其实 我们下载的 glfw中,我下载的是3.3.2版本的,在 glfw-3.3.2\deps 目录下,其实glfw还提供了其他很多的工具类,供用户使用。
如果你需要,也可以在 C/C++->常规->附加包含目录 中添加 glfw-3.3.2\deps 目录就可以了,这是可选的,如果不需要可以不用添加,因为这里面都是一些工具类。我们也可以按需要将需要的文件复制到我们上面提到的 Dependencies

depsdependencies 的缩写
在这里插入图片描述
下面是 glfw 的 simple 项目例子的配置
在这里插入图片描述

而我的测试项目需要用到linmath.h,所以我将它复制到我的 Dependencies 目录上了。目录就变成了:

OpenGL_Studies
	|
   	+--->Dependencies
   	|		|
   	|		+--->Include
	|		|	|
	|		|	+--->GLFW
	|		|	|		|
	|		|	|		+--->glfw3.h
	|		|	|		+--->glfw3native.h
	|		|	|
	|		|	+--->glad
	|		|	|		|
	|		|	|		+--->glad.h
	|		|	+--->KHR
	|		|	|		|
	|		|	|		+--->khrplatform.h
	|		|	+--->linmath.h // 新增
   	|		+--->Lib
   	|		+--->Src
	|				|
	|				+--->glad.c
   	+--->LearnGL

最后是:添加引用源文件:Dependencies/Src/glad.c
对准源文件,鼠标右键:添加->现有项…,选择Dependencies/Src/glad.c文件
在这里插入图片描述
给源文件添加一个一个“C++文件”,命名为:Main.cpp

Main.cpp填入下列代码:

// jave.lin
#include"glad/glad.h"
#include"GLFW/glfw3.h"
#include<iostream>

static void error_callback(int error, const char* description)
{
	fprintf(stderr, "ErrorCode : %d, Error: %s\n", error, description);
}

static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
	// jave.lin : 当键盘按键ESCAPE按下时,设置该window为:需要关闭
	if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
		glfwSetWindowShouldClose(window, GLFW_TRUE);
}

int main() {
	// jave.lin : 安装glfw内部错误时的回调
	glfwSetErrorCallback(error_callback);

	// jave.lin : 初始化glfw
	if (!glfwInit())
	{ // jave.lin : 初始化失败
		std::cout << "glfwInit FAILURE" << std::endl;
		exit(EXIT_FAILURE);
	}
	// jave.lin : 设置最低的openGL 版本,major:主版本号,minor:次版本号
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
	// jave.lin : Profile使用CORE
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

	int width = 600;
	int height = 300;

	// jave.lin : 使用glfw创建窗体
	GLFWwindow* window = glfwCreateWindow(width, height, "jave.lin - Learning OpenGL - 01 CreateWindow", NULL, NULL);
	if (window == NULL)
	{ // jave.lin : 构建窗体失败
		std::cout << "Failed to create GLFW window" << std::endl;
		glfwTerminate();
		exit(EXIT_FAILURE);
	}
	glfwMakeContextCurrent(window);
	// jave.lin : 安装glfw内部键盘按键的回调
	glfwSetKeyCallback(window, key_callback);

	// jave.lin : 装载OpenGL的C函数库
	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
	{ // jave.lin : 装载报错
		std::cout << "Failed to initialize OpenGL context" << std::endl;
		glfwTerminate();
		exit(EXIT_FAILURE);
	}

	// jave.lin : 检测是否需要关闭窗体
	while (!glfwWindowShouldClose(window))
	{

		// jave.lin : 处理其他的系统消息
		glfwPollEvents();
	}

	// jave.lin : 销毁之前创建的window对象
	glfwDestroyWindow(window);

	// jave.lin : 清理glfw之前申请的资源
	glfwTerminate();

	return 0;
}

在此,我们运行看看效果
在这里插入图片描述

第一个窗口终于出现了

到此为止,我们还没有使用到OpenGL 的功能,上面都只是用glfwCreateWindow到GLFW来构建窗体。
还有gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)载入OpenGL的C函数库的API。

那么我们就先添加一个:glClearColor的功能吧,清理FrameBuffer的ColorBuffer,并清除为红色,最简单的了。
给while循环内添加一些代码


	// jave.lin : 检测是否需要关闭窗体
	while (!glfwWindowShouldClose(window))
	{
		// jave.lin : 获取窗口大小
		glfwGetFramebufferSize(window, &width, &height);

		// jave.lin : 设置Viewport
		glViewport(0, 0, width, height);
		glClearColor(1.f, 0.f, 0.f, 1.f);
		glClear(GL_COLOR_BUFFER_BIT);
		glfwSwapBuffers(window);

		// jave.lin : 处理其他的系统消息
		glfwPollEvents();
	}

最后运行效果如下图:
在这里插入图片描述

OpenGL Extensions Viewer

在上面的实例代码中,有这么一段:

	// jave.lin : 设置最低的openGL 版本,major:主版本号,minor:次版本号
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);

上面这段代码中,major、minor也可以不用设置,默认会使用你的计算机上 OpenGL 最高可用的版本。

这句话意思,我想要外界运行这个程序,需要至少支持4.5或以上的OpenGL版本的。

这里测试用,所以我设置为OpenGL 4.5(目前最新的OpenGL 是4.6版本)。

一般为按需求来设置,如设置为OpenGL 2.0,就意思需要外部运行机器需要至少有OpenGL 2.0支持的版本才能正常运行。

如果想要查看本机(Window OS)上的OpenGL 信息,可以使用:OpenGL Extensions Viewer

下载好安装后,运行界面长这样:

在我的笔记本上看到OpenGL 最高可支持版本为:4.5
在这里插入图片描述

除了OpenGL的信息,还可以查看到DX,Vulkan的
在这里插入图片描述

再看看我的笔记本的CPU芯片
在这里插入图片描述

光刻技术才:14 nm,现在手机都用上7 nm 或5nm了,3 nm的台积电都开始研发了。

3 nm 都差不多是物理极限了,所以图形学的模拟方法不会淘汰的,因为现实生活的内容,我在们图形学都只能模拟,不可能1比1全都按真实的来实现,真实生活中数据量无法比拟、无法量化的。

问题

	// jave.lin : 设置最低的openGL 版本,major:主版本号,minor:次版本号
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
	// jave.lin : Profile使用CORE
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

上面这段代码中,major、minor也可以不用设置,默认会使用你的计算机上 OpenGL 最高可用的版本。

后面那句设置 Profile 的,这里设置为 core Profile 的,目前有两中 profile:core (核心)与 compatibility (兼容)。

  • core 是3.3才开始有的第一版有 profile 区分的版本。使用了 core 版本后,注意后面使用 API 时,需要注意是否过时的(这里我还不知道怎么查,-_-!,因为我也没去下载 OpenGL 源码,用的都是,如果有同学知道的话,可以麻烦分享一下。)我现在这里选择了 core Profile,导致后续我使用 core Profile 时,绘制不出然后东西,着色器编译没有错误 与 着色器程序链接也没有错误。一切都没有任何错误提示,就是不显示内容,然后我将 Profile 改为下面的 compatibility 就好了,那意思我用了一些过时的API,但是没有报错。。。但 OpenGL 不绘制任何内容,这就很蛋疼了。
  • compatibility 是为了兼容以前3.3之前的过时 api 的。

关于 Context的Profile 可以查看这篇:OpenGL的Context(Profile)

总结

OpenGL、GLFW、GLAD如果以后再需要使用新的版本,都可以按照类似方式处理:

  • 找官方源码库
  • CMake 生成目标平台工程
  • 目标平台工程编译生成库
  • 自己项目工程再链接(静态或动态)这些编译好的库,在项目设置包含目标下添加开源库项目提供的头文件

References

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值