持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第7天,点击查看活动详情。
一、准备
1.1. 依赖工具的安装
- homebrew
- cmake
1.2. 相关库安装
- GLFW
- 允许用户创建OpenGL上下文、定义窗口参数以及处理用户输入
- GLAD
二、入门
2.1. OpenGL
OpenGL一般它被认为是一个API(Application Programming Interface, 应用程序编程接口),包含了一系列可以操作图形、图像的函数。然而,OpenGL本身并不是一个API,它仅仅是一个由Khronos组织制定并维护的规范(Specification)。
如果有需要OpenGL API Specification 这里可以找到不同版本的OpenGL的规范。
所学习教程 面向OpenGL3.3的核心模式。所有OpenGL的更高的版本都是在3.3的基础上,引入了额外的功能,并没有改动核心架构。
2.1.1. 核心模式与立即渲染模式
立即渲染模式(Immediate mode,也就是固定渲染管线) 核心模式(Core-profile)
2.1.2. 扩展
开发者只需检查显卡是否支持某扩展,就可以根据需求完成新的渲染特性。
if(GL_ARB_extension_name)
{
// 使用硬件支持的全新的现代特性
}
else
{
// 不支持此扩展: 用旧的方式去做
}
2.1.3. 状态机
OpenGL的状态通常被称为OpenGL上下文(Context)。
我们通常使用如下途径去更改OpenGL状态:
- 设置选项
- 操作缓冲
- 使用当前OpenGL上下文来渲染 上述过程会使用到
- 状态设置函数(State-changing Function),这类函数将会改变上下文。
- 状态使用函数(State-using Function),这类函数会根据当前OpenGL的状态执行一些操作。
2.1.4. 对象
是指一些选项的集合,它代表OpenGL状态的一个子集。比如,我们可以用一个对象来代表绘图窗口的设置,之后我们就可以设置它的大小、支持的颜色位数等等。
// OpenGL的状态
struct OpenGL_Context {
...
object* object_Window_Target;
...
};
// 创建对象
unsigned int objectId = 0;
//用一个id保存它的引用(实际数据被储存在后台)
glGenObject(1, &objectId);
// 绑定对象至上下文,此处上下文的目标位置被定义成GL_WINDOW_TARGET
glBindObject(GL_WINDOW_TARGET, objectId);
// 设置当前绑定到 GL_WINDOW_TARGET 的对象的一些选项
glSetObjectOption(GL_WINDOW_TARGET, GL_OPTION_WINDOW_WIDTH, 800);
glSetObjectOption(GL_WINDOW_TARGET, GL_OPTION_WINDOW_HEIGHT, 600);
// 将上下文对象设回默认,即将目标位置的对象id设回0,解绑这个对象
glBindObject(GL_WINDOW_TARGET, 0);
2.2. 创建窗口(案例1)
创建一个OpenGL上下文(Context)和一个用于显示的窗口以及处理用户输入
2.2.1. 完成GLFW环境配置(for macOs)
-
获取 ,从官网下载GLFW源码,如下图所示
-
解压 ,解压 glfw-3.3.6.zip,得到glfw-3.3.6目录,并在glfw-3.3.6 目录下建立build目录
-
make ,打开已经安装的CMake,按下图所示选择对应的源文件,和编译后的目标位置。
【对于cmake的原理还不是很清晰,有空学习学习】 -
Configure,然后点击Configure,按图中指示操作。
-
-
Done,点击Done之后如下图所示
-
Configure,再次点击Configure,如图:
-
Generate,点击Generate,如图
-
编译, 在终端进入glfw-3.3.6/build目录,执行命令
make进行编译 -
安装编译, 执行
make install命令
2.2.2. 配置glad
- 配置,前往 在线服务 界面,按照下图配置 glad
- GENERATE,点击页面下方的 GENERATE
- 下载,点击GENERATE后,进入下载页面,下载glad.zip
- 解压&复制,解压 glad.zip,把include目录中的glad和KHR目录复制到/usr/local/include。不要删除src/glad.c,待添加到xcode项目里
2.2.3. 配置 xcode
-
新建,新建一个Common Line Tool App,打开xcode,点击file-new-project,按照下图选择
-
设置信息,设置 product name 等信息,选择下一步即可
-
头、库文件,设置头文件(Header Search Paths)和库文件(Library Search Paths)目录
将头文件和库文件路径分别填写在 Header Search Paths 和 Library Search Paths 这个之后,如下所示
-
添加 frameWorks,按照下图找到 Link Binary With Libraries,点击 “ + ” 按钮,添加相关 frameWorks。查找时可以使用快捷键command+shift+G,快速访问文件。
这里需要的其他的 framework 可根据下图名称自行搜索添加
-
添加glad.c,过程如图
在弹出的如下对话框中,点击 Options 按钮,选择刚才解压好的 glad.c 文件,完成配置。
2.2.4. 创建窗口
涉及函数
- glfwInit()
- glfwWindowHint(参数一, 参数二) 第一个参数,代表选项的名称,我们可以从很多以GLFW_开头的枚举值中选择; 第二个参数,接受一个整型,用来设置这个选项的值。 该函数的所有的选项以及对应的值都可以在 GLFW’s window handling 这里找到。我们需要告诉GLFW我们要使用的OpenGL版本是3.3,所以这里将主版本号(Major)和次版本号(Minor)都设为3,今后我们可以根据需要来对版本号进行设置。
- glfwCreateWindow(窗口宽度, 窗口长度, 窗口名称, NULL, NULL) 这个函数将会返回一个GLFWwindow对象,我们会在其它的GLFW操作中使用到。创建完窗口我们就可以通知GLFW将我们窗口的上下文设置为当前线程的主上下文了。
将以下代码复制到你的工程中,如果成功显示渲染窗口,则成功,目前还会有一些警告⚠️待处理。
//
// main.cpp
// Test001ShowWindow
//
// Created by GD on 2022/3/21.
//
#include <glad/glad.h>//GLAD的头文件包含了正确的OpenGL头文件(例如GL/gl.h)
#include <GLFW/glfw3.h>
#include <iostream>
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow *window);
// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
int main()
{
// glfw: initialize and configure
// ------------------------------
glfwInit();//初始化GLFW
//OpenGL版本是3.3,以下为设置方式
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//第一个参数代表选项的名称
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//第二个参数接受一个整型,用来设置第一个参数的值
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);//使用核心模式(Core-profile)
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
// glfw window creation
// --------------------
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
// glad: load all OpenGL function pointers
// ---------------------------------------
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
// render loop
// -----------
while (!glfwWindowShouldClose(window))
{
// input
// -----
processInput(window);
//渲染指令
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);//清空颜色缓冲
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
// -------------------------------------------------------------------------------
glfwSwapBuffers(window);//函数会交换颜色缓冲
glfwPollEvents();//函数检查有没有触发什么事件(比如键盘输入、鼠标移动等)、更新窗口状态,并调用对应的回调函数
}
// glfw: terminate, clearing all previously allocated GLFW resources.
// ------------------------------------------------------------------
glfwTerminate();//当渲染循环结束后我们需要正确释放/删除之前的分配的所有资源
return 0;
}
// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow *window)
{
// 在GLFW中实现一些输入控制,这里按下esc,渲染结束
if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);//函数在我们每次循环的开始前检查一次GLFW是否被要求退出,如果是的话该函数返回true然后渲染循环便结束了,之后为我们就可以关闭应用程序了
}
// glfw: whenever the window size changed (by OS or user resize) this callback function executes,对窗口注册一个回调函数,当用户改变窗口的大小的时候,视口也应该被调整
// 处理过的OpenGL坐标范围只为-1到1,因此我们事实上将(-1到1)范围内的坐标映射到(0, width)和(0, height) ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
// make sure the viewport matches the new window dimensions; note that width and
// height will be significantly larger than specified on retina displays.
glViewport(0, 0, width, height);
}
【参考资料】 本教程为参考博客 learnopengl.com/ 的学习实战教程。随着理解的不断加深,还会持续补充,欢迎大家一起探讨,批评指正。