当前位置: 首页 > news >正文

【OpenGL学习】第2课:用OpenGL创建第一个窗口

仅自学做笔记用,后续有错误会更改

环境搭建

  1. 搭建流程参考文章:
    https://learnopengl-cn.github.io/01%20Getting%20started/02%20Creating%20a%20window/

  2. GLFW库

  • 什么是GLFW: GLFW是一个专门针对OpenGL的C语言库,它提供了一些渲染物体所需的最低限度的接口。它允许用户创建OpenGL上下文、定义窗口参数以及处理用户输入,对我们来说这就够了。(最流行的几个库有GLUT,SDL,SFML和GLFW)
  • GLFW库概括:一个轻量级的库,负责处理窗口创建、鼠标 / 键盘事件、上下文管理等与操作系统交互的工作(OpenGL 本身不处理窗口,必须依赖这类库)。
  • 下载链接:https://www.glfw.org/download.html
  • 编译: 最好是下载源码自己去编译,这样才能匹配你的系统。编译过后,我们需要的文件就是glfw3.lib和库的include文件。
  • 库的链接这里不多作描述,跟其他第三方库的链接是一致的。
  1. GLAD库
  • 什么是GLAD:因为OpenGL只是一个标准/规范,具体的实现是由驱动开发商针对特定显卡实现的。由于OpenGL驱动版本众多,它大多数函数的位置都无法在编译时确定下来,需要在运行时查询。所以任务就落在了开发者身上,开发者需要在运行时获取函数地址并将其保存在一个函数指针中供以后使用。取得地址的方法因平台而异,在Windows上会是类似这样(你可以看到代码非常复杂,而且很繁琐,我们需要对每个可能使用的函数都要重复这个过程。幸运的是,有些库能简化此过程,其中GLAD是目前最新,也是最流行的库。):
// 定义函数原型
typedef void (*GL_GENBUFFERS) (GLsizei, GLuint*);
// 找到正确的函数并赋值给函数指针
GL_GENBUFFERS glGenBuffers  = (GL_GENBUFFERS)wglGetProcAddress("glGenBuffers");
// 现在函数可以被正常调用了
GLuint buffer;
glGenBuffers(1, &buffer);
  • GLAD库的作用概括:OpenGL 没有统一的函数加载方式(不同系统 / 显卡实现不同),GLAD 用于自动加载当前系统支持的 OpenGL 函数指针,是使用 OpenGL 的前提。

  • 配置GLAD库:GLAD是一个开源的库,它能解决我们上面提到的那个繁琐的问题。GLAD的配置与大多数的开源库有些许的不同,GLAD使用了一个在线服务。在这里我们能够告诉GLAD需要定义的OpenGL版本,并且根据这个版本加载所有相关的OpenGL函数。
    打开GLAD的在线服务,将语言(Language)设置为C/C++,在API选项中,选择3.4以上的OpenGL(gl)版本(我们的教程中将使用3.4版本,但更新的版本也能用)。之后将模式(Profile)设置为Core,并且保证选中了生成加载器(Generate a loader)选项。现在可以先(暂时)忽略扩展(Extensions)中的内容。都选择完之后,点击生成(Generate)按钮来生成库文件。
    GLAD现在应该提供给你了一个zip压缩文件,包含两个头文件目录,和一个glad.c文件。将两个头文件目录(glad和KHR)复制到你的Include文件夹中(或者增加一个额外的项目指向这些目录),并添加glad.c文件到你的工程中。

代码

  • 这里给出一个GLFW+GLAD显示一个窗口的示例
#include <glad/glad.h> 
#include <GLFW/glfw3.h>
#include <cstdio>
#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初始化glfwInit();glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__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);// GLAD:加载所有OpenGL函数指针if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){std::cout << "Failed to initialize GLAD" << std::endl;return -1;}// 渲染循环while (!glfwWindowShouldClose(window)){// 检查用户输入processInput(window);// 渲染指令(这里暂时把窗口渲染为蓝绿色,类似黑板)glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);// GLFW:交换颜色缓冲(双缓冲机制)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)
{// 确认视口与新窗口尺寸匹配;注意,在视网膜显示器上,宽度和高度将显著大于指定值。// 高度和宽度会根据你的显示器分辨率进行调整glViewport(0, 0, width, height);
}

代码解析

  • main函数(入口) 核心流程解析
      1. GLFW 初始化与窗口属性设置
// 初始化GLFW库(必须第一步,否则后续GLFW函数无法使用)
glfwInit();
// 设置窗口相关的"提示参数"(告诉GLFW我们需要什么样的窗口)
// 指定OpenGL版本为3.4(主版本号3,次版本号4)
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4);
// 指定使用"核心模式"(Core Profile):只包含现代OpenGL特性,移除旧版冗余功能
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// 苹果系统特殊处理:苹果的OpenGL实现需要开启向前兼容模式
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif

glfwWindowHint:用于配置后续创建的窗口属性,参数是 “键 - 值” 对。
例如:GLFW_CONTEXT_VERSION_MAJOR指定 OpenGL 主版本,3表示我们要使用 OpenGL 3.x。
核心模式(Core Profile):是现代 OpenGL 的推荐用法,避免使用已废弃的函数,减少兼容性问题。

      1. 创建窗口与上下文绑定
// 创建窗口:参数依次为宽、高、窗口标题、全屏显示的显示器(NULL表示窗口模式)、共享上下文(NULL表示不共享)
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);// 检查窗口是否创建成功(失败可能因显卡不支持OpenGL 3.3或系统资源不足)
if (window == NULL)
{std::cout << "Failed to create GLFW window" << std::endl;glfwTerminate();  // 失败则释放GLFW资源return -1;
}// 将窗口的OpenGL上下文设置为当前线程的"主上下文"
// (OpenGL需要一个"上下文"来存储状态,所有OpenGL操作都基于当前上下文)
glfwMakeContextCurrent(window);// 设置窗口大小变化时的回调函数:当窗口被拉伸/缩放时,自动调用framebuffer_size_callback
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

OpenGL 上下文:可以理解为 OpenGL 的 “工作环境”,存储了所有状态(如当前绑定的对象、渲染设置等)。
一个窗口对应一个上下文,必须通过glfwMakeContextCurrent将其设为当前上下文,后续 OpenGL 函数才能生效。
回调函数:glfwSetFramebufferSizeCallback注册一个函数,当窗口大小改变时,GLFW 会自动调用这个函数,我们可以在其中处理渲染区域的适配。

      1. 初始化 GLAD(加载 OpenGL 函数)
// 初始化GLAD:通过GLFW提供的glfwGetProcAddress获取系统的OpenGL函数地址
// (GLAD需要知道如何加载函数,GLFW的这个函数可以帮我们做到)
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{std::cout << "Failed to initialize GLAD" << std::endl;return -1;
}

关键作用:OpenGL 函数在编译时无法确定地址(不同系统 / 显卡实现不同),必须在运行时动态加载。
GLAD 通过gladLoadGLLoader自动完成这个过程,加载成功后才能调用glClear等 OpenGL 函数。

      1. 渲染循环(程序主循环)
// 渲染循环:只要窗口没有被要求关闭(点击关闭按钮或代码触发),就一直循环
while (!glfwWindowShouldClose(window))
{// 1. 处理用户输入(如键盘、鼠标)processInput(window);// 2. 渲染指令:这里简单渲染一个背景色// 设置清除颜色(RGBA格式,范围0.0-1.0):这里是深青灰色(0.2红, 0.3绿, 0.3蓝, 1.0透明)glClearColor(0.2f, 0.3f, 0.3f, 1.0f);// 用上面设置的颜色清除"颜色缓冲"(OpenGL的渲染结果先存在缓冲中,而不是直接显示)glClear(GL_COLOR_BUFFER_BIT);// 3. 交换缓冲并处理事件// 交换前后缓冲(双缓冲机制:前缓冲显示,后缓冲绘制,交换后避免画面闪烁)glfwSwapBuffers(window);// 处理所有待处理的事件(如鼠标移动、按键按下),并触发对应的回调函数glfwPollEvents();
}

渲染循环:是图形程序的核心,确保窗口持续显示并响应交互。
循环条件!glfwWindowShouldClose(window)表示:只要窗口没有被标记为 “应该关闭”,就一直运行。
双缓冲机制: OpenGL 渲染时,结果先画在 “后缓冲”(不可见),完成后通过glfwSwapBuffers与 “前缓冲”(可见)交换,避免绘制过程中画面闪烁(如果直接画在可见缓冲,用户会看到半成品)。
glClear(GL_COLOR_BUFFER_BIT):清除颜色缓冲(用glClearColor设置的颜色填充),相当于 “刷新画布”。

      1. 程序退出清理
// 释放GLFW分配的所有资源(窗口、上下文等),避免内存泄漏
glfwTerminate();
return 0;
http://www.dtcms.com/a/578057.html

相关文章:

  • Redis单线程还是多线程?
  • 做网站现在用什么语言网站做优化的好处
  • 做网站需要什么知识wdcp 快速迁移网站
  • 《uni-app 长列表优化:虚拟列表(vue-virtual-scroller)解决 1000+ 数据渲染卡顿》(附虚拟列表封装与多端适配)
  • uniapp在app中如何将json以文件格式存到本地(vue3)
  • uniapp开源ERP多仓库管理系统
  • Qt GUI 程序中进度条的完整指南
  • 网站添加广告源码wordpress和druid
  • 推出 JxBrowser MCP 服务器
  • Etcd详解(raft算法保证强一致性)
  • 东莞网站建设对比建筑模板有几种
  • AIShareTxt入门:快速准确高效的为金融决策智能体提供股票技术指标上下文
  • 赋能智慧监管:视频汇聚平台EasyCVR助力智慧电梯监控智能化监管
  • 【银行测试】对公渠道转账+网银转账+对私转账功能测试点(汇总)
  • 2013年建设工程发布网站字形分析网站
  • 高端网站制作系统百度指数怎么看城市
  • 网站搜索排名查询余姚物流做网站
  • langchain agent的中间件
  • Mysql中隔离级别可重复读解决不可重复读的底层原理是什么?
  • MySQL的DATE_FORMAT函数介绍
  • 涞水县建设局网站电子商务网站建设哪本教材比较适合中等专业学校用
  • 建阳网站建设wordpress手机验证码注册
  • C4D服装建模实战:纽扣、嵌条与拉链工具使用详解
  • Shell高手必备:30字搞定XML注释过滤
  • 律师网站建设哪家好软文范文
  • C++编译期间验证单个对象可以被释放、验证数组可以被释放和验证函数对象能否被指定类型参数调用
  • 机器学习训练过程中的回调函数BaseCallback
  • Cordys CRM正式开源,AI驱动客户关系管理加速演进
  • 河北省 建设执业注册中心网站长沙 汽车 网站建设
  • 手机如何定位:从时间差到地图上的“小蓝点”