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

GAMES101(作业8)

作业8

题目:

模拟绳子动画,包括基于物理的,和非物理的,应该修改的函数是:rope.cpp 中的void Rope::simulateEuler(... Rope::rope(...),,void Rope::simulateVerlet(...)

代码框架:

main:负责接收命令行参数,通过getopt捕获参数设置AppConfig的数据-》创建Application,设置渲染器

  • int getopt(int argc,char * const argv[ ],const char * optstring);用来分析命令行参数

    • 参数argc和argv分别代表参数个数和内容,跟main( )函数的命令行参数是一样的。

    • 参数 optstring为选项字符串

      • 单个字符,表示选项

      • 单个字符后接一个冒号:表示该选项后必须跟一个参数

      • 单个字符后跟两个冒号,表示该选项后可以跟一个参数,也可以不跟。

    • 全域变量optarg指向当前选项参数(如果有)的指针。

CGL:命名空间,包含应用层一下所有模块

application:应用程序

  • AppConfig类,负责从命令行接收信息,mass质点的质量,ks弹簧劲度系数,gravity重力,steps_per_frame每帧仿真步长数

  • Application类继承CGL库中的Renderer

    • 初始化,调用rope的构造函数

    • 渲染,通过opengl库:渲染点(质点),线(弹簧)

void Application::render() {
  //Simulation loops
  for (int i = 0; i < config.steps_per_frame; i++) {/* 每帧仿真步长数 */
    /* 对两个绳子更新这一帧的位置 */
    ropeEuler->simulateEuler(1 / config.steps_per_frame, config.gravity);
    ropeVerlet->simulateVerlet(1 / config.steps_per_frame, config.gravity);
  }
  // Rendering ropes
  Rope *rope;
  /* 分别两个绳子,并设置颜色,和当前绳子*/
  for (int i = 0; i < 2; i++) {
    if (i == 0) {
      glColor3f(0.0, 0.0, 1.0);
      rope = ropeEuler;
    } else {
      glColor3f(0.0, 1.0, 0.0);
      rope = ropeVerlet;
    }
    /* 绘制质点 */
    glBegin(GL_POINTS);

    for (auto &m : rope->masses) {
      Vector2D p = m->position;
      glVertex2d(p.x, p.y);
    }

    glEnd();
    /* 绘制弹簧 */
    glBegin(GL_LINES);

    for (auto &s : rope->springs) {
      Vector2D p1 = s->m1->position;
      Vector2D p2 = s->m2->position;
      glVertex2d(p1.x, p1.y);
      glVertex2d(p2.x, p2.y);
    }

    glEnd();
    /* 提交缓冲区到前台 */
    glFlush();
  }
}

rope:绳子类,包括质点数组,弹簧数组,simulateEuler基于物理的仿真,simulateVerlet非物理的仿真

mass:质点类,包含一个质点,质量,pinned是否是固定的,开始位置,速度,受力等

spring:弹簧类,包括一个弹簧,2个质点,长度,劲度系数k等

解:

首先安装库
sudo apt i n s t a l l l i b g l u 1 −mesa−dev f r e e g l u t 3 −dev \\
mesa−common−dev
sudo apt i n s t a l l xorg−dev #会自 动 安装 l i b f r e e t y p e 6 −dev
 创建绳子

在构造函数中,遍历每个质点,调用mass:类和spring类的构造,并存放到rope的数组中,并且根据参数值,设置mass:对象和spring对象的属性

Vector2D step = (end - start) / (num_nodes - 1);
for(int i = 0; i < num_nodes; i++){
    masses.push_back(new Mass(start + step * i, node_mass, true));
    if(i){
        springs.push_back(new Spring(masses[i-1], masses[i], k));
        masses[i]->pinned = false;
    }
}

 

simulateEuler()

首先遍历绳子的每个弹簧,根据胡可定律计算受到的力,包括ab质点的相互作用力,fr摩擦力,以及空气阻力,带入公式就好

然后遍历每个质点,如果非固定属性,那么根据首先根据f = ma 计算加速度,再根据欧拉方法计算质点的这一步长的位置,+=是上一步长的位置 + 这一步长的增量

for (auto &s : springs)
{
    float length = (s->m2->position - s->m1->position).norm();
    Vector2D dis = s->m2->position - s->m1->position;
    Vector2D force = s->k * (length - s->rest_length) * dis / length;
    s->m1->forces += force;
    s->m2->forces -= force;
    // damping
    Vector2D reve = s->m2->velocity - s->m1->velocity;
    Vector2D force1 = 0.05 * (reve.x * dis.x + reve.y * dis.y) * dis / length;
    s->m1->forces += force1;
    s->m2->forces -= force1;
    // air damping
    s->m1->forces -= 0.005 * s->m1->velocity;
    s->m2->forces -= 0.005 * s->m2->velocity;

for (auto &m : masses)
{
    if (!m->pinned)
    {
        m->forces += gravity;
        m->velocity += m->forces / m->mass * delta_t;
        m->position += m->velocity * delta_t;
        m->forces = Vector2D(0, 0);
}

 

 simulateVerlet()

作业告诉了这个公式, 带入就好

for (auto &s : springs)
{
    float length = (s->m2->position - s->m1->position).norm();
    Vector2D dis = s->m2->position - s->m1->position;
    Vector2D force = s->k * (length - s->rest_length) * dis / length;
    s->m1->forces += force;
    s->m2->forces -= force;
}
for (auto &m : masses)
{
    if (!m->pinned)
    {
        Vector2D temp_position = m->position;
        m->forces += gravity;
        Vector2D pos = m->position;
        m->position += (1 - 0.00005) * (m->position - m->last_position) + m->forces / m->mass * delta_t * delta_t;
        m->last_position = pos;
    }
    m->forces = Vector2D(0, 0);
}

 


http://www.kler.cn/news/325302.html

相关文章:

  • MySQL 加字段锁表怎么解决??
  • 情感短视频素材上哪里找?推荐几个热门情感视频素材资源网站
  • CEPH的写入流程
  • @JsonFormat与@DateTimeFormat的区别
  • 智能监控,守护绿色能源:EasyCVR在电站视频监控中心的一站式解决方案
  • PostgreSQL数据库与PostGIS在Windows中的部署与运行
  • 25基于python的文本冒险岛游戏(源码+游戏简介+python代码学习攻略)校园招聘面试
  • 解决错误:Failed to add the host to the list of known hosts
  • node节点使用:
  • windows下tp5创建定时任务
  • SSH连接Vscode
  • 解决Qt每次修改代码后首次运行崩溃,后几次不崩溃问题
  • 17 vue3之tsx手写vite tsx插件
  • 智能工牌如何通过自然语义处理技术帮助企业提高业务复盘效率?
  • 打印机共享错误11b解决方法介绍
  • nodejs fs 模块的简介与相关案例
  • 【APM】在Kubernetes中,使用Helm安装loki-distributed 3.1.1
  • 【C++并发入门】摄像头帧率计算和多线程相机读取(上):并发基础概念和代码实现
  • 技术速递|加入 .NET 智能组件生态系统
  • [深度学习]卷积神经网络CNN
  • docker常用命令、如何查看docker 镜像的sha256值
  • 算法分享——《滑动窗口》
  • 等保测评中的数据安全风险评估:企业实战
  • COSCon'24 第九届中国开源年会议题征集正式启动
  • RVC变声器入门
  • Linux信号学习三步走及知识脉络
  • BaseCTF2024 web
  • Qt播放音效或音乐使用QSoundEffect类
  • 小程序-基础知识1
  • 【muduo源码分析】「阻塞」「非阻塞」「同步」「异步」