Games101 作业8 质点弹簧系统

发布时间 2023-07-18 21:27:22作者: Dba_sys

1 前言

质点弹簧系统的模拟仿真,其实非常简单,核心就是牛顿第二定律 \(F = ma\), 以及一些数值积分,所要做的无非就是对每一个质点计算附加的力,力是矢量,速度是矢量,加速度也是矢量。

计算出力后,算出加速度,利用一个很小的时间,更新一下位置就好根据位置进行渲染。

下一个循环将力清零,开始重新计算合力。

显示欧拉和半隐式欧拉其实就是计算速度和位置的顺序变了一下,显示欧拉效果奇差无比,半隐式欧拉效果却非常好。至于Verlet Intergration是根据半隐式欧拉推导来的,比较难理解的是它需要做一些约束。

2 基础数据结构

核心的数据就是,位置,质量,速度,力。

struct Mass {
  Mass(Vector2D position, float mass, bool pinned)
      : start_position(position), position(position), last_position(position),
        mass(mass), pinned(pinned) {}

  float mass;
  bool pinned;

  Vector2D start_position;
  Vector2D position;

  // explicit Verlet integration

  Vector2D last_position;

  // explicit Euler integration

  Vector2D velocity;
  Vector2D forces;
};

3 欧拉

核心的差距就是先更新速度还是先更新位置。

// explicit Euler
m->position = m->position + m->velocity * delta_t;
m->velocity = m->velocity + acc * delta_t;
// semi-implicit Euler
m->velocity = m->velocity + acc * delta_t;
m->position = m->position + m->velocity * delta_t;

4 Verlet Integration

这个就是从semi-implicit Euler里推导出来的。

Vector2D temp_position = m->position;
//	t + 1				t
m->position = m->position + (m->position - m->last_position) +  acc * delta_t * delta_t;

//	t-1					t
m->last_position = temp_position;

4.1 Constraints

Constraints的基础模型就是棍子小球模型,需要注意的是先处理小球再根据小球位置处理棍子长度。

image

			Vector2D vec_now = s->m2->position - s->m1->position;
            // if  length_now bigger than rest we need to plus at m1 minus at m2
            float length = (s->m2->position - s->m1->position).norm();

            float diff = length - s->rest_length;

            // Althougth this will not matian the length (if someone of them two are pinned, the other will just +- half-diff)
            // if(!s->m1->pinned) s->m1->position += vec_now.unit() * diff * 0.5;
            // if(!s->m2->pinned) s->m2->position -= vec_now.unit() * diff * 0.5;

            if(!s->m1->pinned && !s->m2->pinned){
                s->m1->position += vec_now.unit() * diff * 0.5;
                s->m2->position -= vec_now.unit() * diff * 0.5;
            }else if(s->m1->pinned && !s->m2->pinned){
                // for just one pinned, the other will be shrink or extended the full diff
                s->m2->position -= vec_now.unit() * diff;
            }else if(!s->m1->pinned && s->m2->pinned){
                s->m1->position += vec_now.unit() * diff;
            }