初始图形API

图形API是软件与硬件沟通的桥梁,提供了一系列可以操作图形、图像的函数。现在常用的图形API有OpenGL、DirectX、Vulkan,其中DX仅支持Windows平台,而OpenGL和Vulkan都是跨平台的图形API,可以支持IOS系统、安卓系统等。随着时代的进步,OpenGL的使用正在逐渐减少,未来Vulkan是更好的发展方向。

不过严格来说,OpenGL本身并不是一个API,它仅仅是一个由Khronos组织制定并维护的规范(Specification)。具体来说,你不太可能找到一个OpenGL的函数的具体实现。因为这些函数的具体实现是由硬件厂商(如AMD、Nvidia、微星等)来做的,他们只是根据OpenGL制定的规范针对他们各家的硬件来完成具体的实现。所以OpenGL函数的具体实现方式与你的电脑GPU品牌型号有关。

初识OpenGL

核心模式和立即渲染模式

  • OpenGL3.2前:使用立即渲染模式(Immediate mode,固定渲染模式),绘图方便,自由度低
  • OpenGL3.2后:使用核心模式(Core-profile),绘图相对麻烦,自由度高

拓展

对显卡新特性的支持。当一个显卡公司提出一个新特性或者渲染上的大优化,通常会以扩展的方式在驱动中实现。
如:

1
2
3
4
5
6
7
8
if(GL_ARB_extension_name)
{
// 使用硬件支持的全新的现代特性
}
else
{
// 不支持此扩展: 用旧的方式去做
}

状态机

OpenGL本身就是一个状态机,OpenGL的状态通常被称为上下文(Context)
例如,更改OpenGL的状态:设置选项,操作缓冲,使用当前上下文进行渲染。

对象

OpenGL的抽象层中的一个。指一些选项的集合,代表OpenGL状态的一个子集。比如,可以用一个对象表示绘图窗口的设置,用于设置大小、颜色位数等。

了解OpenGL的库

GLUT

早期版本的库文件,freeglut是开源版本的glut。glut/freeglut主要包含OpenGL 1.0的基本函数功能
(包括窗口操作函数,窗口初始化、窗口大小、窗口位置等函数;
回调函数:响应刷新消息、键盘消息、鼠标消息、定时器函数等;
创建复杂的三维物体;
菜单函数;程序运行函数)。

GLEW

使用OpenGL 2.0后的一个工具函数,用来查找OpenGL函数的实现,并初始化。

GLFW

跨平台的OpenGL库,支持OpenGL、OpenGL ES、Vulkan。用于管理窗口、读取输入、处理事件。

GLAD

最新的OpenGL接口第三方库,glew的升级版。

配置环境并绘制窗口

配置环境

网上的教程挺多的,遂不再赘述。可以回顾LearnOpenGL

绘制窗口

代码如下,这里用的glfw和glad:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82

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();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_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);

// render
// ------
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)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
}

// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
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);
}