创建GLFW窗口,开启OpenGL之路

前言:本系列文章主要是一个学习笔记和总结,具体学习过程参考https://learnopengl-cn.github.io/这个网站的是学习OpenGL的一个很完美的新手教程。在这个部分系列中,我会以自己的理解详细描述每个函数、方法的使用,以及关键参数的解释。

注意!!!本系列属于C/C++系列的OpenGL学习,不是python。但是学习明白原理后,使用其他语言应用也是大同小异。

使用软件为Visual Studio 2022。

废话少说,开始学习!

GLFW和GLAD

OpenGL并不为我们提供一个用于绘制图像的窗口,它将这些操作抽象(Abstract)出去,交给其他组件完成。所以我们需要自己创建用于显示绘制图形的窗口,这就使用到了GLFW。当然可以使用其他的类似的库,在不同平台上你可以使用的库也不同。

OpenGL驱动版本很多,其内部的多数函数位置都无法在编译的时候确定下来,需要在运行的时候查询,过程复杂,但是使用GLAD库就可以简化这个过程。

 GLFW、GLAD配置参考https://blog.csdn.net/qq_41777179/article/details/138134059

下面我们来下载GLFW和GLAD,下载网址为:
GLAD下载地址:https://glad.dav1d.de/
GLFW下载地址:https://www.glfw.org/download.html

我们先来下载GLFW和GLAD:

下载完成后可以得到两个压缩包,解压得到:

这两个先放在一边,让我来使用Visual Studio 2022创建一个C++的控制台空项目

创建完成后,打开项目路径,在如下位置创建一个Linking文件夹,并在Linking文件夹内创建lib和include文件夹:

然后找到刚才解压的GLAD和glfw-3.4.bin.WIN64文件:
1、进入glfw-3.4.bin.WIN64文件夹内,选择合适的vc版本Visual Studio 2022就选lib-vc2022,然后将其复制到Linking/lib下,并改名为GLFW;
2、进入glfw-3.4.bin.WIN64文件夹内,将include下的GLFW复制到Linking/include下
3、进入GLAD文件夹内,将include下的glad和KHR复制到Linking/include下
4、进入GLAD文件夹内,将res复制到Linking/include下

用Visual Studio 2022打开刚才生成的空项目。

有两种简单的打开方法:
1、拖动项目文件下的.xln文件到Visual Studio 2022桌面图标上
2、打开VS2022后选择项目(曾经打开过)

打开后,找到左侧资源管理器中的文件项目,右击项目文件,点击属性:

选择VC++目录,修改包含目录,编辑为Linking/include文件夹所在位置:

同样修改库目录,将其改为Linking/lib文件夹所在位置,同上述一样。

随后选择链接器 -> 输入,添加两个附加依赖项:
1、GLFW\glfw3.lib
2、opengl32.lib(windows系统自带opengl库,x64也是opengl32.lib)

设置完后,选择两个位置为x64

然后需要添加现有项到项目:
1、项目路径\Linking\include\src\glad.c
2、项目路径\Linging\include\KHR\khrplatform.h

这样就配置完成了

程↗序↘,启→动↗!

#include <iostream>
#include <glad/glad.h>
#include <GLFW/glfw3.h>static float vertices[] = {-0.5f, -0.5f, 0.0f,0.5f, -0.5f, 0.0f,0.0f, 0.5f, 0.0f
};// 当用户改变窗口的大小的时候,视口也应该被调整。
void framebuffer_size_callback(GLFWwindow* window, int width, int height) {glViewport(0, 0, width, height);
}void registerFunction(GLFWwindow* window) {glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
}// 读取用户输入,当程序运行时,按下ESC时退出进程
void processInput(GLFWwindow* window) {if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {glfwSetWindowShouldClose(window, true);}
}GLFWwindow* windowInit() {// 实例化窗口// 初始化GLFWglfwInit();glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);// 创建一个窗口对象,参数:宽、高、名称、*、*,函数返回一个GLFWwindow对象GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL Window", NULL, NULL);if (window == NULL){std::cout << "Failed to create GLFW window" << std::endl;glfwTerminate();}// 通知GLFW将创建的窗口的上下文设置为当前线程的主上下文glfwMakeContextCurrent(window);// GLAD传入了用来加载系统相关的OpenGL函数指针地址的函数if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {std::cout << "Failed to initialize GLAD" << std::endl;}// 通知OpenGL渲染窗口的尺寸大小——视口(Viewport)glViewport(0, 0, 800, 600);return window;
}unsigned int VAOInit() {unsigned int VAO;glGenVertexArrays(1, &VAO);glBindVertexArray(VAO);return VAO;
}unsigned int VBOInit() {unsigned int VBO;glGenBuffers(1, &VBO);glBindBuffer(GL_ARRAY_BUFFER, VBO);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);// 设置顶点属性指针glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);glEnableVertexAttribArray(0);return VBO;
}unsigned int vertexShaderInit() {// 顶点着色器源文件const char* vertexShaderSource ="#version 330 core\n""layout(location = 0) in vec3 aPos;\n""void main(){gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0f);}\n";// 创建顶点着色器并编译unsigned int vertexShader;vertexShader = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);glCompileShader(vertexShader);// 返回顶点着色器对象return vertexShader;
}unsigned int fragmentShaderInit() {// 顶点着色器源文件const char* fragmentShaderSource ="#version 330 core\n""out vec4 FragColor;\n""void main(){FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);}\n";// 创建顶点着色器并编译unsigned int fragmentShader;fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);glCompileShader(fragmentShader);// 返回顶点着色器对象return fragmentShader;
}unsigned int shaderProgramInit() {// 初始化着色器和着色器程序unsigned int vertexShader = vertexShaderInit();unsigned int fragmentShader = fragmentShaderInit();unsigned int shaderProgram = glCreateProgram();// 将着色器附加到着色器程序上glAttachShader(shaderProgram, vertexShader);glAttachShader(shaderProgram, fragmentShader);// 链接到着色器程序glLinkProgram(shaderProgram);// 激活着色器程序glUseProgram(shaderProgram);// 链接完删除着色器对象glDeleteShader(vertexShader);glDeleteShader(fragmentShader);return shaderProgram;
}void render(unsigned int shaderProgram, unsigned int VAO) {// 设置清空颜色(重要!)glClearColor(0.2f, 0.3f, 0.3f, 1.0f);// 清空颜色缓冲区和深度缓冲区glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glUseProgram(shaderProgram);glBindVertexArray(VAO);glDrawArrays(GL_TRIANGLES, 0, 3);
}int main()
{GLFWwindow* window = windowInit();// 注册函数framebuffer_size_callback,告知GLFW当窗口调整大小时调用这个函数registerFunction(window);unsigned int VAO = VAOInit();unsigned int VBO = VBOInit();unsigned int shaderProgram = shaderProgramInit();// glfwWindowShouldClose函数在我们每次循环的开始前检查一次GLFW是否被要求退出while (!glfwWindowShouldClose(window)) {// 输入processInput(window);// 渲染指令render(shaderProgram, VAO);// 检查并调用事件,交换缓冲// glfwSwapBuffers函数会交换颜色缓冲glfwSwapBuffers(window);// glfwPollEvents函数检查有没有触发什么事件(比如键盘输入、鼠标移动等)、更新窗口状并调用对应的回调函数glfwPollEvents();}// 渲染循环结束后我们需要正确释放/删除之前的分配的所有资源。glfwTerminate();return 0;
}

后面章节会一一介绍其中的函数,及其作用,运行结果如下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/96401.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/96401.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

es通过分片迁移迁移解决磁盘不均匀问题

POST _cluster/reroute {"commands": [{"move": {"index": "xxx_detail","shard": 2,"from_node": "el8P9Ul","to_node": "4sDv-RD"}}] }查看迁移进程 GET _cat/shards?v查看磁盘…

c++打包pyd文件给Python使用调用函数

c打包pyd文件给Python使用调用函数C语言源码&#xff1a;simplemath.cpp代码&#xff1a;// // Created by ASFOR on 2025/9/11. // #include <pybind11/pybind11.h>namespace py pybind11;// 一个简单的加法函数 int add(int a, int b) {return a b; }// 一个简单的乘…

hadoop的api操作对象存储

一、获取文件或目录1. 获取某个目录下的文件// 必须的依赖 import org.apache.hadoop.conf.Configuration import org.apache.hadoop.fs.{FileSystem, LocatedFileStatus, Path, RemoteIterator}// 获取某个目录下的文件路径 def list_file(conf: Configuration, dir_path: Str…

《UE5_C++多人TPS完整教程》学习笔记52 ——《P53 FABRIK 算法(FABRIK IK)》

本文为B站系列教学视频 《UE5_C多人TPS完整教程》 —— 《P53 FABRIK 算法&#xff08;FABRIK IK&#xff09; 的学习笔记&#xff0c;该系列教学视频为计算机工程师、程序员、游戏开发者、作家&#xff08;Engineer, Programmer, Game Developer, Author&#xff09; Stephen …

HttpServletRequest vs ServletContext 全面解析

HttpServletRequest vs ServletContext 全面解析 一、 核心区别概览特性HttpServletRequest (请求对象)ServletContext (Servlet上下文/应用对象)作用域请求范围应用范围生命周期从客户端发出请求开始&#xff0c;到服务器返回响应结束。从Web应用启动&#xff08;部署&#xf…

Java后端工程师如何学AI

Java后端工程师如何学AI 目录 前言为什么Java后端工程师要学习AIAI学习路径规划基础知识体系实践项目建议学习资源推荐学习时间规划常见问题与解决方案职业发展建议总结 前言 随着人工智能技术的快速发展&#xff0c;AI已经不再是计算机科学专业的专属领域。作为Java后端工…

Django REST Framework 中 @action 装饰器详解

概述 action 装饰器是 Django REST Framework (DRF) 中 ViewSet 的一个核心功能&#xff0c;用于定义自定义路由方法。它允许开发者在标准的 CRUD 操作&#xff08;list、create、retrieve、update、destroy&#xff09;之外&#xff0c;创建符合特定业务需求的接口&#xff0c…

【重磅更新】RetroBoard 全面升级,让敏捷回顾更高效、更安全、更贴心!

​​​​​​​ ​​​​​​​ ​​​​​​​ ​​​​​​​ ​​​​​​​ ​​​​​​​ ​​​​​​​ ​​​​​​​ ​​​​​​​ ​​​​​​​ ​​​​​​​ ​​​​​​​…

中州养老:华为云设备管理接口开发全流程

需求分析点击同步数据时,要把华为云的数据拉取到我们的系统中对于新增设备操作,实际上这些参数与华为云产品我们添加设备时的参数是一样的表结构设计E-R图数据库字段接口分析对于设备中的数据,我们既要再IOT平台存储,又要在数据库中存储.之所以保存两份数据的原因:IOT平台中只是…

Llama-Factory微调Qwen2.5-VL从数据集制作到部署记录

Llama-Factory微调Qwen2.5-VL从数据集制作到部署记录 电脑环境配置&#xff1a; 1.ubuntu24 2.3090(24G) 3.Cuda12.9 一、数据集制作 我的数据集主要是对图像内容进行描述 1.Label-studio制作数据集 这是最原始的从零开始制作数据集的方法&#xff0c;不建议这样做&#xff01;…

【蓝桥杯真题67】C++数位和为偶数的数 第十五届蓝桥杯青少年创意编程大赛 算法思维 C++编程选拔赛真题解

C++数位和为偶数的数 第十五届蓝桥杯青少年创意编程大赛C++选拔赛真题 博主推荐 所有考级比赛学习相关资料合集【推荐收藏】 1、C++专栏 电子学会C++一级历年真题解析 电子学会C++二级历年真题解析

【计算机网络 | 第11篇】宽带接入技术及其发展历程

文章目录宽带接入技术详解数字传输系统技术演进早期电话网的传输技术演变数字传输系统技术演进&#xff1a;从碎片到统一宽带接入技术 ADSLADSL的基本原理与非对称特性DMT调制技术&#xff1a;多子信道并行传输ADSL接入网组成电话分离器的设计原理与优势ADSL的升级&#xff1a;…

(论文速读)SCSegamba:用于结构裂纹分割的轻量级结构感知视觉曼巴

论文题目&#xff1a;SCSegamba: Lightweight Structure-Aware Vision Mamba for Crack Segmentation in Structures&#xff08;用于结构裂纹分割的轻量级结构感知视觉曼巴&#xff09;会议&#xff1a;CVPR2025摘要&#xff1a;不同场景下的结构裂缝像素级分割仍然是一个相当…

《苏超风云》亮相时尚大赏,成短剧行业发展新风向

当男频短剧凭借《一品布衣》五天横扫10亿播放的数据宣告逆袭&#xff0c;短剧市场格局正经历深刻洗牌。风口之下&#xff0c;头条视听、中皋文旅、国内时尚视觉与短视频创作领域的头部厂牌“大湾视频”携手下场&#xff0c;打造精品男频短剧《苏超风云》&#xff0c;剑指2025年…

HTML5新年元旦网站源码

新年主题网站开发概述 本项目基于HTML5、CSS3与JavaScript技术栈&#xff0c;打造了一个功能丰富、交互体验流畅的新年主题网站&#xff0c;涵盖文化展示、互动娱乐与社交分享三大核心模块&#xff0c;通过现代化前端技术实现沉浸式节日氛围营造。 1.1、核心功能架构 网站采…

CentOS 7 下iscsi存储服务配置验证

一、环境说明 centos7服务器*2服务器ip&#xff1a;服务端10.10.10.186 客户端10.10.10.184服务端存储卷sda1提前关闭防火墙&#xff0c;或开放默认 iSCSI 使用 3260 端口 二、服务端&#xff08;Target&#xff09;配置 安装 iSCSI target 服务 yum install -y targetcli syst…

立即数、栈、汇编与C函数的调用

一、立即数在 ARM 架构中&#xff0c;立即数是指在指令中直接编码的常量值&#xff0c;而不是通过寄存器或内存引用的值立即数的特点编码限制&#xff1a;ARM指令是固定长度的&#xff08;32位&#xff09;&#xff0c;因此立即数不能占用太多位数。典型的算术和逻辑指令通常只…

贪心算法与动态规划:数学原理、实现与优化

贪心算法与动态规划&#xff1a;数学原理、实现与优化 引言&#xff1a;算法选择的本质 在计算机科学领域&#xff0c;算法选择的本质是对问题特征的数学建模与求解策略的匹配。贪心算法与动态规划作为两种经典的优化算法&#xff0c;分别在不同问题域展现出独特优势。本文将从…

Leetcode 刷题记录 21 —— 技巧

Leetcode 刷题记录 21 —— 技巧 本系列为笔者的 Leetcode 刷题记录&#xff0c;顺序为 Hot 100 题官方顺序&#xff0c;根据标签命名&#xff0c;记录笔者总结的做题思路&#xff0c;附部分代码解释和疑问解答&#xff0c;01~07为C语言&#xff0c;08及以后为Java语言&#xf…

Android Studio Meerkat | 2024.3.1 Gradle Tasks不展示

把这两个开关打开&#xff0c;然后刷新gradle文件