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);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值