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

OpenGL入门最后一章观察矩阵(照相机)

        前面的一篇文章笔者向大家介绍了模型变化矩阵,投影矩阵。现在只剩下最后一个观察矩阵没有和大家讲了。此片文章就为大家介绍OpenGL入门篇的最后一个内容。

观察矩阵

        前面的篇章当中,我们看到了即使没有观察矩阵,我们也能对绘制出来的模型有一个很好的控制,那么观察矩阵存在的意义又是什么了?那么我们现在来想象一下这样一件事,我们的屏幕上绘制了特别多的方块,现在我们要把它们全部向屏幕的右边移动一定的距离,如果是前面的做法的话所有的模型都要再乘上一个向右平移的矩阵,这样做完全没有问题,只是这会让程序的效率变得很差,而且你的GPU除了计算一下像素颜色之外基本上就没有做其他任何事,把绝大部分的任务都交给了CPU,这样的任务分配是不合理的,所以我们需要上传一个观察矩阵ViewMatrixGPU,让他把所有的顶点按照某一个方向进行平移,这样我们的任务就合理分配了。(什么样的任务应该交给CPU,什么样的任务又交给GPU这里也有不少东西需要研究)

        看过资料的朋友们都知道,在OpenGL当中想用创建一个观察矩阵只需要使用glm::lookAt函数即可

glm::lookAt(m_Position, m_Forward, m_Up);
//glm::vec3 m_Position 照相机的位置
//glm::vec3 m_Forward 观察的位置
//glm::vec3 m_Up 相机屏幕的上方的方向

这样我们就得到了一个观察矩阵了,看起来也没什么好说的对不对。但是困难的往往是处理与之相关的数学问题,前面说我们要让屏幕上的所有的方块全部向右移动一段距离,那么我们应该怎么设置这个观察矩阵了?直接给答案

glm::vec3 m_Position(-0.3f,0.0f,3.0f)
glm::vec3 m_Forward(-0.3f,0.0f,0.0f);
glm::vec3 m_Up(0.0f,1.0f,0.0f);glm::lookAt(m_Position, m_Forward, m_Up);

可能有的朋友们就要问了,相机为什么要往左边移动,并且看向左边了?要回答这个问题也很简单,大家现在把手机拿出来打开照相机,然后手机屏幕与电脑屏幕保持水平,现在把手机水平向左开始移动,你就会发现手机屏幕中的物体朝着反方向进行移动了,如果再把手机对准刚才位置,你就会发现所有的物体都行了旋转拉绳,这当然不是我们想要的结果,所以我们要让手机继续朝向正前方。观察矩阵和我们的照相机的工作原理一摸一样,所以观察矩阵也可以叫作相机矩阵。

制作一个可以观察物体的矩阵

        观察矩阵其实介绍到这里也就算是结束了,我们现在来做一个可以实际使用的相机。比如说我现在制作了一个立方体,每一个面的颜色都不一样,它刚被绘制出来的时候我只能看见一两个面,但是我想观察其他的面,如果说我去修改模型让它自己转过来,这也有点太蠢了!所以我们要做一个进行鼠标控制的照相机。

        我的打算是,让照相机沿着一个球面进行运动,鼠标坐标的变化来确定照相机在球体坐标上的夹角。

鼠标x方向上的偏移量决定\theta角的大小,鼠标y方向上的偏移量决定\phi角的大小,有了理论的基础过后我们看一下具体如何实现。

照相机类:

Camera.h

#pragma once
#include<glm/glm.hpp>class Camera {
public:Camera(glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f), float yam = 0.0f, float pitch =90.0f);Camera(float posX, float posY, float posZ, float upX, float upY, float upZ, float yaw, float pitch);glm::mat4 GetViewMatrix();void ProcessMouseMovement(float xoffset, float yoffset, bool constrainPitch = true);void ProcessMouseScroll(float yoffset);inline float GetCameraZoom() const { return m_Zoom; }
private:void UpdateCameraVectors();private:glm::vec3 m_Position, m_Front, m_Up, m_Right, m_WorldUp;float m_Yaw, m_Pitch;float m_MouseSensitivity;float m_Zoom;
};

Camera.cpp

#include<glm/gtc/matrix_transform.hpp>
#include<iostream>#include"Camera.h"Camera::Camera(glm::vec3 position ,glm::vec3 up,float yam,float pitch):m_Front(glm::vec3(0.0f,0.0f,-1.0f)),m_MouseSensitivity(0.1f),m_Zoom(45.0f) {m_Position = position;m_WorldUp = up;m_Yaw = yam;m_Pitch = pitch;UpdateCameraVectors();
}Camera::Camera(float posX, float posY, float posZ, float upX, float upY, float upZ, float yaw, float pitch):m_Front(glm::vec3(0.0f,0.0f,-1.0f)),m_MouseSensitivity(0.1f),m_Zoom(45.0f) {m_Position = glm::vec3(posX, posY, posZ);m_WorldUp = glm::vec3(upX, upY, upZ);m_Yaw = yaw;m_Pitch = pitch;UpdateCameraVectors();
}glm::mat4 Camera::GetViewMatrix() {return glm::lookAt(m_Position, glm::vec3(0.0f, 0.0f, 0.0f), m_Up);
}void Camera::ProcessMouseMovement(float xoffset, float yoffset, bool constrainPitch){xoffset *= m_MouseSensitivity;yoffset *= m_MouseSensitivity;m_Yaw += xoffset;m_Pitch += yoffset;if (constrainPitch) {m_Pitch = m_Pitch > 179.0f ? 179.0f : m_Pitch;m_Pitch = m_Pitch < 0.1f ? 0.1f : m_Pitch;}UpdateCameraVectors();
}void Camera::ProcessMouseScroll(float yoffset) {m_Zoom -= yoffset;m_Zoom = m_Zoom < 1.0f ? 1.0f : m_Zoom;m_Zoom = m_Zoom > 45.0f ? 45.0f : m_Zoom;
}void Camera::UpdateCameraVectors() {glm::vec3 position(0.0f,0.0f,0.0f);position.x = 5.0f * sinf(glm::radians(m_Yaw)) * sinf(glm::radians(m_Pitch));position.y = 5.0f * cosf(glm::radians(m_Pitch));position.z = 5.0f * cosf(glm::radians(m_Yaw)) * sinf(glm::radians(m_Pitch));m_Front = glm::normalize(-position);m_Position = position;m_Right = glm::normalize(glm::cross(m_Front, m_WorldUp));m_Up = glm::normalize(glm::cross(m_Right, m_Front));
}

除此以外,我们还需要处理鼠标输入函数

void mouse_callback(GLFWwindow* window, double xposIn, double yposIn) {static float lastX = 320.0f, lastY = 240.0f;static bool firstMouse = true;float xpos = static_cast<float>(xposIn);float ypos = static_cast<float>(yposIn);if (firstMouse) {lastX = xpos;lastY = ypos;firstMouse = false;}float xoffset = xpos - lastX;float yoffset = lastY - ypos;lastX = xpos, lastY = ypos;camera.ProcessMouseMovement(xoffset, yoffset);
}void scroll_callback(GLFWwindow* window, double xoffsetIn, double yoffsetIn) {camera.ProcessMouseScroll(static_cast<float>(yoffsetIn));
}void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)run = false;
}

好的主函数,贴在下面,我们就得到了一个可以绕着物体圆转的照相了,因为窗口隐藏了光标,想要推出的画按Esc键即可。

#include<glad/glad.h>
#include<GLFW/glfw3.h>#include<iostream>
#include<glm/gtc/matrix_transform.hpp>#include"Shader.h"
#include"Camera.h"static Camera camera(glm::vec3(0.0f, 0.0f, 5.0f));
static bool run = true;
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods);
void mouse_callback(GLFWwindow* window, double xposIn, double yposIn);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);int main() {glfwInit();GLFWwindow* window = glfwCreateWindow(640, 480, "Triangles", NULL, NULL);glfwMakeContextCurrent(window);glfwSetCursorPosCallback(window, mouse_callback);glfwSetScrollCallback(window, scroll_callback);glfwSetKeyCallback(window, key_callback);glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);//需要初始化GLADif (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {std::cout << "Failed to initialize GLAD" << std::endl;return -1;}float vertexes[] = {//front surface-0.5f,	-0.5f,	0.5f,	1.0f,	1.0f,0.588f,0.2784f,	//00.5f,	-0.5f,	0.5f,	1.0f,	1.0f,0.588f,0.2784f,	//10.5f,	0.5f,	0.5f,	1.0f,	1.0f,0.588f,0.2784f,	//2-0.5f,	0.5f,	0.5f,	1.0f,	1.0f,0.588f,0.2784f,	//3//back surface-0.5f,	-0.5f,	-0.5f,	1.0f,	0.933f,0.9098f,0.6666f,	//40.5f,	-0.5f,	-0.5f,	1.0f,	0.933f,0.9098f,0.6666f,	//50.5f,	0.5f,	-0.5f,	1.0f,	0.933f,0.9098f,0.6666f,	//6-0.5f,	0.5f,	-0.5f,	1.0f,	0.933f,0.9098f,0.6666f,	//7//up surface-0.5f,	0.5f,	0.5f,	1.0f,	0.0f,0.749f,1.0f,		//80.5f,	0.5f,	0.5f,	1.0f,	0.0f,0.749f,1.0f,		//90.5f,	0.5f,	-0.5f,	1.0f,	0.0f,0.749f,1.0f,		//10-0.5f,	0.5f,	-0.5f,	1.0f,	0.0f,0.749f,1.0f,		//11//down surface-0.5f,	-0.5f,	0.5f,	1.0f,	0.498f,1.0f,0.0f,		//120.5f,	-0.5f,	0.5f,	1.0f,	0.498f,1.0f,0.0f,		//130.5f,	-0.5f,	-0.5f,	1.0f,	0.498f,1.0f,0.0f,		//14-0.5f,	-0.5f,	-0.5f,	1.0f,	0.498f,1.0f,0.0f,		//15//left surface-0.5f,	-0.5f,	-0.5f,	1.0f,	0.5f,0.5f,0.145f,	//16-0.5f,	-0.5f,	0.5f,	1.0f,	0.5f,0.5f,0.145f,	//17-0.5f,	0.5f,	0.5f,	1.0f,	0.5f,0.5f,0.145f,	//18-0.5f,	0.5f,	-0.5f,	1.0f,	0.5f,0.5f,0.145f,	//19//right surface0.5f,	-0.5f,	-0.5f,	1.0f,	1.0f,0.8941f,0.7686f,	//200.5f,	-0.5f,	0.5f,	1.0f,	1.0f,0.8941f,0.7686f,	//210.5f,	0.5f,	0.5f,	1.0f,	1.0f,0.8941f,0.7686f,	//220.5f,	0.5f,	-0.5f,	1.0f,	1.0f,0.8941f,0.7686f	//24};					unsigned int indexes[] = {//front surface0,1,2,2,3,0,//back surface4,5,6,6,7,4,//up surface8,9,10,10,11,8,//down surface12,13,14,14,15,12,//left surface16,17,18,18,19,16,//right surface20,21,22,22,23,20};glEnable(GL_DEPTH_TEST);unsigned int buffer = 0, vertexArray = 0, indexBuffer = 0;glCreateVertexArrays(1, &vertexArray);glBindVertexArray(vertexArray);glCreateBuffers(1, &buffer);glBindBuffer(GL_ARRAY_BUFFER, buffer);glBufferData(GL_ARRAY_BUFFER, sizeof(vertexes), vertexes, GL_STATIC_DRAW);glEnableVertexAttribArray(0);glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), NULL);glEnableVertexAttribArray(1);glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (const void*)(4 * sizeof(float)));glCreateBuffers(1, &indexBuffer);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indexes), indexes, GL_STATIC_DRAW);Shader* pShader = new Shader("assets/shaders/TextureShader.glsl");while (!glfwWindowShouldClose(window) && run) {glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glm::mat4 project = glm::perspective(glm::radians(camera.GetCameraZoom()), 640.0f / 480.0f, 0.1f, 100.0f);glm::mat4 view = camera.GetViewMatrix();glm::mat4 ViewProject = project * view;pShader->Bind();pShader->UploadUniformat4("u_ViewProject", ViewProject);glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, NULL);glfwSwapBuffers(window);glfwPollEvents();}delete pShader;glfwDestroyWindow(window);glfwTerminate();
}void mouse_callback(GLFWwindow* window, double xposIn, double yposIn) {static float lastX = 320.0f, lastY = 240.0f;static bool firstMouse = true;float xpos = static_cast<float>(xposIn);float ypos = static_cast<float>(yposIn);if (firstMouse) {lastX = xpos;lastY = ypos;firstMouse = false;}float xoffset = xpos - lastX;float yoffset = lastY - ypos;lastX = xpos, lastY = ypos;camera.ProcessMouseMovement(xoffset, yoffset);
}void scroll_callback(GLFWwindow* window, double xoffsetIn, double yoffsetIn) {camera.ProcessMouseScroll(static_cast<float>(yoffsetIn));
}void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)run = false;
}

注意

        你可能注意到了,相机是不能绕过Y轴顶点的,但这里要声明的是并不是笔者的代码写错了,这是因为,如果绕道Y轴顶点,那么你看向的方向和世界向上的方向就平行了,这两个向量叉乘的结果是一个0向量,也就是根本没办法计算相机的右侧是那一边,相机的上边也同样没办法计算。这是纯数学问题导致的,纯数学问题也是最难解决的问题,现在多软件的相机使用都是四元数来解决这个问,有兴趣的朋友可以去查找相关资料。

总结

        此片文章看完OpenGL入门基础篇已经写完了,相信你也可以做一个像样的游戏出来了,比如以前红白机上的一些游戏,可能觉得很Low,但凡事都要一步一个脚印,游戏也是一路发展过来的,没有多少人生来就特别牛。笔者在这里感谢大家的支持。

相关文章:

OpenGL入门最后一章观察矩阵(照相机)

前面的一篇文章笔者向大家介绍了模型变化矩阵&#xff0c;投影矩阵。现在只剩下最后一个观察矩阵没有和大家讲了。此片文章就为大家介绍OpenGL入门篇的最后一个内容。 观察矩阵 前面的篇章当中&#xff0c;我们看到了即使没有观察矩阵&#xff0c;我们也能对绘制出来的模型有一…...

ES6中定义私有属性详解

在ES6中&#xff0c;定义私有属性的方式相对传统的JavaScript有所不同。ES6并没有提供直接的语法来定义私有属性&#xff0c;但可以通过几种方法间接实现私有属性。 1. 使用Symbol来模拟私有属性 Symbol是一种新的数据类型&#xff0c;可以作为对象的键&#xff0c;并且它的值…...

工业5G路由器让无人机数据传输 “飞” 起来

无人机上搭载5G通信模块&#xff0c;该模块与工业5G路由器通过5G网络建立连接。无人机的飞控系统、传感器以及摄像头等设备采集到的数据&#xff0c;如飞行姿态、高度、速度、环境图像、温度湿度等&#xff0c;经过编码、加密、调制等处理后转换为适合5G网络传输的信号形式。 …...

面试经典150题——滑动窗口

文章目录 1、长度最小的子数组1.1 题目链接1.2 题目描述1.3 解题代码1.4 解题思路 2、无重复字符的最长子串2.1 题目链接2.2 题目描述2.3 解题代码2.4 解题思路 3、串联所有单词的子串3.1 题目链接3.2 题目描述3.3 解题代码3.4 解题思路 4、最小覆盖子串4.1 题目链接4.2 题目描…...

MiFlash 线刷工具下载合集

MiFlash 线刷工具下载合集 MiFlash 线刷工具下载合集 – MIUI历史版本相较于小米助手的刷机功能&#xff0c;线刷还是偏好使用 MiFlash。特点是界面简单纯粹&#xff0c;有自定义高级选项&#xff0c;可以选择刷机不上 BL 锁&#xff0c;自定义刷机脚本&#xff0c;EDL 刷机模…...

【MySQL高级】第1-4章

第1章 存储过程 1.1 什么是存储过程&#xff1f; 存储过程可称为过程化SQL语言&#xff0c;是在普通SQL语句的基础上增加了编程语言的特点&#xff0c;把数据操作语句(DML)和查询语句(DQL)组织在过程化代码中&#xff0c;通过逻辑判断、循环等操作实现复杂计算的程序语言。 换…...

课程设计项目之基于Python实现围棋游戏代码

项目介绍 游戏进去默认为九路玩法&#xff0c;当然也可以选择十三路或是十九路玩法 使用pycharam打开项目&#xff0c;pip安装模块并引用&#xff0c;然后运行即可&#xff0c; 代码每行都有详细的注释&#xff0c;可以做课程设计或者毕业设计项目参考 效果预览 源码下载 h…...

uni-app tab 双击事件监听

1、data中定义属性&#xff0c;用于临时记录点击次数 tabClick: {touchNum: 0 },2、添加页面事件监听方法 onTabItemTap(e) {this.tabClick.touchNumsetTimeout(()>{if(this.tabClick.touchNum > 2){// 双击执行代码区}this.tabClick.touchNum 0}, 250) },个人博客&am…...

如何在Maxscript脚本中检查磁盘可用空间?

在我们实际工作中&#xff0c;有时需要在工作开始之前检查磁盘的可用空间&#xff0c;比如渲染。 当然&#xff0c;我们可以人工很容易查看电脑中各个磁盘的空间使用情况&#xff0c;但是&#xff0c;如果是Maxscript插件完成的工作&#xff0c;那么如何才能实现其工作之前对磁…...

pytorch梯度上下文管理器介绍

PyTorch 提供了多种梯度上下文管理器&#xff0c;用于控制自动梯度计算 (autograd) 的行为。这些管理器在训练、推理和特殊需求场景中非常有用&#xff0c;可以通过显式地启用或禁用梯度计算&#xff0c;优化性能和内存使用。 主要梯度上下文管理器 torch.no_grad(): 功能&am…...

Redis Stream:实时数据处理的高效解决方案

Redis Stream&#xff1a;实时数据处理的高效解决方案 引言 在当今这个数据驱动的时代&#xff0c;实时数据处理对于各种应用场景都至关重要。Redis&#xff0c;作为一个高性能的键值存储系统&#xff0c;自然也紧跟这一趋势&#xff0c;推出了Redis Stream——一种用于处理实…...

使用交换机构建简单局域网

创建交换机SW-1 交换机接口规划 序号交换机名接口连接设备接口类型1SW-1Ethernet 0/0/1Host-1默认2SW-1Ethernet 0/0/2Host-2默认3SW-1Ethernet 0/0/5Host-3默认4SW-1Ethernet 0/0/6Host-4默认 主机IP规划 Host-1&#xff1a;192.168.64.11/24&#xff0c;接入SW-1 Ethernet…...

基于MATLAB的冰箱水果保鲜识别系统

摘要&#xff1a;本作品旨在研究和实现基于MATLAB软件的冰箱水果保鲜识别系统&#xff0c;针对多种常见水果混合的图像进行处理和识别。首先&#xff0c;根据水果与背景的差异选择合适的阈值&#xff0c;对图像进行去噪和对比度增强&#xff0c;然后进行二值化处理。接下来&…...

Flink源码解析之:Flink On Yarn模式任务提交部署过程解析

Flink源码解析之&#xff1a;Flink On Yarn模式任务提交部署过程解析 一、Flink on Yarn部署模式概述 Apache Hadoop YARN 在许多数据处理框架中都很流行。 Flink 服务提交给 YARN 的 ResourceManager&#xff0c;后者会在 YARN NodeManagers 管理的机器上生成容器。 Flink 将…...

吊舱激光测距核心技术详解!

一、核心技术 吊舱激光测距的核心技术主要体现在激光发射与接收、信号处理与距离计算、以及数据校正与优化等方面。 激光发射与接收&#xff1a; 激光发射器&#xff1a;产生经过调制的激光束&#xff0c;该激光束具有特定的频率和波形。这些激光束被投射到目标物体上。 光…...

[ZJCTF 2019]NiZhuanSiWei

检查通过 file_get_contents 函数读取 $text 变量指定的文件内容是否等于字符串 "welcome to the zjctf"。 测试了一下直接传参&#xff0c;然后进入下一阶段&#xff0c;通过php伪协议读取useless.php发现不行&#xff0c;我们使用data协议将其输入进去试试 读取到…...

Kafka配置公网或NLB访问(TCP代理)

这套配置适用于TCP代理和公网访问 分几种场景&#xff0c;正常来说我们直接使用kafka IP地址访问就行&#xff0c;考虑到网络架构和环境安全&#xff0c;需要使用公网或代理访问kafka时就需要对kafka进行一些额外配置 EXTERNAL这个地址需要监听本地地址&#xff0c;之后kafka…...

大模型推理:vllm多机多卡分布式本地部署

文章目录 1、vLLM分布式部署 docker镜像构建通信环境配置 2、其他大模型部署工具3、问题记录参考文献 单台机器GPU资源不足以执行推理任务时&#xff0c;一个方法是模型蒸馏量化&#xff0c;结果就是会牺牲些效果。另一种方式是采用多台机器多个GPU进行推理&#xff0c;资源不…...

clickhouse-backup配置及使用(Linux)

一、下载地址 Releases Altinity/clickhouse-backup GitHub 二、上传到服务器解压安装 自行上传至服务器&#xff0c;解压命令&#xff1a; tar xvf clickhouse-backup-linux-amd64.tar.gz 三、创建软连接 sudo ln -sv build/linux/amd64/clickhouse-backup /usr/local/bin/…...

【YashanDB知识库】启动yasom时报错:sqlite connection error

本文内容来自YashanDB官网&#xff0c;原文内容请见 https://www.yashandb.com/newsinfo/7817893.html?templateId1718516 【标题】启动yasom时报错&#xff1a;sqlite connection error 【问题分类】安装部署 【关键字】错误码sqlite3.Error、yasom启动失败、共享集群 、u…...

CTF show Web 红包题第六弹

提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框&#xff0c;很难让人不联想到SQL注入&#xff0c;但提示都说了不是SQL注入&#xff0c;所以就不往这方面想了 ​ 先查看一下网页源码&#xff0c;发现一段JavaScript代码&#xff0c;有一个关键类ctfs…...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

简易版抽奖活动的设计技术方案

1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

逻辑回归:给不确定性划界的分类大师

想象你是一名医生。面对患者的检查报告&#xff08;肿瘤大小、血液指标&#xff09;&#xff0c;你需要做出一个**决定性判断**&#xff1a;恶性还是良性&#xff1f;这种“非黑即白”的抉择&#xff0c;正是**逻辑回归&#xff08;Logistic Regression&#xff09;** 的战场&a…...

STM32F4基本定时器使用和原理详解

STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

高防服务器能够抵御哪些网络攻击呢?

高防服务器作为一种有着高度防御能力的服务器&#xff0c;可以帮助网站应对分布式拒绝服务攻击&#xff0c;有效识别和清理一些恶意的网络流量&#xff0c;为用户提供安全且稳定的网络环境&#xff0c;那么&#xff0c;高防服务器一般都可以抵御哪些网络攻击呢&#xff1f;下面…...

Swagger和OpenApi的前世今生

Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章&#xff0c;二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑&#xff1a; &#x1f504; 一、起源与初创期&#xff1a;Swagger的诞生&#xff08;2010-2014&#xff09; 核心…...

Golang——7、包与接口详解

包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...

Linux系统部署KES

1、安装准备 1.版本说明V008R006C009B0014 V008&#xff1a;是version产品的大版本。 R006&#xff1a;是release产品特性版本。 C009&#xff1a;是通用版 B0014&#xff1a;是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存&#xff1a;1GB 以上 硬盘&#xf…...

深度剖析 DeepSeek 开源模型部署与应用:策略、权衡与未来走向

在人工智能技术呈指数级发展的当下&#xff0c;大模型已然成为推动各行业变革的核心驱动力。DeepSeek 开源模型以其卓越的性能和灵活的开源特性&#xff0c;吸引了众多企业与开发者的目光。如何高效且合理地部署与运用 DeepSeek 模型&#xff0c;成为释放其巨大潜力的关键所在&…...