【OpenGL学习】(一)创建窗口
文章目录
- 【OpenGL】(一)创建窗口
【OpenGL】(一)创建窗口
GLFW
OpenGL 本身只是一套图形渲染 API,不提供窗口创建、上下文管理或输入处理的功能。
GLFW 是一个支持创建窗口、处理键盘鼠标输入和管理 OpenGL 上下文的跨平台库。因此,可以将OpenGL 和GLFW结合使用。
注:除了 GLFW,OpenGL 也可以与其他 GUI 框架如 Qt、MFC、SDL 等结合使用,实现更复杂或平台特定的图形界面程序。
GLAD
OpenGL 是一个跨平台的图形 API,其函数并非直接由操作系统或编译器提供,而是通过显卡驱动动态加载。这些函数的地址需要你在程序运行时手动获取,例如:
// 定义一个函数指针类型 GLGENBUFFERSPROC,用于指向 glGenBuffers 函数。
typedef void (*GLGENBUFFERSPROC)(GLsizei, GLuint*);
// 使用 wglGetProcAddress 函数动态加载 OpenGL 的 glGenBuffers 函数。
GLGENBUFFERSPROC glGenBuffers = (GLGENBUFFERSPROC)wglGetProcAddress("glGenBuffers");
每一个函数你都得这么写,非常繁琐。
GLAD是一个OpenGL函数加载库,可以自动加载与指定OpenGL版本相关的所有函数指针,避免了繁琐的手动获取,让我们可以像普通函数一样直接调用它们。
示例:创建窗口
#include <glad/glad.h> // 用于加载 OpenGL 函数指针
#include <GLFW/glfw3.h> // 用于创建窗口和处理用户输入
#include <iostream>// 函数声明:窗口大小变化回调函数
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
// 函数声明:处理输入
void processInput(GLFWwindow* window);// 设置窗口宽高
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;int main()
{// 初始化 GLFW 库,并配置 OpenGL 版本glfwInit(); // 初始化 GLFWglfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // 要 OpenGL 3.xglfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); // 精确到 3.3 版本glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 使用现代核心功能,不兼容旧版#ifdef __APPLE__// 兼容 Mac OS 系统glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif// 创建 GLFW 窗口对象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); // 注册窗口尺寸改变的回调函数,告诉GLFW当窗口调整大小的时调用这个函数// 初始化 GLAD,加载所有 OpenGL 函数指针if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){std::cout << "Failed to initialize GLAD" << std::endl;return -1;}// 渲染循环while (!glfwWindowShouldClose(window)) // 如果窗口没有被关闭{// 处理输入processInput(window);glfwSwapBuffers(window); // 交换颜色缓冲区:把画好的图像展示到屏幕上glfwPollEvents(); // 从操作系统获取事件(键盘、鼠标、窗口变化等),并更新 GLFW 内部状态,或者触发用户注册的回调函数。}// 释放资源并退出glfwTerminate();return 0;
}// 处理输入
void processInput(GLFWwindow* window)
{// 当按下 ESC 键时关闭窗口if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)glfwSetWindowShouldClose(window, true); // 设置窗口应关闭标志
}// 窗口尺寸改变时调用的回调函数
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{// 设置视口大小,使其匹配新窗口尺寸// 注意:在高 DPI 显示屏上,实际像素尺寸可能比指定尺寸更大glViewport(0, 0, width, height);
}
颜色缓冲区
颜色缓冲区是帧缓冲区(Frame Buffer) 的一部分,它保存了当前窗口中每一个像素的颜色值。
当你在屏幕上绘制图形时,你的所有绘制操作(画三角形、贴纹理、光照等)其实都是先写入颜色缓冲区,最后才一次性展示在屏幕上。
OpenGL 中的默认帧缓冲区包括:
缓冲区 | 作用 |
---|---|
颜色缓冲区(Color Buffer) | 存储每个像素的颜色值(RGB 或 RGBA)。 |
深度缓冲区(Depth Buffer) | 存储每个像素的深度值(Z 值),用于深度测试。 |
模板缓冲区(Stencil Buffer) | 用于进行复杂的遮罩、裁剪操作。 |
OpenGL 默认使用双缓冲机制(Double Buffering),也就是有两个颜色缓冲区:
缓冲区 | 用途 |
---|---|
前缓冲区(Front Buffer) | 当前正在显示在屏幕上的图像 |
后缓冲区(Back Buffer) | 当前正在绘制的图像内容(你所有的渲染操作都写在这里) |
渲染流程大致如下:
- 你通过 OpenGL API 画东西 → 写入后缓冲区。
- 绘制完成后,调用
glfwSwapBuffers(window);
→ 前后缓冲区交换。 - 后缓冲区的图像变成可见,前缓冲区变成新的绘制目标。
这样就可以避免画面撕裂或闪烁,保证画面平滑流畅。
processInput()和glfwPollEvents()的关系
glfwPollEvents() | processInput() | |
---|---|---|
谁写的 | GLFW 提供的函数 | 你自己写的函数 |
属于哪一层 | 系统层(事件驱动层) | 应用层(行为控制层) |
作用 | 从操作系统获取输入事件(键盘、鼠标、窗口)并更新内部状态 | 基于 GLFW 状态判断执行逻辑,比如关闭窗口、移动物体 |
必须调用吗 | 是的,否则无法接收到新输入 | 可选,但你不写就不会响应用户行为 |
通常调用顺序 | 一般在主循环每帧末尾调用 | 一般在主循环每帧开始调用 |
是否处理输入行为 | 不处理输入逻辑,只更新状态 | 你写的行为处理代码(比如 ESC 退出)就在这里 |
参考:
https://learnopengl-cn.github.io/01%20Getting%20started/03%20Hello%20Window/