OpenGL/GLUT实践:GLUT环境配置+实现反弹运动的三角形动画与键盘控制(电子科技大学信软图形与动画Ⅱ实验)

news2024/11/26 2:53:24

源码见GitHub:A-UESTCer-s-Code

文章目录

    • 1 运行效果
    • 2 实验过程
      • 2.1 环境配置
      • 2.2 绘制三角形
        • 2.2.1 渲染函数
        • 2.2.2 主函数
        • 2.2.3 运行结果
      • 2.3 调整窗口大小
      • 2.4 简单动画与按键控制
        • 2.4.1 简单旋转
        • 2.4.2 键盘控制
      • 2.5 窗口反弹动画
        • 2.5.1 处理窗口大小变化
        • 2.5.2 渲染函数
        • 2.5.3 定时器
        • 2.5.4 控制速度

1 运行效果

我们运行程序,得到一个运动的等腰三角形,当其触碰到边框时会反弹,并且可以通过键盘上的F1、F2、F3来控制颜色,wasd来控制速度。

recording

2 实验过程

2.1 环境配置

OpenGL作为图形显示库,在图形建模、游戏开发和科学可视化等领域有着广泛的应用,而GLUT作为其补充库则提供了方便的窗口管理和用户交互功能,简化了OpenGL程序的开发过程。

步骤:

  1. 下载Glut的依赖库:

    • 访问OpenGL官网或直接从https://www.opengl.org/resources/libraries/glut/glut_downloads.php#windows下载Glut
    • 解压下载文件,得到glut.dllglut32.dllglut.libglut32.libglut.h5个文件
  2. 配置OpenGL环境:

    • glut.h文件复制到 Visual Studio 安装目录下的 include 文件夹内的一个新建名为 GL 的子文件夹中

      image-20240330085410414
    • glut32.lib文件复制到 Visual Studio 安装目录下的lib文件夹中的x86文件夹内

      image-20240330085440530
    • glut.lib文件复制到 Visual Studio 安装目录下的lib文件夹中的x64文件夹内

      image-20240330085509954
    • glut.dllglut32.dll文件复制到系统文件夹 C:\Windows\SysWOW64

      image-20240330085332324
  3. 创建OpenGL项目:

    • 在Microsoft Visual Studio中创建一个控制台应用程序项目

    • 添加源文件(如main.cpp)到项目中

    • 在源文件中引入OpenGL和GLUT库:#include <GL/glut.h>

  4. 编写测试程序:

    • 编写一个简单的OpenGL程序,例如,绘制一个正方形
    • 使用OpenGL提供的函数进行图形绘制
    • 设置窗口的显示模式、大小、位置等参数
    • 编译并运行程序,检查环境配置是否成功

    运行结果:

    image-20240330091416015

2.2 绘制三角形

具体步骤:

2.2.1 渲染函数
void renderScene() {
    glClear(GL_COLOR_BUFFER_BIT); // 清除颜色缓冲区

    // 绘制三角形
    glBegin(GL_TRIANGLES);
    glColor3f(181./225, 206./225, 163./255); // 设置颜色为指定的RGB值
    glVertex2f(-0.88, -0.5); // 左下角
    glVertex2f(0.64, -0.5); // 右下角
    glVertex2f(0.43, 0.7); // 顶点
    glEnd();

    glFlush(); // 刷新绘图命令
}

作用:renderScene() 函数是一个回调函数,在窗口需要被绘制时被调用,用于绘制图形。

细节讲解:

  • glClear(GL_COLOR_BUFFER_BIT);:清除颜色缓冲区,确保每次绘制前都有一个干净的画布

  • glBegin(GL_TRIANGLES);glEnd();:开始和结束绘制三角形的过程

  • glColor3f(181./225, 206./225, 163./255);:设置绘制图形的颜色为指定的RGB值。需要注意的是,这里的颜色值是使用范围在0到1之间的小数来表示的,所以将RGB值除以255来进行归一化处理

  • glVertex2f():指定三角形的顶点坐标,这里使用的是二维坐标

    坐标是以窗口为中心, x x x y y y 轴范围从-11,三角形只需要设置三个顶点即可:

    glVertex2f(-0.88, -0.5); // 左下角
    glVertex2f(0.64, -0.5); // 右下角
    glVertex2f(0.43, 0.7); // 顶点
    
    image-20240330092749677
2.2.2 主函数
int main(int argc, char** argv) {
    glutInit(&argc, argv); // 初始化GLUT库
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); // 设置显示模式为单缓冲和RGB颜色模式
    glutInitWindowSize(400, 400); // 设置窗口大小
    glutInitWindowPosition(100, 100); // 设置窗口位置
    glutCreateWindow("Simple Triangle Test"); // 创建窗口,并设置标题

    glutDisplayFunc(renderScene); // 设置绘图函数

    glutMainLoop(); // 进入主循环,等待事件

    return 0;
}

作用: main() 函数是程序的入口,主要负责初始化OpenGL环境和GLUT库,并进入主循环等待事件。

细节讲解:

  • glutInit(&argc, argv);:初始化GLUT库,接受程序启动时的命令行参数
  • glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);:设置显示模式为单缓冲和RGB颜色模式,这意味着窗口使用单缓冲区,并且颜色采用RGB模式
  • glutInitWindowSize(400, 400);:设置窗口的大小为400x400像素
  • glutInitWindowPosition(100, 100);:设置窗口的位置为屏幕左上角起始点向右下移动100像素的位置
  • glutCreateWindow("Simple Triangle Test");:创建窗口,并设置窗口标题为 “Simple Triangle Test”
  • glutDisplayFunc(renderScene);:注册回调函数 renderScene(),当窗口需要被重绘时会调用该函数进行绘制
  • glutMainLoop();:进入主循环,等待事件的发生,例如窗口的关闭、键盘输入等
2.2.3 运行结果

通过运行得到一个颜色为黄绿色(RGB为181, 206, 163),顶点为(0.43, 0.7)(0.64, -0.5)(-0.88, -0.5)的普通三角形

image-20240330093833522

2.3 调整窗口大小

当我们调整窗口时,图像出现了明显的变形,窗口大小改变会影响OpenGL的视口和投影矩阵,而默认情况下OpenGL使用的是透视投影矩阵,因此窗口大小改变会导致图像的变形。为了解决这个问题,我们需要重新计算投影矩阵,并将其与窗口的新大小相匹配。

image-20240330094129019

在OpenGL中,我们可以使用 glutReshapeFunc() 函数来注册一个回调函数,以便在窗口大小改变时进行处理。这个函数的原型如下:

void glutReshapeFunc(void (*func)(int width, int height));

这个函数将一个自定义的函数与窗口大小改变事件绑定,当窗口大小改变时,该函数就会被调用。

接下来,我们需要编写一个自定义的函数来处理窗口大小改变事件。这个函数应该重新计算投影矩阵,并将其与新的窗口大小相匹配。下面是一个示例函数:

void changeSize(int width, int height) {
    // 避免除以0
    if (height == 0) height = 1;

    // 设置视口大小
    glViewport(0, 0, width, height);

    // 设置投影矩阵
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0f, (GLfloat)width / (GLfloat)height, 0.1f, 100.0f);

    // 切换回模型观察矩阵
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

方法:

为了处理窗口大小的改变,我们使用了OpenGL提供的glutReshapeFunc()函数来注册一个回调函数,该函数会在窗口大小改变时被调用。在这个回调函数中,我们重新计算投影矩阵,并根据新的窗口大小设置视口和透视投影。

具体而言,我们的处理过程包括以下步骤:

  1. 检查窗口的高度是否为0,如果是则将其设置为1,以避免除以0的错误
  2. 计算窗口的宽高比,以便在设置透视投影时使用
  3. 将当前矩阵模式设置为投影矩阵模式,并重置矩阵
  4. 设置OpenGL的视口大小为新的改变后的窗口大小
  5. 使用gluPerspective()函数设置透视投影,其中包括视角大小、宽高比、近裁剪面和远裁剪面的距离
  6. 将当前矩阵模式设置回模型视图矩阵模式,并重置矩阵
  7. 使用gluLookAt()函数设置观察者的视点和方向,以模拟相机在场景中的位置和方向

最后,在 main() 函数中,我们需要将这个自定义的函数与窗口大小改变事件绑定起来,如下所示:

glutReshapeFunc(changeSize);

注意:这个函数要在主循环 glutMainLoop();,否则无法生效(因为程序一直在主循环运行,运行不到这个函数)

通过这样的设置,当我们调整窗口大小时,OpenGL会自动调用 changeSize() 函数来重新计算投影矩阵,从而保证图像的正确显示

执行结果:

recording

2.4 简单动画与按键控制

2.4.1 简单旋转

目的:

本部分旨在实现一个简单的OpenGL动画,让一个三角形在窗口中绕固定轴匀速旋转。

方法:

为了实现动画效果,我们需要做以下几个步骤:

  1. main()函数中,设置双缓冲区模式(GLUT_DOUBLE)以及RGB颜色模式(GLUT_RGB),这样可以避免画面闪烁并且产生平滑的动画效果

    双缓冲区通过在后一个缓冲区里绘画,并不停交换前后缓冲区(可见缓冲区),来产生平滑的动画。使用双缓冲区可以预防闪烁。

  2. 使用glutSwapBuffers()函数在每一帧绘制完毕后切换前后缓冲区,将后台缓冲区的内容绘制到屏幕上

  3. 使用glutTimerFunc()函数设置一个定时器,以一定的时间间隔调用指定的函数,在这个函数中更新动画的状态

  4. 在定时器函数中更新三角形的旋转角度,并重新注册定时器,实现连续的动画效果

    • GLfloat angle = 0;:定义了一个全局变量angle,用于表示旋转角度,初始值为0
    • timer()函数:是一个定时器函数,在每次被调用时更新旋转角度,并请求重绘窗口。这里使用了glutPostRedisplay()函数请求重绘,以触发renderScene()函数的执行。同时,通过glutTimerFunc()函数设置了一个16毫秒的定时器,用于每隔一定时间调用一次timer()函数,从而实现连续的动画效果

    定时器函数

    GLfloat angle = 0; // 设置初始旋转角度
    // 定时器函数,每16ms调用一次,用于旋转三角形
    void timer(int value)
    {
        angle += 1; // 旋转角度
        glutPostRedisplay(); // 重绘
        glutTimerFunc(16, timer, 0); // 设置定时器
    } 
    
  5. 在渲染函数renderScene()中,使用更新后的旋转角度绘制旋转的三角形

    renderScene()函数:在这里,首先清除颜色缓冲区,然后将当前矩阵推入堆栈,接着根据当前的旋转角度对场景进行旋转,绘制一个黄绿色的三角形。最后,通过glutSwapBuffers()函数进行双缓冲区的切换,将后台缓冲区的内容显示到屏幕上。

    // 渲染函数,绘制一个单色的三角形
    void renderScene()
    {
        glClear(GL_COLOR_BUFFER_BIT); // 清除颜色缓冲区
        glPushMatrix();
        glRotatef(angle, 1.0, 0.0, 0.0); // 绕x旋转
        // 绘制三角形
        // ...
        glPopMatrix(); 
        glutSwapBuffers(); // 设置双缓冲
    }
    

结果:
recording

通过以上步骤,我们可以实现一个简单的OpenGL动画,让一个三角形在窗口中不断旋转。动画效果平滑流畅。

2.4.2 键盘控制

普通按键处理:

使用 glutKeyboardFunc 函数来注册处理普通按键事件的回调函数。

  • 普通按键是指字母数字和其他可以用 ASCII 代码表示的键

  • 我们可以在普通按键回调函数中执行相应的操作,例如根据按下的键执行不同的操作,或者响应程序的退出等

    void processNormalKeys(unsigned char key, int x, int y)
    {
        switch (key)
        {
        case 27: // ESC键
            exit(0);
            break;
    }
    

特殊按键处理:

使用 glutSpecialFunc 函数来注册处理特殊按键事件的回调函数。

  • 特殊按键的标识符通常由预定义的常量表示,如 GLUT_KEY_F1GLUT_KEY_LEFT

  • 我们可以在特殊按键回调函数中根据按下的特殊键执行相应的操作,例如改变颜色、移动物体等

    记得将颜色值设为全局变量,渲染时,使用全局变量对颜色进行设置

    void processSpecialKeys(int key, int x, int y)
    {
        switch (key)
        {
        case GLUT_KEY_F1:
            red = 181. / 225;
            green = 206. / 225;
            blue = 163. / 255;
            break;
        case GLUT_KEY_F2:
            red = 163. / 255;
            green = 163. / 255;
            blue = 163. / 255;
            break;
        case GLUT_KEY_F3:
            red = 30. / 255;
            green = 60. / 255;
            blue = 153. / 255;
            break;
        }
    

最后在main函数里面设置这两个回调函数即可

int main(int argc, char** argv)
{
    // ...
    glutSpecialFunc(processSpecialKeys); // 设置特殊键回调函数
    glutKeyboardFunc(processNormalKeys); // 设置普通键回调函数
    // ...
}

运行结果:

recording
  • processSpecialKeys 函数,根据按下的特殊键设置不同的颜色值。具体地,当按下F1键时,设置颜色为黄绿色;按下F2键时,设置颜色为灰色;按下F3键时,设置颜色为蓝色
  • processNormalKeys 函数,增加对ESC键的处理。当按下ESC键时,退出程序

2.5 窗口反弹动画

这一部分,我们要实现可以反弹运动的三角形动画,键盘控制三角形移动速度、颜色。

先引入几个全局变量:

GLfloat x = 0, y = 0, rsize = 50; // 设置初始位置和大小
GLfloat dx = 1.5, dy = 1.5; // 设置初始速度
GLfloat windowWidth, windowHeight; // 窗口大小
GLfloat red = 181. / 225, green = 206. / 225, blue = 163. / 255; // 设置初始颜色为黄绿色
2.5.1 处理窗口大小变化
  • 函数调用 glViewport 函数设置新的视口大小

    glViewport(0, 0, w, h); // 设置视口大小
    
  • 函数计算新的宽高比,并根据宽高比的大小调整窗口的宽度和高度。如果宽度小于或等于高度,那么窗口的宽度被设置为100,高度则根据宽高比进行调整。否则,窗口的高度被设置为100,宽度则根据宽高比进行调整

    aspectRatio = (GLfloat)w / (GLfloat)h; // 计算窗口的宽高比
    if (w <= h)
    {
        windowWidth = 100;
        windowHeight = 100 / aspectRatio;
    }
    else
    {
        windowWidth = 100 * aspectRatio;
        windowHeight = 100;
    }
    

    引入了 windowWidthwindowHeight 全局变量,用于保存窗口的宽度和高度

  • 使用 glOrtho 函数设置正交投影矩阵,将场景限定在一个固定大小的区域内,以保持图形的比例不变

     glOrtho(-windowWidth, windowWidth, -windowHeight, windowHeight, 1.0, -1.0);
    
2.5.2 渲染函数

渲染函数修改:

  • 在绘制三角形时,顶点坐标根据 xy 的值确定,以及矩形大小 rsize 的一半,顶点定义如下:

    glVertex2f(x, y);     
    glVertex2f(x + rsize, y);
    glVertex2f(x + rsize / 2, y + rsize);
    
2.5.3 定时器

修改了定时器函数 timer

  • 先更新位置 xy

    x += dx;
    y += dy;
    
  • 然后检测是否与窗口边界发生碰撞,如果碰撞,则将对应的速度分量 dxdy 取反,实现反弹效果,并稍微调整位置以避免卡在边界上

     // 检测碰撞,如果碰到边界就反弹
     if (x + rsize > windowWidth || x < -windowWidth)
     {
         dx = -dx;
         x += dx; // 稍微调整位置,防止卡在边界上
     }
     if (y + rsize > windowHeight || y < -windowHeight)
     {
         dy = -dy;
         y += dy; // 稍微调整位置,防止卡在边界上
     }
    
  • 使用 glutPostRedisplay() 触发重绘,以更新窗口中的图形

  • 设置定时器每16ms触发一次 glutTimerFunc(16, timer, 1);,以实现动画效果

2.5.4 控制速度

控制速度的实现:

我们使用了 processNormalKeys 函数来处理普通按键事件

  1. 当按下 ESC 键时,程序退出
  2. 当按下 ‘w’ 键时,增加图形在y方向上的速度
  3. 当按下 ‘s’ 键时,减少图形在y方向上的速度,但保证速度不小于0
  4. 当按下 ‘a’ 键时,减少图形在x方向上的速度,但保证速度不小于0
  5. 当按下 ‘d’ 键时,增加图形在x方向上的速度
switch (key)
{
case 27: // ESC键
    exit(0);
    break;
case 'w': // 增加y方向的速度
    dy += 0.1;
    break;
case 's': // 减少y方向的速度,但不小于0
    if (dy > 0)
    {
        dy -= 0.1;            
    }
    break;
case 'a': // 减少x方向的速度,但不小于0
    if (dx > 0)
    {
        dx -= 0.1;            
    }
    break;
case 'd': // 增加x方向的速度
    dx += 0.1;
    break;
}

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

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

相关文章

使用 `Vitesse Uni App` 创建微信小程序并配置 uview-plus 和 alovajs

使用 Vitesse Uni App 创建微信小程序 Vitesse Uni App&#xff1a;https://vitesse-docs.netlify.app/ UI&#xff1a;https://uview-plus.jiangruyi.com/components/intro.html 编辑器&#xff1a;VScode 安装 Volar&#xff08;Vue Offices&#xff09;插件 创建项目 pnpm …

并发编程:ReentrantLock

一、ReentrantLock 是什么&#xff1f; ReentrantLock 实现了 Lock 接口&#xff0c;是一个可重入且独占式的锁&#xff0c;和 synchronized 关键字类似。不过&#xff0c;ReentrantLock 更灵活、更强大&#xff0c;增加了轮询、超时、中断、公平锁和非公平锁等高级功能。 pu…

十一、C语言:字符串函数

目录 一、strlen 二、strcpy 三、strcat 四、strcmp 五、strstr 六、strtok 七、strerror 一、strlen 注意&#xff1a;strlen()函数的返回值是size_t&#xff0c;两个size_t相减仍为无符号数 int main() {char arr[10] "abc";char brr[10] "abc123&quo…

高基数 GroupBy 在 SLS SQL 中的查询加速

作者&#xff1a;顾汉杰&#xff08;执少&#xff09; 什么是高基数 GroupBy 简单来说&#xff0c;想要分析的数据&#xff0c;拥有超多的“唯一值计数”&#xff08;Distinct Count&#xff09;&#xff0c;而我们需要对这些数据进行分组分析&#xff08;如统计次数、排名、…

如何高效调试JavaScript代码:从Console到断点调试

聚沙成塔每天进步一点点 本文回顾 ⭐ 专栏简介如何高效调试JavaScript代码&#xff1a;从Console到断点调试1. 引言2. 基本调试工具概览2.1 浏览器开发者工具&#xff08;DevTools&#xff09;如何打开浏览器开发者工具&#xff1f; 2.2 常用的调试面板 3. 基本调试方法3.1 使用…

Springboot邮箱发送:如何快速集成并发信?

Springboot邮箱发送性能如何&#xff1f;怎么用SpringBoot发信&#xff1f; Springboot作为一款流行的Java框架&#xff0c;提供了简便的方式来集成邮件发送功能。AokSend将详细介绍如何快速集成Springboot邮箱发送功能&#xff0c;并实现高效的邮件发送。 Springboot邮箱发送…

考拉悠然产品发布会丨以悠然远智全模态AI应用平台探索AI行业应用

9月6日&#xff0c;成都市大模型新技术新成果发布暨供需对接系列活动——考拉悠然专场&#xff0c;在成都市高新区菁蓉汇盛大举行。考拉悠然重磅发布了悠然远智丨全模态AI应用平台&#xff0c;并精彩展示了交通大模型应用——智析快处等最新的AI产品和技术成果。 在四川省科学…

警用车载4G5G无线视频监控技术方案

目录 一、背景 二、系统方案设计 1.1系统架构 1.2车载终端 1.3监控中心 1.4传输网络 三、警用车载监控功能特点 2.1警用车载监控功能 &#xff08;1&#xff09;实时视频监控 &#xff08;2&#xff09;录像存储回放 &#xff08;3&#xff09;车载报警联动 &#…

如何清理C盘临时文件,释放10G以上空间

在我们日常使用电脑系统的过程中&#xff0c;想必大家都曾遇到过这样的情况&#xff1a;明明没有主动安装任何软件&#xff0c;然而 C 盘的可用空间却逐渐减少&#xff0c;甚至有时会收到系统发出的空间不足的提醒。 其实&#xff0c;在系统中存在这样一个至关重要的临时文件夹…

【Prometheus】PromQL聚合函数详细用法与应用实战

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

基于springboot+vue乒乓球预约管理系统

基于springbootvuemysql实现的乒乓球预约管理系统&#xff08;源码数据库部署视频&#xff09; ### 主要技术 SpringBoot、LayUI、Vue、MySQL ### 系统角色 用户、管理员 ### 系统功能 前台&#xff1a; 首页、乒乓球场、公告信息、留言反馈、个人中心 后台&#xff1a; …

Nginx解析:入门笔记

&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》《MYSQL》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 ✨欢迎加入探索nginx之旅✨ &#x1f44b; 大家好&#xff01;文本学习和探索Nginx配置。…

【C++ Primer Plus习题】13.2

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream> #include "classic.h&quo…

数据同步-Mysql同步到ElasticSearch

Mysql同步到ElasticSearch 数据同步1、定时任务2、双写3、MQ异步写入4、Logstash5、Canal 数据同步 一般情况下&#xff0c;如果做查询搜索功能&#xff0c;使用 ES 来模糊搜索&#xff0c;但是数据是存放在数据库 MySQL 里的&#xff0c;所以说我们需要把 MySQL 中的数据和 E…

身份证识别及信息核验 API 对接说明

身份证识别及信息核验 API 对接说明 本文将介绍一种 身份证识别及信息核验 API 对接说明&#xff0c;它可以通过输入身份证图片 或 姓名和身份证号码&#xff0c;来校验姓名和身份证号的真实性和一致性。本接口用于校验姓名和身份证号的真实性和一致性&#xff0c;您可以通过输…

SOMEIP_ETS_098: SD_ClientService_subscribe_without_method_call

测试目的&#xff1a; 验证当测试器激活DUT的ETS客户端服务模式并发送OfferService消息时&#xff0c;DUT不会尝试订阅每个接收到的OfferService&#xff0c;因为测试器没有发送必要的clientServiceSubscribeEventgroup消息。 描述 本测试用例旨在确保DUT在没有收到clientSe…

SuiNS的成就与未来愿景

是Sui上领先的域名服务&#xff0c;通过用用户友好、易记的域名替换复杂的钱包地址&#xff0c;提升了链上交互。在过去的两年中&#xff0c;SuiNS经过了多次改进和优化&#xff0c;致力于创建易于理解的链上身份。 借鉴社交媒体的常见用法&#xff0c;SuiNS更进一步&#xff…

这样的接口幂等实现我认为最为优雅(防重复提交)

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 &#x1f38f;&#xff1a;你只管努力&#xff0c;剩下的交给时间 &#x1f3e0; &#xff1a;小破站 这样的接口幂等实现我认为最为优雅 基于token(和网上大部分不一样)对比构思需要幂等性的场景不需…

【无人机设计与控制】用于四轴飞行器仿真和控制系统设计的参数驱动的 Simulink 模型

摘要 本文介绍了一种用于四轴飞行器仿真和控制系统设计的参数驱动Simulink模型。该模型通过参数化设置&#xff0c;允许用户对四轴飞行器的关键性能参数&#xff08;如质量、转动惯量、推力系数等&#xff09;进行调整&#xff0c;从而研究不同参数对飞行器性能的影响。通过此…

安全管理体系化的智慧油站开源了。

AI视频监控平台简介 AI视频监控平台是一款功能强大且简单易用的实时算法视频监控系统。它的愿景是最底层打通各大芯片厂商相互间的壁垒&#xff0c;省去繁琐重复的适配流程&#xff0c;实现芯片、算法、应用的全流程组合&#xff0c;从而大大减少企业级应用约95%的开发成本。用…