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

LearnOpenGL-笔记-其九

今天让我们完结高级OpenGL的部分:

Instancing

很多时候,在场景中包含有大量实例的时候,光是调用GPU的绘制函数这个过程都会带来非常大的开销,因此我们需要想办法在每一次调用GPU的绘制函数时尽可能多地绘制,这个过程就是我们的实例化。

具体来说,我们来看调用glDrawArraysInstanced函数的代码:

float quadVertices[] = {// 位置          // 颜色-0.05f,  0.05f,  1.0f, 0.0f, 0.0f,0.05f, -0.05f,  0.0f, 1.0f, 0.0f,-0.05f, -0.05f,  0.0f, 0.0f, 1.0f,-0.05f,  0.05f,  1.0f, 0.0f, 0.0f,0.05f, -0.05f,  0.0f, 1.0f, 0.0f,   0.05f,  0.05f,  0.0f, 1.0f, 1.0f                   
}; 

这是我们的顶点数组,二维的位置坐标和三维的RGB颜色值。

#version 330 core
layout (location = 0) in vec2 aPos;
layout (location = 1) in vec3 aColor;out vec3 fColor;uniform vec2 offsets[100];void main()
{vec2 offset = offsets[gl_InstanceID];gl_Position = vec4(aPos + offset, 0.0, 1.0);fColor = aColor;
}

这个就是我们的顶点着色器,能够看到我们有一个uniform偏移量数组,我们用gl_InstanceID作为数组的索引。就像我们之前所言,gl_InstanceID是一个自增的内建变量,我们使用这个变量可以省去一个for循环的过程,当然,前提是我们调用glDrawArraysInstanced函数。

glBindVertexArray(quadVAO);
glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 100);

我们调用glDrawArraysInstanecd和glDrawArrays的方式没有区别,只是多了一个实例的数目,这里我们是100,这样的话我们的gl_InstanceID就会从0自增到100。

虽然这种直接在着色器里定义好偏差数组的做法非常的方便快捷,但是显然在真正的应用中,我们需要的实例数量还会不断提高。作为定义在着色器里的uniform类型变量是有自己的数据的上限的,这个时候我们就需要去寻找新的方法来解决这个问题,这个新的方法就是实例化数组。

我们用一个代码实例就能知道效果如何:

// generate a list of 100 quad locations/translation-vectors
// ---------------------------------------------------------glm::vec2 translations[100];int index = 0;float offset = 0.1f;for (int y = -10; y < 10; y += 2){for (int x = -10; x < 10; x += 2){glm::vec2 translation;translation.x = (float)x / 10.0f + offset;translation.y = (float)y / 10.0f + offset;translations[index++] = translation;}}

在这里我们定义了一个大小为100的二维向量数组,他们的每一个值都不一样。

    unsigned int instanceVBO;glGenBuffers(1, &instanceVBO);glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec2) * 100, &translations[0], GL_STATIC_DRAW);glBindBuffer(GL_ARRAY_BUFFER, 0);

我们专门生成一个VBO对象去把这些值加载进缓冲中。

    float quadVertices[] = {// positions     // colors-0.05f,  0.05f,  1.0f, 0.0f, 0.0f,0.05f, -0.05f,  0.0f, 1.0f, 0.0f,-0.05f, -0.05f,  0.0f, 0.0f, 1.0f,-0.05f,  0.05f,  1.0f, 0.0f, 0.0f,0.05f, -0.05f,  0.0f, 1.0f, 0.0f,0.05f,  0.05f,  0.0f, 1.0f, 1.0f};

这是我们具体的顶点数组,每个顶点有两个属性:位置和颜色,其实一个是二维向量一个是三维向量。

    unsigned int quadVAO, quadVBO;glGenVertexArrays(1, &quadVAO);glGenBuffers(1, &quadVBO);glBindVertexArray(quadVAO);glBindBuffer(GL_ARRAY_BUFFER, quadVBO);glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), quadVertices, GL_STATIC_DRAW);glEnableVertexAttribArray(0);glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);glEnableVertexAttribArray(1);glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(2 * sizeof(float)));// also set instance dataglEnableVertexAttribArray(2);glBindBuffer(GL_ARRAY_BUFFER, instanceVBO); // this attribute comes from a different vertex bufferglVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);glBindBuffer(GL_ARRAY_BUFFER, 0);glVertexAttribDivisor(2, 1); // tell OpenGL this is an instanced vertex attribute.

这里我们定义并配置我们的VAO对象和VBO对象,注意我们的VBO的配置过程中,我们把location为0和1的数据交给了我们的quadVBO,而到了location为2的第三个对象实例化数据,我们切换VBO对象为instanceVBO,然后我们还调用了glVertexAttribDivisor函数:这个函数用于告诉GPU我们的实例ID(就是那个内建变量gl_InstanceID)每隔一个实例更新一次(2代表location,1则是隔1个实例自增一次)。

搭配上我们的顶点着色器的定义:

#version 330 core
layout (location = 0) in vec2 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aOffset;out vec3 fColor;void main()
{fColor = aColor;gl_Position = vec4(aPos + aOffset, 0.0, 1.0);
}

效果如图:

现在让我们来上点强度,我们把需要渲染的模型的数量提高N个数量级:我们来生成一个小行星带的效果。

小行星带,显然难的不是行星而是行星带比较难处理,当我们想象行星带时,我们很容易想到大量的碎石,显然这些碎石的数量远远大小我们的Uniform的数据大小上限(非常大的数量级)。

    unsigned int amount = 100000;glm::mat4* modelMatrices;modelMatrices = new glm::mat4[amount];srand(static_cast<unsigned int>(glfwGetTime())); // initialize random seedfloat radius = 150.0;float offset = 25.0f;for (unsigned int i = 0; i < amount; i++){glm::mat4 model = glm::mat4(1.0f);// 1. translation: displace along circle with 'radius' in range [-offset, offset]float angle = (float)i / (float)amount * 360.0f;float displacement = (rand() % (int)(2 * offset * 100)) / 100.0f - offset;float x = sin(angle) * radius + displacement;displacement = (rand() % (int)(2 * offset * 100)) / 100.0f - offset;float y = displacement * 0.4f; // keep height of asteroid field smaller compared to width of x and zdisplacement = (rand() % (int)(2 * offset * 100)) / 100.0f - offset;float z = cos(angle) * radius + displacement;model = glm::translate(model, glm::vec3(x, y, z));// 2. scale: Scale between 0.05 and 0.25ffloat scale = static_cast<float>((rand() % 20) / 100.0 + 0.05);model = glm::scale(model, glm::vec3(scale));// 3. rotation: add random rotation around a (semi)randomly picked rotation axis vectorfloat rotAngle = static_cast<float>((rand() % 360));model = glm::rotate(model, rotAngle, glm::vec3(0.4f, 0.6f, 0.8f));// 4. now add to list of matricesmodelMatrices[i] = model;}

我们生成10万个模型变换矩阵,然后将其坐标设置为绕着圆心的圆上。

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 2) in vec2 aTexCoords;
layout (location = 3) in mat4 aInstanceMatrix;out vec2 TexCoords;uniform mat4 projection;
uniform mat4 view;void main()
{TexCoords = aTexCoords;gl_Position = projection * view * aInstanceMatrix * vec4(aPos, 1.0f); 
}

这里我们把模型变化矩阵作为一个变量传进顶点着色器,注意我们传的是一个mat4变量,而顶点着色器的大小上限是一个vec4变量(mat4是4个vec4),所以我们需要进行一些额外的处理。

    // configure instanced array// -------------------------unsigned int buffer;glGenBuffers(1, &buffer);glBindBuffer(GL_ARRAY_BUFFER, buffer);glBufferData(GL_ARRAY_BUFFER, amount * sizeof(glm::mat4), &modelMatrices[0], GL_STATIC_DRAW);// set transformation matrices as an instance vertex attribute (with divisor 1)// note: we're cheating a little by taking the, now publicly declared, VAO of the model's mesh(es) and adding new vertexAttribPointers// normally you'd want to do this in a more organized fashion, but for learning purposes this will do.// -----------------------------------------------------------------------------------------------------------------------------------for (unsigned int i = 0; i < rock.meshes.size(); i++){unsigned int VAO = rock.meshes[i].VAO;glBindVertexArray(VAO);// set attribute pointers for matrix (4 times vec4)glEnableVertexAttribArray(3);glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)0);glEnableVertexAttribArray(4);glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(sizeof(glm::vec4)));glEnableVertexAttribArray(5);glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(2 * sizeof(glm::vec4)));glEnableVertexAttribArray(6);glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(3 * sizeof(glm::vec4)));glVertexAttribDivisor(3, 1);glVertexAttribDivisor(4, 1);glVertexAttribDivisor(5, 1);glVertexAttribDivisor(6, 1);glBindVertexArray(0);}

我们可以看到,我们生成VBO之后,我们从指向模型变换矩阵的数组指针开始,我们需要单独取出每个子碎石的VAO来绑定庞大的模型变换矩阵数组,我们从layout=3的位置开始一行一行地读取,然后每一个实例都要更新一个实例ID,因为一个顶点数据的最大大小为vec4,所以我们需要四个顶点数据组成完整的mat4变量。这样做的意思其实就是我们将多达十万个mat4的数据量直接一次性全部传入缓存中,这样的话我们只用单独Draw Call一次就可以绘制所有的碎石。

效果如图:

Anti Aliasing

抗锯齿已经是一个经久不衰的老问题了:

很喜欢闫老师的一句话:世界上所有的失真现象都可以归结为采样率不足。

SSAA事实上某种程度来说也算是一种针对抗锯齿的通解,用更高的算力开销来从根本上解决问题,但是我们如果想要真正体现出思想优越之处的做法,那就得从头开始做。

为了理解什么是多重采样(Multisampling),以及它是如何解决锯齿问题的,我们有必要更加深入地了解OpenGL光栅器的工作方式。

光栅器是位于最终处理过的顶点之后到片段着色器之前所经过的所有的算法与过程的总和。光栅器会将一个图元的所有顶点作为输入,并将它转换为一系列的片段。顶点坐标理论上可以取任意值,但片段不行,因为它们受限于你窗口的分辨率。顶点坐标与片段之间几乎永远也不会有一对一的映射,所以光栅器必须以某种方式来决定每个顶点最终所在的片段/屏幕坐标。

是的,多重采样的本质就是提高每个像素的采样点数量,这样我们可以更清晰地了解具体某个像素有多少个采样点被采样,从而体现出颜色的层次并大大减少锯齿数量。

明白了我们的多重采样的基本原理之后,让我们回到OpenGL之中的抗锯齿技术。

我们的OpenGL之中已经帮我们定义好了MSAA方法,所以我们只需要在生成窗口系统时去显示地写明我们的采样缓冲数量即可,需要注意的是,这里的缓冲是包含所有的帧缓冲,也就是除了颜色缓冲以外还有深度缓冲和模板缓冲。

由于后续的OpenGL课程中并没有展开对抗锯齿算法的详细介绍与具体优化,我也就不再浪费篇幅。

相关文章:

LearnOpenGL-笔记-其九

今天让我们完结高级OpenGL的部分&#xff1a; Instancing 很多时候&#xff0c;在场景中包含有大量实例的时候&#xff0c;光是调用GPU的绘制函数这个过程都会带来非常大的开销&#xff0c;因此我们需要想办法在每一次调用GPU的绘制函数时尽可能多地绘制&#xff0c;这个过程就…...

开源软件与自由软件:一场理念与实践的交锋

在科技的世界里&#xff0c;“开源软件”和“自由软件”这两个词几乎无人不知。很多人或许都听说过&#xff0c;它们的代码是公开的&#xff0c;可以供所有人查看、修改和使用。然而&#xff0c;若要细究它们之间的区别&#xff0c;恐怕不少朋友会觉得云里雾里。今天&#xff0…...

关于使用HAL_ADC_Start函数时为什么要放在while里的解释

HAL_ADC_Start() 是一个用于启动 ADC&#xff08;模数转换器&#xff09;转换的函数&#xff0c;那为什么有时候我们会看到它被放在 while 循环里呢&#xff1f;其实取决于你使用的是哪种ADC采样方式&#xff0c;我们来细说&#x1f447;&#xff1a; &#x1f9e0; 一、先搞清…...

Qt 入门 2 之窗口部件 QWidget

Qt 入门2之窗口部件 QWidget Qt Creator 提供的默认基类只有QMainWindow、QWidget和QDialog 这3种&#xff0c;这3种窗体也是以后用得最多的&#xff0c;QMainWindow是带有菜单栏和工具栏的主窗口类,QDialog是各种对话框的基类,而它们全部继承自QWidget。不仅如此,其实所有的窗…...

在 Windows 上安装 WSL Ubuntu 的完整避坑指南:从报错到成功运行

问题背景​​ 最近在尝试通过 ​​Windows Subsystem for Linux (WSL)​​ 安装 Ubuntu 时&#xff0c;遇到了一系列报错。最初的步骤是直接使用 wsl --install 命令&#xff0c;但安装完成后发现系统中并未自动安装默认的 Ubuntu 发行版。随后尝试通过命令行手动选择发行版&a…...

STM32看门狗原理与应用详解:独立看门狗 vs 窗口看门狗(上) | 零基础入门STM32第九十四步

主题内容教学目的/扩展视频看门狗什么是看门狗&#xff0c;原理分析&#xff0c;启动喂狗方法&#xff0c;读标志位。熟悉在程序里用看门狗。 师从洋桃电子&#xff0c;杜洋老师 &#x1f4d1;文章目录 一、看门狗核心原理1.1 工作原理图解1.2 经典水桶比喻 二、STM32看门狗双雄…...

Hyperlane 框架路由功能详解:静态与动态路由全掌握

Hyperlane 框架路由功能详解&#xff1a;静态与动态路由全掌握 Hyperlane 框架提供了强大而灵活的路由功能&#xff0c;支持静态路由和动态路由两种模式&#xff0c;让开发者能够轻松构建各种复杂的 Web 应用。本文将详细介绍这两种路由的使用方法。 静态路由&#xff1a;简单…...

webpack js 逆向 --- 个人记录

网站 aHR0cDovL2FlcmZheWluZy5jb20v加密参数 参数加密位置 方法&#xff1a; 1. 构造自执行函数 !function(e) {// 加载器 }(// 模块1&#xff1b;// 模块2 )2. 找到js的加载器 3. 把上述代码放入第一步构造的自执行函数(完整扣取一整个加载器里的代码)&#xff0c;并用一…...

代码随想录回溯算法03

93.复原IP地址 本期本来是很有难度的&#xff0c;不过 大家做完 分割回文串 之后&#xff0c;本题就容易很多了 题目链接/文章讲解&#xff1a;代码随想录 视频讲解&#xff1a;回溯算法如何分割字符串并判断是合法IP&#xff1f;| LeetCode&#xff1a;93.复原IP地址_哔哩哔…...

SOMEIP通信矩阵解读

目录 1 摘要2 SOME/IP通信矩阵详细属性定义与示例2.1 服务基础属性2.2 数据类型定义2.3 服务实例与网络配置参数2.4 SOME/IP-SD Multicast 配置&#xff08;SOME/IP服务发现组播配置&#xff09;2.5 SOME/IP-SD Unicast 配置2.6 SOME/IP-SD ECU 配置参数详解 3 总结 1 摘要 本…...

keys简单通用命令

目录 一、通配符匹配key 二、key的常用命令 1&#xff09;exists 判断某个key是否存在 2&#xff09;删除key 3&#xff09;expire设置key的过期时间、ttl查询key的过期时间 4&#xff09;type可以获取key对应的value的类型 一、通配符匹配key redis作为键值对类型的数据…...

Linux : 页表

目录 一 前言 二 深入理解页表 三 页表的实际组成 四 总结 一 前言 页表是我们之前在讲到Linux : 进程地址空间-CSDN博客的时候说到的&#xff0c;它是物理内存到进程程序地址空间的一个桥梁&#xff0c;通过它&#xff0c;物理内存的数据和代码才能映射到进程的程序地址空间…...

多智能体优秀开发框架

原文链接:https://i68.ltd/notes/posts/20250402-multi-agent/ motia-面向软件工程师的智能体框架 项目仓库:https://github.com/MotiaDev/motia 1.3k官方网站:https://motia.devMotia 允许开发人员在几分钟内创建&#xff0c;测试和部署生产就绪的 AI 代理&#xff0c;在一个…...

JavaScript创建对象与构造函数

目录 创建对象 一、创建对象的 5 种核心方式 1. 对象字面量&#xff08;直接量&#xff09; 2. 使用 Object.create() 3. 工厂模式 4. 构造函数模式 5. ES6 class 语法&#xff08;语法糖&#xff09; 二、构造函数与 new 关键字 1. 构造函数的作用 2. 构造函数的特征…...

【langchain4j系列教程-02】Langchain4j调用DeepSeek

文章目录 依赖引入代码示例api key如何获取模型名称及价格为什么调用DeepSeek API用的是OpenAIChatModel 这篇文章主要介绍了如何在Java项目中引入DeepSeek的依赖&#xff0c;并提供了调用DeepSeek API的代码示例。 依赖引入 DeepSeek是一个与OpenAI接口标准兼容的人工智能平台…...

c++STL入门

目录 什么是STL&#xff1f; vector容器 构造函数 赋值操作 vector容量和大小 vector存放内置数据类型 vector存放自定义数据类型 存放指针 vector容器嵌套容器 string容器 构造函数 赋值操作 字符串拼接 查找和替换 string字符串比较 string字符存取 string插…...

公有云子账号认证的原理和步骤

1 为什么使用子账号 1.1 子账号认证的背景 主账号权限过大:公有云账号(主账号)对账号中的资源具有完全管理权限,且无法调整其权限大小,多人共用时无法在审计日志中区分出具体使用人,一旦泄露风险极大且难以追溯。 安全需求:为了提高安全性,避免因主账号信息泄露而导致…...

基于Flask的微博舆情数据分析系统

【Flask】基于Flask的微博舆情数据分析系统&#xff08;完整系统源码开发笔记详细部署教程&#xff09;✅ 目录 一、项目简介二、项目界面展示三、项目视频展示 一、项目简介 该系统能够高效收集、处理微博上的海量数据&#xff0c;实时反映公众对某些事件或话题的舆论倾向&am…...

Mac OS 禁用 SIP 系统完整性保护

关闭并重新启动 Mac&#xff0c;CommandR在启动时按住以进入Recovery Mode.进入Recovery模式后打开终端 -bash-3.2# csrutil disable Turning off System Integrity Protection reguires modifying system security.Allow booting unsigned operating systems and any ker…...

第十四届蓝桥杯省赛真题解析(含C++详细源码)

第十四届蓝桥杯省赛 整数删除满分思路及代码solution1 &#xff08;40% 双指针暴力枚举&#xff09;solution 2&#xff08;优先队列模拟链表 AC&#xff09; 冶炼金属满分代码及思路 子串简写满分思路及代码solution 1&#xff08;60% 双指针&#xff09;solution 2&#xff0…...

整车CAN网络和CANoe

车载网络中主要包含有Can网络,Lin网络,FlexRay,Most,以太网。 500kbps:500波特率,表示的数据传输的速度。表示的是最大的网速传输速度。也就是每秒 500kb BodyCan车身Can InfoCan娱乐信息Can 车身CAN主要连接的是ESB电动安全带 ADB自适应远光灯等 PTCan动力Can 底盘Can...

从扩展黎曼泽塔函数构造物质和时空的结构-16

都是一样的泽塔函数&#xff0c;却呈现出不同的性质&#xff0c;而不同的性质无关于自然数还是质数&#xff0c;完全是由s来决定的。可以猜想&#xff0c; 就是光子&#xff0c;而如果&#xff0c; 就是物质粒子。其中不同的k指出不同的周期或者对应于不同的质数p&#xff0c;虽…...

【C++】list模拟实现

&#x1f4dd;前言&#xff1a; 这篇文章我们来讲讲STL中list的模拟实现&#xff1a; &#x1f3ac;个人简介&#xff1a;努力学习ing &#x1f4cb;个人专栏&#xff1a;C学习笔记 &#x1f380;CSDN主页 愚润求学 &#x1f304;其他专栏&#xff1a;C语言入门基础&#xff0c…...

人脸专注度检测系统(课堂专注度检测、人脸检测、注意力检测系统)

人脸专注度检测系统 项目介绍 本项目是基于Flask、MobileNetV2、Mediapipe的人脸专注度检测系统。 项目采用tensorflow.keras库内置的MobileNetV2预训练模型&#xff0c;对自主采集的少量人脸图片数据迁移训练而得到最终的人脸专注度检测模型。 项目采用前后端分离的技术框架…...

文件操作和IO ——Java

初识文件 首先文件分为&#xff1a; 1.狭义的文件 – 保存在硬盘上的文件。 2.广义的文件 – 操作系统进行资源管理的一种机制。很多的软件/硬件资源&#xff0c;抽象成“文件”来进行表示。 &#xff08;println > 控制台&#xff0c;scanner > 控制台的标准输入&#…...

dmsetup 清理ceph osd残留磁盘分区

在物理机上接入磁盘并准备格式化时&#xff0c;发现磁盘中存在之前残留的 Ceph OSD 分区。尝试运用 fdisk 重新分区、重新格式化&#xff0c;以及使用 sgdisk 格式化&#xff0c;甚至重写磁盘头&#xff0c;都未能成功清理掉这些 OSD 残留分区。最终&#xff0c;借助 dmsetup 直…...

每日一题(小白)字符串娱乐篇16

分析题意可以了解到本题要求在一串字符串中找到所有组合起来排序递增的字符串。我们可以默认所有字符在字符串中的上升序列是1&#xff0c;从第一个字符开始找&#xff0c;如果后面的字符大于前面的字符就说明这是一个上序列那么后面字符所在的数组加一&#xff0c;如果连接不上…...

【Mac 从 0 到 1 保姆级配置教程 11】- Mac 基础配置 Finder、触控板、常用快捷键等

文章目录 前言配置 Finder1. 把我们的家目录请出来2. 显示文件扩展名3. 展示隐藏文件4. 显示路径栏和状态栏5. 固定文件夹到工具栏 基础快捷键1. Finder 导航快捷键2. 文件操作快捷键3. 视图和显示快捷键4. 搜索和选择快捷键5. 实用技巧6. 关于文件创建 配置触控板1. 右键设置2…...

Redis 渐进式rehash怎么判定rehash完成了?

Redis 渐进式 Rehash 的完成判断机制 在 Redis 的字典(dict)结构扩容或缩容时,会使用 渐进式 Rehash 来避免一次性迁移所有键值对导致的阻塞。以下是判断旧哈希表(ht[0])是否全部迁移完毕的核心逻辑: 1. 渐进式 Rehash 的核心流程 Redis 的字典结构包含两个哈希表: t…...

Redis的常用数据结构

三. Redis 的常用数据结构 (redis提供的查询功能, 不像mysql这么强大) 1. 认识数据类型和编码方式 常见数据结构 (数据类型) : string (字符串), list (列表), hash (哈希), set (集合), zset (有序集合). Redis 底层在实现上述数据结构的时候, 会在源码层面进行优化, 来达到…...

c++中的虚函数

在C中&#xff0c;虚函数&#xff08;Virtual Function&#xff09;是一种实现多态的重要机制&#xff0c;它允许在派生类中重写基类的函数&#xff0c;从而在运行时根据对象的实际类型调用相应的函数版本。 1. 虚函数的定义 虚函数是在基类中使用关键字virtual声明的函数。例…...

unreal engine5开发仿鬼泣5的游戏,把敌人击飞到空中4连击

UE5系列文章目录 文章目录 UE5系列文章目录前言一、实现思路二、具体蓝图 前言 unreal engine5开发仿鬼泣5的游戏&#xff0c;把敌人击飞到空中4连击&#xff0c;先看下效果 一、实现思路 unreal engine5开发仿鬼泣5的游戏&#xff0c;把敌人击飞到空中4连击 在Unreal Engi…...

蓝桥杯嵌入式第十四届模拟二(PWM、USART)

一.LED 先配置LED的八个引脚为GPIO_OutPut,锁存器PD2也是,然后都设置为起始高电平,生成代码时还要去解决引脚冲突问题 二.按键 按键配置,由原理图按键所对引脚要GPIO_Input 生成代码,在文件夹中添加code文件夹,code中添加fun.c、fun.h、headfile.h文件,去资源包中把lc…...

深挖 TypeScript 基础数据类型:应用与陷阱

在 TypeScript 的学习与实践过程中&#xff0c;对基础数据类型的深入理解和正确运用&#xff0c;是写出高质量代码的关键。本篇文章会通过探讨数据类型在实际场景中的应用&#xff0c;分析常见错误&#xff0c;帮助大家提升运用 TypeScript 基础数据类型的能力。​ 一、函数参…...

B站视频教材: Yocto项目实战教程 第一章 PPT讲解

B站视频链接,请多多关注本人B站&#xff1a; &#x1f4cc; Yocto项目实战教程&#xff1a;第一章 视频讲解 在当今嵌入式系统快速发展的背景下&#xff0c;越来越多的设备和行业依赖于高效、可定制、可维护的操作系统解决方案。嵌入式Linux系统&#xff0c;凭借其开源灵活性和…...

嵌入式软件开发调试方法

文章目录 1. 利于函数返回值,retrurn 定位错误位置2. 合理使用逻辑分析仪&#xff08;正点原子 厉害&#xff01;&#xff01;&#xff09; 1. 利于函数返回值,retrurn 定位错误位置 如下图所示&#xff0c;设置不同的返回值&#xff0c;0是ok的&#xff0c;其他值均为失败&…...

Sentinel核心源码分析(上)

文章目录 前言一、客户端与Spring Boot整合二、SphU.entry2.1、构建责任链2.2、调用责任链2.2.1、NodeSelectorSlot2.2.2、ClusterBuilderSlot2.2.3、LogSlot2.2.4、StatisticSlot2.2.5、AuthoritySlot2.2.6、SystemSlot2.2.7、FlowSlot2.2.7.1、selectNodeByRequesterAndStrat…...

TCPIP详解 卷1协议 一 概述

相关概念 协议族&#xff1a;一系列相关协议的集合称为一个协议族体系结构&#xff1a;指定一个协议族中的各种协议之间的相互关系并划分需要完成的任务的设计&#xff0c;称为协议族的体系结构。分组交换&#xff1a;数据被分割为固定或可变长度的分组 &#xff0c;每个分组包…...

条件生成对抗网络(Conditional GAN, CGAN)原理及实现(pytorch版)

CGAN 原理及实现 一、CGAN 原理1.1 基本概念1.2 与传统GAN的区别1.3 目标函数1.4 损失函数1.5 条件信息的融合方式1.6 与其他GAN变体的对比1.7 CGAN的应用1.8 改进与变体二、CGAN 实现2.1 导包2.2 数据加载和处理2.3 构建生成器2.4 构建判别器2.5 训练和保存模型2.6 绘制训练损…...

类与对象(上)

【本节目标】 1.面向过程和面向对象初步认识 2.类的引入 3.类的定义 4.类的访问限定符及封装 5.类的作用域 6.类的实例化 7.类的对象大小的计算 8.类成员函数的this指针 1.面向过程和面向对象初步认识 C语言是面向过程的&#xff0c;关注的是过程&#xff0c;…...

MySQL基础 [三] - 数据类型

目录 数据类型分类 ​编辑 数值类型 tinyint bit 浮点类型 float decimal 字符串类型 char varchar varchar和char的比较和选择 日期和时间类型 enum和set enum类型 set类型 enum和set的类型查找 数据类型分类 数值类型 tinyint TINYINT[(M)] [UNSIGNED]是 …...

1.1 测试计划阶段:如何制定高效的测试策略

测试计划阶段&#xff1a;如何制定高效的测试策略 摘要 本文详细介绍了软件测试流程中的测试计划阶段&#xff0c;包括测试策略制定、资源规划、进度安排和风险管理等内容。通过本文&#xff0c;读者可以系统性地了解如何制定有效的测试计划&#xff0c;确保测试工作有序进行…...

Spring 概念

Spring 是一个功能强大、灵活且广泛使用的 Java 企业级开发框架&#xff0c;它诞生于 2003 年&#xff0c;由 Rod Johnson 创建&#xff0c;初衷是简化 Java EE 的开发过程。 一、Spring 是什么&#xff1f; 简单来说&#xff1a; Spring 是一个轻量级的 Java 开发框架&#…...

animals_classification动物分类

数据获取 深度学习训练中第一个是获取数据集&#xff0c;数据集的质量很重要&#xff0c;我们这里做的是动物分类&#xff0c;大致会选择几个动物&#xff0c;来做一个简单的多分类问题&#xff0c;数据获取的方法&#xff0c;鼠鼠我这里选择使用爬虫的方式来对数据进行爬取&a…...

15.QT窗口:主窗口、浮动窗口、对话框

0. 概述 Qt窗口是通过 QMainWindow类 来实现的。 QMainWindow 是一个为用户提供主窗口程序的类&#xff0c;继承自QWidget类&#xff0c;并且提供了一个预定义的布局。QMainWindow包含一个菜单栏&#xff08;menu bar&#xff09;、多个工具栏&#xff08;tool bars&#xff…...

nginx中地理位置访问控制模块geo

1.安装 GeoIP2 模块 Ubuntu/Debian 系统&#xff1a; sudo apt-get update sudo apt-get install nginx-module-geoip2 sudo apt-get install libnginx-mod-http-geoip2CentOS/RHEL 系统&#xff1a; sudo yum install nginx-module-geoip22.下载 GeoIP2 数据库 下载 GeoIP2 …...

基于SpringBoot酒店管理系统设计和实现(源码+文档+部署讲解)

技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论文…...

蓝桥杯嵌入式第十四届模拟二

一.LED 先配置LED的八个引脚为GPIO_OutPut,锁存器PD2也是,然后都设置为起始高电平,生成代码时还要去解决引脚冲突问题 二.按键 按键配置,由原理图按键所对引脚要GPIO_Input 生成代码,在文件夹中添加code文件夹,code中添加fun.c、fun.h、headfile.h文件,去资源包中把lc…...

【前端】Node.js一本通

近两天更新完毕&#xff0c;建议关注收藏点赞。 目录 复习Node.js概述使用fs文件系统模块path路径模块http模块模块化 复习 为什么JS可以在浏览器中执行 原理&#xff1a;待执行的JS代码->JS解析引擎 不同的浏览器使用不同的 JavaScript 解析引擎&#xff1a;其中&#xf…...

Groovy

一&#xff1a;了解 1:groovy保留字 2: 标识符 二&#xff1a;数据类型 1:字符串(1) 1: java.lang.string 定义的字符串是不能改变的 2: groovy.lang.GString 定义的字符串的值是不能改变的 2: 总结 三&#xff1a;数值类型 1: Groovy的数值型包括整数型&#xff08;integer)…...