GAMES101-Assignment8

一、总览

1.1 连接绳子的约束

在rope.cpp 中, 实现Rope 类的构造函数。这个构造函数应该可以创建一个
新的绳子(Rope) 对象,该对象从start 开始,end 结束,包含num_nodes 个节点。也就是如下图所示:
在这里插入图片描述

每个结点都有质量,称为质点;质点之间的线段是一个弹簧。通过创建一系列的质点和弹簧,你就可以创建一个像弹簧一样运动的物体。
pinned_nodes 设置结点的索引。这些索引对应结点的固定属性(pinned attribute)应该设置为真(他们是静止的)。对于每一个结点,你应该构造一个Mass对象,并在Mass对象的构造函数里设置质量和固定属性。(请仔细阅读代码,确定传递给构造函数的参数)。你应该在连续的两个结点之间创建一个弹簧,设置弹簧两端的结点索引和弹簧系数k,请检查构造函数的签名以确定传入的参数。
运行./ropesim。你应该可以看到屏幕上画出绳子,但它不发生运动。

1.2 显式/半隐式欧拉法

胡克定律表示弹簧连接的两个质点之间的力和他们之间的距离成比例。也就是:
在这里插入图片描述

在Rope::simulateEuler 中, 首先实现胡克定律。遍历所有的弹簧,对弹簧两端的质点施加正确的弹簧力。保证力的方向是正确的!对每个质点,累加所有的弹簧力。
一旦计算出所有的弹簧力,对每个质点应用物理定律:
在这里插入图片描述

运行./ropesim。仿真应该就开始运行了,但是只有3 个结点,看起来不够多。在application.cpp 文件的最上方,你应该可以看到欧拉绳子Verlet绳子的定义。改变两个绳子结点个数(默认为3个),比如16或者更多。
运行./ropesim -s 32 来设置仿真中每帧不同的仿真步数。尝试设置较小的
值和较大的值(默认值为64)。

1.3 显式Verlet

Verlet 是另一种精确求解所有约束的方法。这种方法的优点是只处理仿真中
顶点的位置并且保证四阶精度。和欧拉法不同,Verlet 积分按如下的方式来更新下一步位置:
在这里插入图片描述

除此之外,我们可以仿真弹簧系数无限大的弹簧。不用再考虑弹簧力,而是用解约束的方法来更新质点位置:只要简单的移动每个质点的位置使得弹簧的长度保持原长。修正向量应该和两个质点之间的位移成比例,方向为一个质点指向另一质点。每个质点应该移动位移的一半。
只要对每个弹簧执行这样的操作,我们就可以得到稳定的仿真。为了使运动更加平滑,每一帧可能需要更多的仿真次数。

1.4 阻尼

向显示Verlet方法积分的胡克定律中加入阻尼。现实中的弹簧不会永远跳动,因为动能会因摩擦而减小。阻尼系数设置为0.00005, 加入阻尼之后质点位置更新如下:
在这里插入图片描述

应该修改的函数是:

  • rope.cpp 中的Rope::rope(…)
  • rope.cpp 中的void Rope::simulateEuler(…)
  • rope.cpp 中的void Rope::simulateVerlet(…)

二、安装依赖

$ sudo apt install libglu1-mesa-dev freeglut3-dev mesa-common-dev
$ sudo apt install xorg-dev

三、参考答案

3.1 rope.cpp中的Rope::rope(…)

实现1.1 连接绳子的约束

    Rope::Rope(Vector2D start, Vector2D end, int num_nodes, float node_mass, float k, vector<int> pinned_nodes){// TODO (Part 1): Create a rope starting at `start`, ending at `end`, and containing `num_nodes` nodes.for(int i = 0; i < num_nodes; i++){// 创建质点Vector2D pos = start + (end - start) * (double(i) / double(num_nodes));masses.push_back(new Mass(pos, node_mass, false));}for(int i = 0; i < num_nodes - 1; i++){// 创建弹簧springs.push_back(new Spring(masses[i], masses[i + 1], k));}
//        Comment-in this part when you implement the constructorfor (auto &i : pinned_nodes) {masses[i]->pinned = true;}}

3.2 rope.cpp 中的void Rope::simulateEuler(…)

实现1.2 显式/半隐式欧拉法

  • 胡克定律
    在这里插入图片描述
    for (auto &s : springs){// TODO (Part 2): Use Hooke's law to calculate the force on a nodeauto len = (s->m1->position - s->m2->position).norm();s->m1->forces += -s->k * (s->m1->position - s->m2->position) / len * (len - s->rest_length);s->m2->forces += -s->k * (s->m2->position - s->m1->position) / len * (len - s->rest_length);}
  • 显式/隐式欧拉法
    在这里插入图片描述
    if (!m->pinned){// TODO (Part 2): Add the force due to gravity, then compute the new velocity and position// 显式欧拉法:下一个时刻位置用当前速度计算auto a = m->forces / m->mass + gravity;m->position += m->velocity * delta_t;//根据当前速度更新位置m->velocity += a * delta_t;//更新下一时刻速度// 隐式欧拉法:下一个时刻位置用下一时刻速度计算// auto a = m->forces / m->mass + gravity;// m->velocity += a * delta_t;//更新速度// m->position += m->velocity * delta_t;//根据下一时刻速度更新位置 // TODO (Part 2): Add global damping}

  • 完整代码
    void Rope::simulateEuler(float delta_t, Vector2D gravity){for (auto &s : springs){// TODO (Part 2): Use Hooke's law to calculate the force on a nodeauto len = (s->m1->position - s->m2->position).norm();s->m1->forces += -s->k * (s->m1->position - s->m2->position) / len * (len - s->rest_length);s->m2->forces += -s->k * (s->m2->position - s->m1->position) / len * (len - s->rest_length);}for (auto &m : masses){if (!m->pinned){// TODO (Part 2): Add the force due to gravity, then compute the new velocity and position// 显式欧拉法:下一个时刻位置用当前速度计算auto a = m->forces / m->mass + gravity;m->position += m->velocity * delta_t;//根据当前速度更新位置m->velocity += a * delta_t;//更新下一时刻速度// 隐式欧拉法:下一个时刻位置用下一时刻速度计算// auto a = m->forces / m->mass + gravity;// m->velocity += a * delta_t;//更新速度// m->position += m->velocity * delta_t;//根据下一时刻速度更新位置 // TODO (Part 2): Add global damping}// Reset all forces on each massm->forces = Vector2D(0, 0);}}

3.3 rope.cpp 中的void Rope::simulateVerlet(…)

实现1.3 显式Verlet

  • 显式Verlet
    在这里插入图片描述
    void Rope::simulateVerlet(float delta_t, Vector2D gravity){for (auto &s : springs){// TODO (Part 3): Simulate one timestep of the rope using explicit Verlet (solving constraints)auto len = (s->m1->position - s->m2->position).norm();s->m1->forces += -s->k * (s->m1->position - s->m2->position) / len * (len - s->rest_length);s->m2->forces += -s->k * (s->m2->position - s->m1->position) / len * (len - s->rest_length);}for (auto &m : masses){if (!m->pinned){Vector2D temp_position = m->position;// TODO (Part 3.1): Set the new position of the rope massauto a = m->forces / m->mass + gravity;m->position = temp_position + (temp_position - m->last_position) + a * delta_t * delta_t;m->last_position = temp_position;// TODO (Part 4): Add global Verlet damping}m->forces = Vector2D(0, 0);}}

3.4 增加阻尼

  • rope.cpp 中的void Rope::simulateVerlet(…)
    向显示Verlet方法积分的胡克定律中加入阻尼。现实中的弹簧不会永远跳动,因为动能会因摩擦而减小。阻尼系数设置为0.00005, 加入阻尼之后质点位置更新如下:
    在这里插入图片描述
    void Rope::simulateVerlet(float delta_t, Vector2D gravity){for (auto &s : springs){// TODO (Part 3): Simulate one timestep of the rope using explicit Verlet (solving constraints)auto len = (s->m1->position - s->m2->position).norm();s->m1->forces += -s->k * (s->m1->position - s->m2->position) / len * (len - s->rest_length);s->m2->forces += -s->k * (s->m2->position - s->m1->position) / len * (len - s->rest_length);}for (auto &m : masses){if (!m->pinned){Vector2D temp_position = m->position;// TODO (Part 3.1): Set the new position of the rope massauto a = m->forces / m->mass + gravity;//m->position = temp_position + (temp_position - m->last_position) + a * delta_t * delta_t;//m->last_position = temp_position;// TODO (Part 4): Add global Verlet dampingdouble damping_factor = 0.00005;m->position = temp_position + (1 - damping_factor) * (temp_position - m->last_position) + a * delta_t * delta_t;m->last_position = temp_position;}m->forces = Vector2D(0, 0);}}
  • rope.cpp 中的void Rope::simulateEuler(…)
    向欧拉方法中加入阻尼,直接使用−kdv作为阻尼,而不是相对速度
    void Rope::simulateEuler(float delta_t, Vector2D gravity){for (auto &s : springs){// TODO (Part 2): Use Hooke's law to calculate the force on a nodeauto len = (s->m1->position - s->m2->position).norm();s->m1->forces += -s->k * (s->m1->position - s->m2->position) / len * (len - s->rest_length);s->m2->forces += -s->k * (s->m2->position - s->m1->position) / len * (len - s->rest_length);}for (auto &m : masses){if (!m->pinned){// TODO (Part 2): Add the force due to gravity, then compute the new velocity and position// 显式欧拉法:下一个时刻位置用当前速度计算// auto a = m->forces / m->mass + gravity;// m->position += m->velocity * delta_t;//根据当前速度更新位置// m->velocity += a * delta_t;//更新下一时刻速度// 隐式欧拉法:下一个时刻位置用下一时刻速度计算// auto a = m->forces / m->mass + gravity;// m->velocity += a * delta_t;//更新速度// m->position += m->velocity * delta_t;//根据下一时刻速度更新位置 // TODO (Part 2): Add global dampingfloat kd = 0.005;auto a = m->forces / m->mass + gravity - kd * m->velocity / m->mass;m->velocity += a * delta_t; m->position += m->velocity * delta_t; //隐式欧拉法}// Reset all forces on each massm->forces = Vector2D(0, 0);}}

四、编译

$ mkdir build
$ cd build
$ cmake ..
$ make

通过查看rope.cpp中的Rope::rope(…)的引用,可以定位到application.cpp文件,

// Create two ropes 
// 通过修改构造函数的第三个参数指定质点个数(默认三个质点,这里改成了10个)
ropeEuler = new Rope(Vector2D(0, 200), Vector2D(-400, 200), 10, config.mass,config.ks, {0});
ropeVerlet = new Rope(Vector2D(0, 200), Vector2D(-400, 200), 10, config.mass,config.ks, {0});

附件

作业7压缩包

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

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

相关文章

【论文阅读】Automated Runtime-Aware Scheduling for Multi-Tenant DNN Inference on GPU

该论文发布在 ICCAD’21 会议。该会议是EDA领域的顶级会议。 基本信息 AuthorHardwareProblemPerspectiveAlgorithm/StrategyImprovment/AchievementFuxun YuGPUResource under-utilization ContentionSW SchedulingOperator-level schedulingML-based scheduling auto-searc…

Rustdesk 中VP8 / VP9 / AV1 是什么?

环境&#xff1a; Rustdesk1.1.9 VP8 / VP9 / AV1 问题描述&#xff1a; VP8 / VP9 / AV1 是什么&#xff1f; 解决方案&#xff1a; 1.VP8、VP9和AV1是视频编解码器&#xff0c;用于压缩和解压缩视频数据。它们是由Google和Alliance for Open Media&#xff08;AOM&#…

011 变量

变量的定义 注意事项 作用域 类变量&#xff1a;定义在类中的变量&#xff0c;类的整个生命周期内可用实例变量&#xff1a;定义在类中的变量&#xff0c;类的实例可以使用局部变量&#xff1a;定义在方法中的变量&#xff0c;仅在方法内可以使用 class Dog{// 类变量static …

机器学习 | 深入理解并掌握核心概念

在如今数字化时代的浪潮下&#xff0c;机器学习已经成为人工智能领域的璀璨明星。它像一面魔镜&#xff0c;赋予计算机系统学习和改进的能力&#xff0c;让机器能够从海量数据中提取规律、预测未来&#xff0c;甚至做出智能决策。本 专栏 将带您踏上机器学习的奇妙之旅&#xf…

题解:CF1920E. Counting Binary Strings

题解&#xff1a;CF1920E. Counting Binary Strings 题意简述 题目链接&#xff1a;Problem - E - Codeforces。 洛谷翻译&#xff1a;Counting Binary Strings - 洛谷。 思路解析 假设我们有一个01串str&#xff08;设里面有z个“1”&#xff09;&#xff0c;我们要求它里…

【MySQL进阶】视图_存储过程_存储函数_触发器

文章目录 视图基本介绍视图操作视图创建视图查询视图修改视图删除 存储过程基本介绍基本操作存储语法变量IF语句参数传递CASEWHILEREPEATLOOP游标 存储函数触发器基本介绍基本操作 总结 视图 基本介绍 视图概念&#xff1a;视图是一种虚拟存在的数据表&#xff0c;这个虚拟的表…

透明拼接屏在汽车领域的应用

随着科技的进步&#xff0c;透明拼接屏作为一种新型的显示技术&#xff0c;在汽车领域的应用越来越广泛。尼伽小编将围绕透明拼接屏在汽车本身、4S店、展会、工厂等方面的应用进行深入探讨&#xff0c;并展望未来的设计方向。 一、透明拼接屏在汽车本身的应用 车窗显示&#x…

Python入门(一)

anaconda安装 官网&#xff1a;https://www.anaconda.com下载 jupyter lab 简介&#xff1a; 包含了Jupyter Notebook所有功能。 JupyterLab作为一种基于web的集成开发环境&#xff0c;你可以使用它编写notebook&#xff0c;操作终端&#xff0c;编辑markdown文本&#xf…

Linux中文件属性的获取(stat、chmod、Istat、fstat函数的使用)

修改文件权限 函数如下&#xff1a; chmod/fchmod函数用来修改文件的访问权限: #include <sys/stat.h> int chmod(const char *path, mode_t mode); int fchmod(int fd, mode_t mode); 成功时返回0&#xff1b;出错时返回EOF 注意&#xff1a;在vmware和windows共享的文…

NetSuite 文心一言(Ernie)的AI应用

有个故事&#xff0c;松下幸之助小时候所处的年代是明治维新之后&#xff0c;大量引用西洋技术的时期。当时大家对“电”能干什么事&#xff0c;充满好奇。“电能干什么&#xff1f;它能帮我们开门么&#xff1f;” 松下幸之助的爷爷对电不屑&#xff0c;于是就问他。松下幸之助…

【新闻感想】谈一下PandoraNext的覆灭(潘多拉Next-国内可访问的免费开放GPT共享站将于2024年1月30日关闭)

文章目录 悲报&#xff1a;TIME TO SAY GOODBYE&#xff01;PandoraNext&#xff01;PandoraNext作者言&#xff1a;你们赢了&#xff0c;但我却没有输我如何了解到PandoraNext的合照留念于是开始逆向&#xff01; 悲报&#xff1a;TIME TO SAY GOODBYE&#xff01;PandoraNext…

Java入门高频考查基础知识5(扎实技术基础应变一切变化-45题4.2万字参考答案)

技术变革裁员影响的因素&#xff1a; 自动化替代简单重复性工作&#xff1a;随着技术的发展&#xff0c;一些简单、重复性的编码任务可能被自动化工具或者机器学习算法取代。这可能导致一些岗位的需求减少或者消失&#xff0c;从而可能导致部分人员裁员。 技能更新要求&#x…

大模型日报-20240122

清华、小米、华为、 vivo、理想等多机构联合综述&#xff0c;首提个人LLM智能体、划分5级智能水平 https://mp.weixin.qq.com/s/JYB4BzsXhWF8pEUUkvn_GQ 想必这些唤醒词中至少有一个曾被你的嘴发出并成功呼唤出了一个能给你导航、讲笑话、添加日程、设置闹钟、拨打电话的智能个…

【.NET Core】深入理解异步编程模型(APM)

【.NET Core】深入理解异步编程模型&#xff08;APM&#xff09; 文章目录 【.NET Core】深入理解异步编程模型&#xff08;APM&#xff09;一、APM概述二、IAsyncResult接口2.1 BeginInvoke2.2 EndInvoke2.3 IAsyncResult属性2.4 IAsyncResult异步演示 三、通过结束异步操作来…

系统架构演变

1.1系统架构的演变 2008年以后&#xff0c;国内互联网行业飞速发展&#xff0c;我们对软件系统的需求已经不再是过去”能用就行”这种很low的档次了&#xff0c;像抢红包、双十一这样的活动不断逼迫我们去突破软件系统的性能上限&#xff0c;传统的IT企业”能用就行”的开发思…

yum下载源,vim使用

文章目录 yum本地配置lzrsz命令行互传scp(远程拷贝)vim yum本地配置 [rootiZf8z3j2ckkap6ypn717msZ ~]# pwd /root [rootiZf8z3j2ckkap6ypn717msZ ~]# ls /etc/yum.repos.d CentOS-Base.repo epel.repo //本地配置源yum会根据/etc/yum.repo.d路径下的配置文件来构成自己的下载…

人类行为动作数据集大合集

最近收集了一大波关于人类行为动作的数据集&#xff0c;主要包括&#xff1a;动作识别、行为识别、活动预测、动作行为分类等数据集。废话不多说&#xff0c;接下来就给大家介绍这些数据集&#xff01;&#xff01; 1、用于自动视频编辑的视频Blooper数据集 用于自动视频编辑…

idea中debug Go程序报错error layer=debugger could not patch runtime.mallogc

一、问题场景 在idea中配置了Go编程环境&#xff0c;可以运行Go程序&#xff0c;但是无法debug&#xff0c;报错error layerdebugger could not patch runtime.mallogc: no type entry found, use ‘types’ for a list of valid types 二、解决方案 这是由于idea中使用的d…

SpringBoot统一返回和统一异常处理

Session 认证和 Token 认证 过滤器和拦截器 SpringBoot统一返回和统一异常处理 上篇文章我们学习了基于 Token 认证的登录功能实现&#xff0c;分别使用了过滤器和拦截器去实现登录功能&#xff0c;这篇文章我们来学习项目中常用的统一返回结果和统一异常处理。 一、统一返…

【LeetCode每日一题】670. 最大交换

2024-1-22 文章目录 [670. 最大交换](https://leetcode.cn/problems/maximum-swap/)思路&#xff1a; 670. 最大交换 思路&#xff1a; 从后往前遍历整数的字符数组&#xff0c;找到第一个比当前最大值小的数字&#xff0c;然后将该数字与最大值进行交换。 将给定的整数转换为…