OpenGL 入门(一)— 创建窗口

文章目录

  • 前言
  • 创建一个窗口
    • 视口动态调整
    • 输入控制
    • 渲染
  • 完整代码

前言

关键词介绍:

  • OpenGL: 一个定义了函数布局和输出的图形API的正式规范。
  • GLFW:一个专门针对OpenGL的C语言库,它提供了一些渲染物体所需的最低限度的接口。它允许用户创建OpenGL上下文、定义窗口参数以及处理用户输入,对我们来说这就够了。
  • GLAD: 一个扩展加载库,用来为我们加载并设定所有OpenGL函数指针,从而让我们能够使用所有(现代)OpenGL函数。
  • 视口(Viewport): 我们需要渲染的窗口。

创建一个窗口

首先,引入头文件

#include <glad/glad.h>
#include <GLFW/glfw3.h>

接下来,实例化GLFW窗口:

    //初始化GLFWglfwInit();//配置GLFW  第一个参数代表选项的名称,我们可以从很多以GLFW_开头的枚举值中选择;//第二个参数接受一个整型,用来设置这个选项的值。glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);// glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);

注意:glfwWindowHint函数的第一个参数代表选项的名称,很多以GLFW_开头的枚举值中选择,该函数的所有的选项以及对应的值都可以在 GLFW’s window handling 这篇文档中找到,具体怎么用可以查看文档。

然后,我们创建一个窗口对象:

    //创建一个窗口对象GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);if(window == NULL){std::cout << "Failed to create GLFW window" << std::endl;//创建失败,终止程序glfwTerminate();return -1;}//将我们窗口的上下文设置为当前线程的主上下文glfwMakeContextCurrent(window);

这时候编译运行会闪烁一下,说明我们创建成功了,如果保持常显示,需要下一步操作:

    // 循环渲染while (!glfwWindowShouldClose(window)){// 检查并调用事件,交换缓冲glfwSwapBuffers(window);glfwPollEvents();}// 释放/删除之前的分配的所有资源glfwTerminate();
  • glfwWindowShouldClose函数:在我们每次循环的开始前检查一次GLFW是否被要求退出,如果是的话该函数返回true然后渲染循环便结束了,之后为我们就可以关闭应用程序了。
  • glfwPollEvents函数:检查有没有触发什么事件(比如键盘输入、鼠标移动等)、更新窗口状态,并调用对应的回调函数(可以通过回调方法手动设置)。
  • glfwSwapBuffers函数:会交换颜色缓冲(它是一个储存着GLFW窗口每一个像素颜色值的大缓冲),它在这一迭代中被用来绘制,并且将会作为输出显示在屏幕上。
  • glfwTerminate函数:当渲染循环结束后我们需要正确释放/删除之前的分配的所有资源。

到这里编译运行,就会出现窗口了。
完整代码:

#include <iostream>
#include <glad/glad.h>
#include <GLFW/glfw3.h>int main()
{// 初始化GLFWglfwInit();// 配置GLFW  第一个参数代表选项的名称,我们可以从很多以GLFW_开头的枚举值中选择;// 第二个参数接受一个整型,用来设置这个选项的值。glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);// glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);// 创建一个窗口对象GLFWwindow *window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);if (window == NULL){std::cout << "Failed to create GLFW window" << std::endl;// 创建失败,终止程序glfwTerminate();return -1;}// 将我们窗口的上下文设置为当前线程的主上下文glfwMakeContextCurrent(window);// 初始化GLAD,传入加载系统相关opengl函数指针的函数if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){std::cout << "Failed to initialize GLAD" << std::endl;// 初始化失败,终止程序return -1;}// 循环渲染while (!glfwWindowShouldClose(window)){// 检查并调用事件,交换缓冲glfwSwapBuffers(window);glfwPollEvents();}// 释放/删除之前的分配的所有资源glfwTerminate();std::cout << "Hello, World!" << std::endl;return 0;
}

在这里插入图片描述

当然,我们也可以参考官方完整代码做些功能扩展:

视口动态调整

在我们开始渲染之前还有一件重要的事情要做,我们必须告诉OpenGL渲染窗口的尺寸大小,即视口(Viewport),这样OpenGL才只能知道怎样根据窗口大小显示数据和坐标。我们可以通过调用glViewport函数来设置窗口的维度

glViewport(0, 0, 800, 600);

glViewport函数前两个参数控制窗口左下角的位置。第三个和第四个参数控制渲染窗口的宽度和高度(像素)。

当用户改变窗口的大小的时候,视口也应该被调整。我们可以对窗口注册一个回调函数(Callback Function),它会在每次窗口大小被调整的时候被调用。

...
// 窗口大小改变时调用
void framebuffer_size_callback(GLFWwindow *window, int width, int height);// settings 窗口宽高
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;int main()
{...// 设置窗口大小改变时的回调函数glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);...return 0;
}// 窗口大小改变时调用
void framebuffer_size_callback(GLFWwindow *window, int width, int height)
{// 设置窗口的维度glViewport(0, 0, width, height);
}

输入控制

使用GLFW的glfwGetKey函数,它需要一个窗口以及一个按键作为输入。这个函数将会返回这个按键是否正在被按下。我们将创建一个processInput函数来让所有的输入代码保持整洁。

// 窗口大小改变时调用...void processInput(GLFWwindow *window);int main()
{...// 循环渲染while (!glfwWindowShouldClose(window)){// 输入processInput(window);// 检查并调用事件,交换缓冲glfwSwapBuffers(window);glfwPollEvents();}...return 0;
}// 输入
void processInput(GLFWwindow *window)
{// 当用户按下esc键,我们设置window窗口的windowShouldClose属性为true// 关闭应用程序if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)glfwSetWindowShouldClose(window, true);
}

渲染

我们要把所有的渲染(Rendering)操作放到渲染循环中,因为我们想让这些渲染指令在每次渲染循环迭代的时候都能被执行。代码将会是这样的:

// 渲染循环
while(!glfwWindowShouldClose(window))
{// 输入processInput(window);// 渲染指令glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);// 检查并调用事件,交换缓冲glfwPollEvents();glfwSwapBuffers(window);
}

完整代码

#include <iostream>
#include <glad/glad.h>
#include <GLFW/glfw3.h>// 窗口大小改变时调用
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()
{// 初始化GLFWglfwInit();// 配置GLFW  第一个参数代表选项的名称,我们可以从很多以GLFW_开头的枚举值中选择;// 第二个参数接受一个整型,用来设置这个选项的值。glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);// glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);// 创建一个窗口对象GLFWwindow *window = glfwCreateWindow(800, 600, "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);// 检查并调用事件,交换缓冲glfwSwapBuffers(window);glfwPollEvents();}// 释放/删除之前的分配的所有资源glfwTerminate();std::cout << "Hello, World!" << std::endl;return 0;
}// 窗口大小改变时调用
void framebuffer_size_callback(GLFWwindow *window, int width, int height)
{// 设置窗口的维度glViewport(0, 0, width, height);
}// 输入
void processInput(GLFWwindow *window)
{// 当用户按下esc键,我们设置window窗口的windowShouldClose属性为true// 关闭应用程序if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)glfwSetWindowShouldClose(window, true);
}

编译之后,效果展示
在这里插入图片描述

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

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

相关文章

2024美赛数学建模思路 - 案例:最短时间生产计划安排

文章目录 0 赛题思路1 模型描述2 实例2.1 问题描述2.2 数学模型2.2.1 模型流程2.2.2 符号约定2.2.3 求解模型 2.3 相关代码2.4 模型求解结果 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 模型…

【doghead】2: 数据产生及pacing发送

默认采用fake的数据生产者 FakeDataProducer也可以读取h264文件生成:H264FileDataProducerUSE_FAKE_DATA_PRODUCER G:\CDN\BWE-DEV\Bifrost\worker\src\bifrost\bifrost_send_algorithm\bifrost_pacer.cpp FakeDataProducer 生产制造rtp包 ExperimentDumpData : 可用带宽、发…

【C/C++】详解程序环境和预处理(什么是程序环境?为什么要有程序环境?如何理解程序环境?)

目录 一、前言 二、 什么是程序环境&#xff1f; 三、 为什么要有程序环境&#xff1f; 四、如何理解程序环境&#xff1f; &#x1f34e; ANSI C 标准 &#x1f350; 翻译环境和执行环境 五、详解翻译环境和执行环境 &#x1f347;翻译环境&#xff08;重点&#xff01…

Vue3动态插入组件

一、使用<component>is实现动态组件插入 <component>&#xff1a;一个用于渲染动态组件或元素的“元组件”。 :is : 要渲染的实际组件&#xff0c;当 is 是字符串&#xff0c;它既可以是 HTML 标签名也可以是组件的注册名。 <script> import Foo from ./F…

3ds Max宣传片怎么提升渲染速度?从硬件升级到云渲染,全面提升你的渲染速度!

在3ds Max中&#xff0c;渲染是一项耗时的任务&#xff0c;尤其是对于大型场景和复杂的动画。然而&#xff0c;通过一些优化策略和技巧&#xff0c;你可以显著加速渲染过程。以下是一些建议和技巧&#xff0c;帮助你提高3ds Max的渲染速度&#xff1a; 1.升级硬件&#xff1a; …

51单片机内部的主要寄存器

51单片机内部的主要寄存器 51单片机&#xff08;8051系列&#xff09;内部包含一系列特殊功能寄存器&#xff08;SFRs&#xff09;&#xff0c;这些寄存器用于控制和管理单片机的各种硬件资源&#xff0c;包括定时器、中断系统、串行通信接口、并行输入输出端口等。以下是51单…

leetcode88合并两个有序数组

力扣&#xff08;LeetCode&#xff09;-合并两个有序数组 方法一 | 合并后排序 题目要求将两个有序数组合并并保证合并后的数组仍然有序。 观察题目可以看出&#xff0c;nums1的容量大小总是 mn&#xff0c;所以 nums2能够合并到 nums1中。 那就将 nums1中未赋值的地方赋上 …

AI Agents系列—— 探究大模型的推理能力,关于Chain-of-Thought的那些事儿

一、写在前面&#xff1a;关于AI Agents与CoT 本文是2023.07.24发表在同名公众号「陌北有棵树」上的一篇文章&#xff0c;个人观点是基础理论的学习现在仍是有必要的&#xff0c;所以搬运过来。 今天要读的论文是《Chain-of-Thought Prompting Elicits Reasoning in Large La…

ABAP SQL CDSView Entity中使用正则RegEx表达式(Regular Expressions)

1. 正则表达式测试程序 DEMO_REGEXDEMO_REGEX_TOY 2. ABAP SQL & CDSView Entity支持正则语法的场景 SQL函数语法作用执行逻辑返回类型CDS View EntitiesABAP SQLLIKE_REGEXPRLIKE_REGEXPR( PCRE pcre, VALUE sql_exp1[, CASE_SENSIT…

Ubuntu系统服务器安装宝塔面板,可一键部署幻兽帕鲁服务端且可调整游戏参数

本来腾讯云服务器&#xff08;Windows系统和Ubuntu系统&#xff09;的一键运行命令即可部署安装幻兽帕鲁功能&#xff0c;让很多多轻松搭建了自己专属的服务器&#xff0c;这也是腾讯云服务器远远甩开阿里云服务器和华为云服务器及其他品牌服务器的原因&#xff0c;没想到现在其…

Pycharm快捷键大全

Pycharm快捷键大全 同样适用于JetBrains全家桶的其他工具&#xff0c;例如IDEA。 <kbd></kbd>用于定义按键输入 快捷键操作Alt1打开左侧ProjectAlt3打开Find窗口Alt7打开file structure窗口Shift10快速运行ShiftShift打开搜索对话框&#xff0c;查找&#xff0c;…

ANN论文总结

本文主要是个人笔记&#xff0c;记录与存储相关的ANN工作&#xff0c;想着写都写了不如发出来与大家分享&#xff0c;大多写得比较简单有些稍微详细一点&#xff0c;内容仅供参考。 CognitiveSSD S. Liang, Y. Wang, Y. Lu, et al. Cognitive SSD: A Deep Learning Engine for…

原生图数据库实现原理解析

目录 前言1 实现原理&#xff1a;免索引邻接1.1 免索引邻接构建1.2 查询性能保障 2. 物理存储实现2.1 节点存储文件2.2 关系边存储文件2.3 属性数据的存储处理 3. RDF图模型和属性图模型的比较3.1 RDF图模型3.2 属性图模型 4. 查询语言比较4.1. SPARQL4.2 Cypher4.3 Gremlin4.4…

基于密码技术的身份认证——基于对称密码体制的身份认证

一、符号说明&#xff1a; A→B&#xff1a;表示通信实体A向通信实体B发送消息&#xff1b; Ek(x)&#xff1a;表示用认证双方共享的密钥K对x进行加密&#xff1b; Text1&#xff0c;Text2&#xff0c;……&#xff0c;Text n属于可选项&#xff1b; ||&#xff1a;表示比特…

由浅入深!一文5张图教你做性能测试~

&#x1f525; 交流讨论&#xff1a;欢迎加入我们一起学习&#xff01; &#x1f525; 资源分享&#xff1a;耗时200小时精选的「软件测试」资料包 &#x1f525; 教程推荐&#xff1a;火遍全网的《软件测试》教程 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1…

研究性学习背景

研究性学习是学生在教师指导下,从自然、社会和生活中选择和确定专题进行研究,并在研究过程中主动地获取知识、应用知识和解决问题的学习活动。是《普通高中课程方案(2017 年版 2020 年修订)》中“综合实践活动”的主要组成部分,是全体普通高中学生必须完成的国家必修课程,也…

【Web】CTFSHOW SQL注入刷题记录(上)

目录 无过滤注入 web171 web172 web173 web174 web175 时间盲注 写马 过滤注入 web176 web177 web178 web179 web180 web181-182 web183 web184 web185-186 web187 web188 web189 web190 布尔盲注 web191 web192 web193 web194 堆叠注入 web195 …

找出字符串中第一个匹配项的下标

给你两个字符串 haystack 和 needle &#xff0c;请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标&#xff08;下标从 0 开始&#xff09;。如果 needle 不是 haystack 的一部分&#xff0c;则返回 -1 。 示例 1&#xff1a; 输入&#xff1a;haystack &qu…

a-table自定义展开图标

原文来自&#xff1a;vue 修改ant中table表格的展开图标 树形表格expandIcon自定义图标 <template #expandIcon"props"><span v-if"props.record.children?.length > 0"><divv-if"props.expanded"style"display: inline…

作用力(Force)和压力(Pressure)的区别

一般&#xff0c;力和压力在方向以及数值大小给的准确的情况下是可以通用的&#xff0c; 但是相对而言&#xff0c;力比压力的给定方便一点&#xff0c;考虑的东西可以少一点&#xff0c; 对于流体的分析&#xff0c;应该给与压力去进行分析。 力的方向一般是恒定的&#xff…