OpenGL/GLUT实践:弹簧-质量-阻尼系统模拟摆动的绳子和布料的物理行为(电子科技大学信软图形与动画Ⅱ实验)

本文主要是介绍OpenGL/GLUT实践:弹簧-质量-阻尼系统模拟摆动的绳子和布料的物理行为(电子科技大学信软图形与动画Ⅱ实验),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

文章目录

    • 1 实现效果
    • 2 实现过程
      • 2.1 一维弹性物体模拟
        • 2.1.1 质点类(Mass)
        • 2.1.2 弹簧类(Spring)
        • 2.1.3 模拟类(RopeSimulation)
        • 2.1.4 openGL实现
      • 2.2 二维弹性物体模拟
        • 2.2.1 模拟类改进
          • (1) Simulation1 类
          • (2) ClothSimulation 类
        • 2.2.2 openGL 渲染
        • 2.2.3 鼠标互动
        • 2.2.4 最终实现

1 实现效果

二维的弹性物体最终实现的效果如下:

recording

2 实现过程

2.1 一维弹性物体模拟

2.1.1 质点类(Mass)

质点类(Mass)是用于表示弹性物体中的单个质点的关键组件之一。在这个类中,我们记录了质点的基本信息,包括质量、位置、速度和受力。下面是对质点类中关键成员和方法的说明:

  • float m: 质点的质量。质量决定了质点对外力的响应程度。
  • Vector3D pos: 质点在空间中的位置。位置向量用来描述质点的位置。
  • Vector3D vel: 质点的速度。速度向量表示质点在各个方向上的运动速度。
  • Vector3D force: 质点所受的外力。在每个时间步长内,质点可能受到多个外力的作用,这些外力的向量和即为质点所受的总外力。

以下是质点类中的关键方法:

  • applyForce(Vector3D force):用于将外力应用于质点上。在一段时间内,可能会有多个外部力作用于质点上,因此我们将这些外力向量相加,得到质点所受的总外力。
  • init():初始化方法,将质点的外力值设为零。在每个时间步长开始时,我们需要将质点的外力重置为零,以便计算新的外力。
  • simulate(float dt):模拟方法,根据质点所受的外力和牛顿运动定律,计算质点在时间步长 dt 内的新位置和新速度。这里采用了欧拉方法(Euler Method)进行数值积分,它虽然简单但通常足够用于大多数物理模拟。

质点类是模拟弹性物体运动过程中的基础,通过不断更新质点的状态,我们可以模拟出弹性物体在外力作用下的运动行为。

2.1.2 弹簧类(Spring)

弹簧类(Spring)是用于模拟弹簧连接的两个质点之间的作用力的关键组件。在这个类中,我们记录了弹簧的基本信息,包括连接的两个质点、弹簧的刚度和长度,以及内部阻尼的影响。下面是对弹簧类中关键成员和方法的说明:

  • Mass* mass1Mass* mass2: 弹簧连接的两个质点。这两个质点受到弹簧作用的力,质点运动受到弹簧力的影响。
  • float springConstant: 弹簧的刚度常数。它决定了弹簧对质点施加的力的大小。
  • float springLength: 弹簧的静止长度。当两个质点的距离等于静止长度时,弹簧不会施加力。
  • float frictionConstant: 弹簧的内部阻尼系数。它描述了弹簧内部摩擦的程度。

以下是弹簧类中的关键方法:

solve(): 解决方法,用于计算弹簧连接的两个质点受到的合力。

  1. 首先计算两个质点之间的距离,并根据距离计算弹簧的伸长量。

    float r = springVector.length();

  2. 然后根据伸长量和弹簧的刚度常数计算弹簧对质点施加的力。

    • e = springVector / r;:计算弹簧的单位方向向量。springVector 是弹簧两端质点之间的位移向量,通过除以该向量的长度 r,可以得到单位方向向量 e
    • force += e * (r - springLength) * (-springConstant);:计算弹簧的弹性力。根据胡克定律,弹簧的弹性力与弹簧的伸长量成正比,方向与弹簧的单位方向向量相同。r - springLength 表示当前弹簧的伸长量,乘以弹簧的弹性常数 springConstant,即可得到弹簧的弹性力大小。
    • force += -e * (mass1->vel*e - mass2->vel*e) * frictionConstant;:计算弹簧的摩擦力。摩擦力与两个质点之间的相对速度以及弹簧的内摩擦常数成正比。(mass1->vel*e - mass2->vel*e) 计算了两个质点之间的相对速度在弹簧方向上的分量,然后乘以内摩擦常数 frictionConstant,即可得到摩擦力的大小。
  3. 最后,将弹簧力施加到两个质点上,以更新它们的受力状态。

弹簧类是模拟弹性物体运动过程中的关键组件之一,通过模拟弹簧连接的两个质点之间的作用力,我们可以模拟出弹簧在外力作用下的伸缩变形情况,从而实现对弹性物体的模拟。

2.1.3 模拟类(RopeSimulation)

模拟类是整个模拟系统的核心,负责协调质点和弹簧之间的相互作用,并模拟一维弹性物体的运动过程。在模拟类中,我们创建了弹簧数组,并初始化了所有的弹簧。然后,在每个时间步长内,我们通过迭代计算所有弹簧的受力情况,并更新所有质点的位置和速度。下面是对弹簧类中关键成员和方法的说明:

  • Spring** springs;:弹簧数组,用于存储所有弹簧对象的指针。

  • Vector3D gravitation;:表示重力加速度的向量,将作用于所有质点。

  • Vector3D ropeConnectionPos;:绳索连接点的位置向量,用于指定系统中第一个质点的位置。

  • Vector3D ropeConnectionVel;:绳索连接点的速度向量,用于移动绳索连接点。

以下是弹簧类中的关键方法:

  • RopeSimulation(...) 构造函数:初始化模拟对象。在此构造函数中,我们设置了质点的初始位置,创建了弹簧对象,并将其连接到相应的质点上。

  • release() 方法:释放内存,用于删除所有的弹簧对象。

  • solve() 方法:计算系统中所有弹簧的受力情况,包括弹簧的弹性力和重力。然后将这些力应用于相应的质点上。

  • simulate(float dt) 方法:模拟系统的运动过程。在每个时间步长内,首先调用基类的 simulate() 方法更新所有质点的位置和速度。然后更新绳索连接点的位置。

  • setRopeConnectionVel(Vector3D ropeConnectionVel) 方法:设置绳索连接点的速度,用于移动绳索连接点。

通过这些方法,模拟类 RopeSimulation 能够模拟一维弹性物体的运动过程,并在其中考虑了重力、弹簧力以及绳索连接点的运动。

2.1.4 openGL实现

实现了一个基于OpenGL的绳索模拟系统,其中使用了一些物理引擎的概念,如质点、弹簧和重力。

  • RopeSimulation* ropeSimulation = new RopeSimulation(...);:创建了一个绳索模拟对象,设置了模拟所需的参数,如质点数量、质点重量、弹簧常数、弹簧长度等。
  • void renderScene(void):渲染函数,绘制绳索模拟系统的图像,包括绳索的线条表示。
    1. 首先,它设置了视图矩阵和模型矩阵,然后清除颜色缓冲区和深度缓冲区。
    2. 接着,调用了 Update() 函数更新模拟系统的状态。
    3. 最后,通过OpenGL的绘图函数 glBegin()glEnd() 绘制了绳索的形状,以线段的形式连接相邻的质点。绘制完成后,刷新绘图管线并交换缓冲区,使绘制结果显示在屏幕上。

这段代码通过OpenGL实现了一个基本的绳索模拟系统,并提供了键盘控制功能,用户可以通过键盘输入控制绳索的运动方向和停止模拟等。

实现效果如下:

recording

2.2 二维弹性物体模拟

接下来我们要实现一个二维的弹性物体——布料,其就是将之前实现的弹性绳子交叉纵横编织成一个网。

2.2.1 模拟类改进
(1) Simulation1 类

Simulation1 类在 Simulation 类的基础上进行了扩展,以支持二维的弹性物体模拟,而不仅仅是一维的质点链。以下是主要的改进:

  1. 二维质点数组:在 Simulation 类中,质点存储在一个一维数组中。在 Simulation1 类中,质点存储在一个二维数组中,这使得可以模拟一个二维的弹性物体,如布料。

    Mass*** masses; // In Simulation1Mass** masses; // In Simulation
    
  2. 构造函数Simulation1 的构造函数接受两个参数,分别表示二维物体的行数和列数,而 Simulation 的构造函数只接受一个参数,表示一维质点链的长度。

    Simulation1(int numOfMassX, int numOfMassY, float m) // In Simulation1Simulation(int numOfMasses, float m) // In Simulation
    
  3. 获取质点的方法Simulation1 类提供了一个新的 getMass(int x, int y) 方法,可以获取二维数组中的任何一个质点。而 Simulation 类只提供了一个 getMass(int index) 方法,只能获取一维数组中的质点。

    Mass* getMass(int x, int y) // In Simulation1Mass* getMass(int index) // In Simulation
    
  4. 初始化和模拟方法Simulation1 类的 init()simulate(float dt) 方法都使用了两层循环,以处理二维数组中的所有质点。而 Simulation 类的这两个方法只使用了一层循环,只处理一维数组中的质点。

    for (int i = 0; i < row; ++i)for (int j = 0; j < col; ++j)masses[i][j]->init(); // In Simulation1for (int a = 0; a < numOfMasses; ++a)masses[a]->init(); // In Simulation
    

Simulation1 类在 Simulation 类的基础上进行了扩展,以支持二维的弹性物体模拟。

(2) ClothSimulation 类

ClothSimulation类在RopeSimulation类的基础上进行了一些改动以模拟布料的物理行为。以下是一些主要的改动:

  1. ClothSimulation类引入了XlenYlen两个变量,它们分别表示布料在X轴和Y轴方向上的质点数量。这与RopeSimulation类不同,后者只需要一个质点数组来模拟一维的绳索。
  2. ClothSimulation类的构造函数接受两个额外的参数numOfMassesXnumOfMassesY,它们分别表示布料在X轴和Y轴方向上的质点数量。这与RopeSimulation类的构造函数不同,后者只需要一个参数来表示质点的数量。
  3. ClothSimulation类的springs变量是一个四维数组,用于存储布料中的弹簧。每个弹簧都连接着两个相邻的质点。这与RopeSimulation类不同,后者的springs变量是一个二维数组,只需要存储绳索中的弹簧。
  4. ClothSimulation类的simulate方法更新了四个角的质点位置(固定了四个角)和速度,以模拟布料的运动。这与RopeSimulation类的simulate方法不同,后者只更新了第一个质点的位置和速度。
2.2.2 openGL 渲染

renderScene() 主要思想是遍历布料模拟中的所有质点,并绘制连接这些质点的弹簧。弹簧的颜色和宽度由其张力决定。

  1. 通过两层循环遍历所有质点。每个质点都与其右侧和下方的质点相连,形成一个弹簧。

    if (i < clothSimulation->Xlen - 2)if (j < clothSimulation->Ylen - 2) 这两个条件判断确保了不会尝试访问超出数组范围的质点。

  2. 对于每个弹簧,计算其两端质点的距离,以此计算张力。

  3. 根据张力计算颜色强度,张力越大,颜色强度越小。

  4. 使用OpenGL的函数设置线段的颜色和宽度,然后绘制线段。

这样,就可以在屏幕上绘制出一个由弹簧组成的网格,模拟布料的效果。

2.2.3 鼠标互动

mouse()motion() 主要处理鼠标的点击和移动事件,以便在布料模拟中选择和移动质点。

  1. mouse 函数处理鼠标点击事件。当左键被按下时,它会记录鼠标的状态和位置,并将鼠标的屏幕坐标转换为模拟空间的坐标。然后,它会遍历所有的质点,找到距离鼠标位置最近的质点,并记录其位置。当左键被释放时,它会重置鼠标的状态。
  2. motion 函数处理鼠标移动事件。当左键被按下时,它会将鼠标的屏幕坐标转换为模拟空间的坐标,并计算出鼠标移动的距离。然后,它会更新被选中质点的位置,使其沿着鼠标移动的方向移动。最后,它会更新鼠标的位置。

这样就可以通过鼠标操作来选择和移动布料模拟中的质点,从而直观地观察和控制布料的运动。

2.2.4 最终实现

最终实现的效果如下:

recording

这篇关于OpenGL/GLUT实践:弹簧-质量-阻尼系统模拟摆动的绳子和布料的物理行为(电子科技大学信软图形与动画Ⅱ实验)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1133758

相关文章

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

Flutter 进阶:绘制加载动画

绘制加载动画:由小圆组成的大圆 1. 定义 LoadingScreen 类2. 实现 _LoadingScreenState 类3. 定义 LoadingPainter 类4. 总结 实现加载动画 我们需要定义两个类:LoadingScreen 和 LoadingPainter。LoadingScreen 负责控制动画的状态,而 LoadingPainter 则负责绘制动画。

用Unity2D制作一个人物,实现移动、跳起、人物静止和动起来时的动画:中(人物移动、跳起、静止动作)

上回我们学到创建一个地形和一个人物,今天我们实现一下人物实现移动和跳起,依次点击,我们准备创建一个C#文件 创建好我们点击进去,就会跳转到我们的Vision Studio,然后输入这些代码 using UnityEngine;public class Move : MonoBehaviour // 定义一个名为Move的类,继承自MonoBehaviour{private Rigidbo

STM32(十一):ADC数模转换器实验

AD单通道: 1.RCC开启GPIO和ADC时钟。配置ADCCLK分频器。 2.配置GPIO,把GPIO配置成模拟输入的模式。 3.配置多路开关,把左面通道接入到右面规则组列表里。 4.配置ADC转换器, 包括AD转换器和AD数据寄存器。单次转换,连续转换;扫描、非扫描;有几个通道,触发源是什么,数据对齐是左对齐还是右对齐。 5.ADC_CMD 开启ADC。 void RCC_AD

Prometheus与Grafana在DevOps中的应用与最佳实践

Prometheus 与 Grafana 在 DevOps 中的应用与最佳实践 随着 DevOps 文化和实践的普及,监控和可视化工具已成为 DevOps 工具链中不可或缺的部分。Prometheus 和 Grafana 是其中最受欢迎的开源监控解决方案之一,它们的结合能够为系统和应用程序提供全面的监控、告警和可视化展示。本篇文章将详细探讨 Prometheus 和 Grafana 在 DevO

springboot整合swagger2之最佳实践

来源:https://blog.lqdev.cn/2018/07/21/springboot/chapter-ten/ Swagger是一款RESTful接口的文档在线自动生成、功能测试功能框架。 一个规范和完整的框架,用于生成、描述、调用和可视化RESTful风格的Web服务,加上swagger-ui,可以有很好的呈现。 SpringBoot集成 pom <!--swagge

HNU-2023电路与电子学-实验3

写在前面: 一、实验目的 1.了解简易模型机的内部结构和工作原理。 2.分析模型机的功能,设计 8 重 3-1 多路复用器。 3.分析模型机的功能,设计 8 重 2-1 多路复用器。 4.分析模型机的工作原理,设计模型机控制信号产生逻辑。 二、实验内容 1.用 VERILOG 语言设计模型机的 8 重 3-1 多路复用器; 2.用 VERILOG 语言设计模型机的 8 重 2-1 多