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

news2024/11/24 10:31:56

源码见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 Simulation1
    
    Mass** masses; // In Simulation
    
  2. 构造函数Simulation1 的构造函数接受两个参数,分别表示二维物体的行数和列数,而 Simulation 的构造函数只接受一个参数,表示一维质点链的长度。

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

    Mass* getMass(int x, int y) // In Simulation1
    
    Mass* 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 Simulation1
    
    for (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

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

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

相关文章

场外个股期权为什么那么火?收益翻倍不是梦!

今天带你了解场外个股期权为什么那么火&#xff1f;收益翻倍不是梦&#xff01;场外个股期权&#xff0c;与交易所交易的标准化期权相比&#xff0c;是在场外市场进行交易的定制化金融衍生品&#xff0c;很多人都很疑惑&#xff0c;场外个股期权咋就火起来了&#xff1f; 场外…

E810网卡驱动安装-适用于centos7.9

安装E810网卡驱动 问题现象处理过程最后 问题现象 新上的物理机&#xff0c;重新装最小化安装了centos7.9操作系统&#xff0c;系统起来后未发现有网卡&#xff0c;只有本地环回口 处理过程 第一点怀疑就是没有装驱动&#xff0c;因为我使用是浪潮的服务器&#xff0c;就到官…

LeetCode—string练习

415.字符串相加 . - 力扣&#xff08;LeetCode&#xff09; 错误示范&#xff1a; 遇到这种我们第一想法就是将字符串转化成整数&#xff0c;但这种解法无法提交通过&#xff0c;只能支持将小数字互相转化&#xff0c;遇到较长的字符串就没法通过。 class Solution { public…

【STM32项目设计】STM32F411健康助手--三脚--波轮开关--外部中断输入(3)

硬件设计 软件设计 key.c 波轮按键默认为低电平&#xff0c;需要配置为下拉输入&#xff0c;如果浮空的话电压会在1.8v上下波动&#xff0c;单片机检测会出现异常。波动时为高电平&#xff0c;设置为高电平触发。 key0是一个普通按键&#xff0c;忽略即可&#xff0c;key1~3为…

批量剪辑+批量发布的短视频矩阵系统,你真的需要吗?

矩阵的概念&#xff0c;可以简单理解成一种放大和复制的策略。就像你经营一家某宝店铺&#xff0c;如果每天能赚100元&#xff0c;那么通过开设更多的店铺&#xff0c;比如50家&#xff0c;你的日收入就能达到5000元。这就是所谓的“矩阵店铺”&#xff0c;它的核心在于通过增加…

uniapp使用uni-popup做底部弹出选项(vue3)

效果图 页面代码 <!-- 发票筛选弹出框 --><uni-popup ref"popupRef" type"bottom" border-radius"10px 10px 0 0" background-color"#fff"><h4 style"text-align: center;margin-bottom: 20px;">发票筛…

微服务配置管理

小编目前大一&#xff0c;刚开始着手学习微服务的相关知识&#xff0c;小编会把它们整理成知识点发布出来。我认为同为初学者&#xff0c;我把我对知识点的理解以这种代码加观点的方式分享出来不仅加深了我的理解&#xff0c;或许在某个时候对你也有所帮助&#xff0c;同时也欢…

计算机毕业设计选题推荐-企业人事管理系统-Java/Python项目实战

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…

Mysql(一) - 数据库操作, 表操作, CRUD

目录 一.数据库操作 1.增加数据库 2.展示数据库 3.删除数据库 4.选定数据库 二.表操作 1.增加选定数据库中的表 2.展示选定数据库中的表 3.删除选定数据库中表 4.查看选定表的字段信息 三.增加和查找 1.增加 2.查找 a.where的使用 b.分页查询 四.更新和删除 1.…

Spring及Springboot事件机制详解

程序设计的所有原则和方法论都是追求一件事——简单——功能简单、依赖简单、修改简单、理解简单。因为只有简单才好用&#xff0c;简单才好维护。因此&#xff0c;不应该以评论艺术品的眼光来评价程序设计是否优秀&#xff0c;程序设计的艺术不在于有多复杂多深沉&#xff0c;…

中资优配:“迪王”,拔得头筹!

Wind数据闪现&#xff0c;现在已有逾越190家上市公司入围券商9月“金股”组合。从举荐频次看&#xff0c;“迪王”比亚迪拔得头筹&#xff0c;阳光电源、我国移动等标的获券商密布举荐&#xff0c;医药生物等工作含“金”量高。 展望9月商场&#xff0c;券商判别&#xff0c;其…

真实:关于源代码防泄漏工作一些经验分享

互联网的飞速发展&#xff0c;各行各业都在往数字化转型&#xff0c;很多传统的业务数据都需要逐渐录入到电脑中&#xff0c;不仅节省了空间&#xff0c;还节约了成本。而这些数据都需要通过各类型的应用程序&#xff0c;进行分类&#xff0c;统计&#xff0c;展示&#xff0c;…

远程桌面连接出现身份验证错误解决方法

远程桌面身份验证错误的原因是什么&#xff1f; 在尝试远程连接到其他设备时&#xff0c;您可能会遇到身份验证错误&#xff0c;通常会弹出提示“出现身份验证错误&#xff0c;要求的函数不受支持”。这种身份验证错误通常是因为您输入的凭据与受控设备上设置的安全帐户信息不…

B端系统门门清之:CRM-客户管理系统,客户是一切的源头。

公司最宝贵的是什么&#xff0c;有人说是人才、有人说品牌、还有人说是技术&#xff0c;错&#xff0c;大错特错了&#xff0c;最宝贵的永远是客户&#xff0c;没有了客户&#xff0c;人才、品牌、技术都无从谈起。 今天分享最常见的B端系统CRM&#xff0c;那么是什么是CRM呢&…

大模型技术开发与应用

大模型技术开发与应用 LLM背景知识介绍: 大语言模型是一种人工智能模型,旨在理解和生成人类语言.大语言模型可以处理多种自然语言任务,如文本分类,问答,翻译,对话等等. 通常,大语言模型(LLM)是指包含数千亿(或更多)参数的语言模型(目前定义参数数量超过10B的模型为大语言模…

UI自动化测试 —— web端元素获取元素等待实践!

前言 Web UI自动化测试是一种软件测试方法&#xff0c;通过模拟用户行为&#xff0c;自动执行Web界面的各种操作&#xff0c;并验证操作结果是否符合预期&#xff0c;从而提高测试效率和准确性。 目的&#xff1a; 确保Web应用程序的界面在不同环境(如不同浏览器、操作系统)下…

注册登陆(最新版)

整体概述 本项目中&#xff0c;使用数据库连接池实现服务器访问数据库的功能&#xff0c;使用POST请求完成注册和登录的校验工作。 本文内容 本篇将介绍同步实现注册登录功能&#xff0c;具体的涉及到流程图&#xff0c;载入数据库表&#xff0c;提取用户名和密码&#xff0…

AquaCrop模型数据制备、优化方法、敏感性与气候变化影响分析及源码解析

AquaCrop是由世界粮食及农业组织&#xff08;FAO&#xff09;开发的一个先进模型&#xff0c;旨在研究和优化农作物的水分生产效率。这个模型在全球范围内被广泛应用于农业水管理&#xff0c;特别是在制定农作物灌溉计划和应对水资源限制方面显示出其强大的实用性。AquaCrop 不…

PySide6复杂C/S系统开发

PySide6复杂C/S系统开发 目录 0.了解 1.前提 2.实际代码&#xff08;继承QGraphicsview修改&#xff09; 0.了解 之前写了一篇“PySimpleGUI复杂C/S系统开发”博客&#xff08;由于pysimplegui更改了协议&#xff0c;因此不再推荐&#xff0c;用了pyside6后yyds&#xff09…

Transiting from CUDA to HIP (二)

一、Identifying Architecture Features 1. HIP_ARCH Defines 在 CUDA 编程中&#xff0c;__CUDA_ARCH__ 是一个预定义的宏&#xff0c;用于指示当前编译的代码所针对的 NVIDIA GPU 的计算能力&#xff08;Compute Capability&#xff09;。开发者可以使用这个宏来编写条件代…