粒子系统物理行为怪异

时间:2012-07-18 13:58:31

标签: c++ physics simulation particles

我的粒子系统的物理更新功能似乎不正确。我的目标是将所有粒子吸引到鼠标上。

粒子像预期的那样向鼠标指针移动,直到它们非常靠近。当它们靠近时,它们会加速,以至于它们飞离指针并且永远不会返回。

这是更新功能:

void updateParticle(particle& p,double time){
    const double G=0.000000000066726;
    const double POINTERMASS=1000000000000;

    double squareDistance=pow(p.coords.x-pointerDevice.x,2)+pow(p.coords.y-pointerDevice.y,2)+pow(p.coords.z-pointerDevice.z,2);
    if(squareDistance<0.001)
        squareDistance=0.001;//to fix the possible division by zero

    coords_3d_f accelerationVector={p.coords.x-pointerDevice.x,p.coords.y-pointerDevice.y,p.coords.z-pointerDevice.z};

    accelerationVector=vector_scalar_multiplication(vector_unit(accelerationVector),((G*POINTERMASS)/squareDistance));
    accelerationVector=vector_scalar_multiplication(accelerationVector,time);

    p.velocity=vector_addition(p.velocity,accelerationVector);

    p.coords.x-=p.velocity.x*time;
    p.coords.y-=p.velocity.y*time;
    p.coords.z-=p.velocity.z*time;
}

当squareDistance为常量时,程序看起来没问题,但我知道它是假的。

那么,我做错了什么?

4 个答案:

答案 0 :(得分:4)

力与距离的平方成反比,因此当距离接近0时,力(和加速度)接近无穷大。换句话说,如果粒子非常接近,它们也会非常快。

如果你想要在物理上准确,那么让你的指针对象具有有限的大小,以便粒子从它反弹。

如果你不需要准确,你可以在粒子非常接近时使力减少

答案 1 :(得分:1)

这非常简单:当粒子与鼠标指针squareDistance取得联系时,0变为((G*POINTERMASS)/squareDistance),并且if (squareDistance >= 1.0) // 1.0 is the zero tolerance for your context of pixel distances { // proceed normally accelerationVector=vector_scalar_multiplication(vector_unit(accelerationVector),((G*POINTERMASS)/squareDistance)); accelerationVector=vector_scalar_multiplication(accelerationVector,time); } else { // no acceleration accelerationVector=/*{0, 0}*/; } 为粒子产生未定义的行为,因为除以零是非法的。

这可能对您更有效:

{{1}}

答案 2 :(得分:0)

当粒子非常靠近鼠标指针时,粒子将具有非常高速度。当此速度乘以time时,这就是粒子将跳得很远的时候。

您可以尝试通过设置最大速度来解决此问题。

答案 3 :(得分:0)

模拟运动方程涉及以有限间隔积分函数,因此只能近似函数。这导致系统不稳定。一个简单快速的解决方案是使用固定步骤 verlet集成

void integrate(particle& p, double t2, const particle& mouse)
{
  // universal gravitational constant
  const double G = 0.000000000066726;

  // artificial drag
  // set it to 1.0 to not have any drag
  // set it to 0.0 to not have any momentum
  const double drag = 0.99;

  // get direction and distance between the particle and the mouse
  dvec3 dir = p.pos - mouse.pos;
  double dist2 = dot(dir, dir);
  double dist = sqrt(dist2);
  dir /= dist;

  // calculate relative acceleration vector
  dvec3 a = -dir * G * (p.mass + mouse.mass) / dist2;

  // verlet integration
  dvec3 tmp = p.pos;
  p.pos += (p.pos - p.prev_pos) * drag + a * t2;
  p.prev_pos = tmp;
}

void update(particle& p, double elapsed, const particle& mouse, double& accumulator)
{
  // fixed timestep (arbitrary)
  const double timestep = 1.0 / 120.0;
  const double timestep2 = timestep * timestep;

  // "accumulate" time
  accumulator += elapsed;

  // "consume" time
  while(accumulator > timestep)
  {
    // perform integration
    integrate(p, timestep2, mouse);
    accumulator -= timestep;
  }
}

注意:为清晰起见,请使用GLM math library