1

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

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

这是更新功能:

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

4 回答 4

4

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

如果你想在物理上准确,让你的指针对象有一个有限的大小,这样粒子就会从它上面反弹。

如果不需要精确,可以在粒子非常靠近时使力减小。

于 2012-07-18T14:04:00.860 回答
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}*/;
}
于 2012-07-18T14:03:09.540 回答
0

当您的粒子非常接近鼠标指针时,粒子将具有非常高的速度。当这个速度乘以这个速度time时,粒子将跳得很远。

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

于 2012-07-18T14:14:47.993 回答
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 数学库

于 2012-07-18T15:15:16.480 回答