【问题标题】:Particle system physics acting weird粒子系统物理行为怪异
【发布时间】:2012-07-18 13:58:30
【问题描述】:

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

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

这里是更新函数:

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 为常数时,程序看起来没问题,但我知道它是假的。

那么,我做错了什么?

【问题讨论】:

  • 你真的看到粒子加速了,还是他们只是消失在屏幕外?您可以尝试增加最低 squareDistance 直到您看到它们变慢。
  • @Staven 我看到他们以极快的速度走了一段时间。然后他们就消失了。
  • 如果我没记错的话,当一个粒子距离指针 1 个单位时,你将获得大约 67 个单位/秒平方的加速度。一个单位在屏幕上有多长?将POINTERMASS 缩小可能是个好主意。
  • @Staven 一个单位是一个像素。

标签: c++ physics simulation particles


【解决方案1】:

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

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

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

【讨论】:

  • 我确实希望在物理上非常准确。是否可以通过让粒子在它们足够接近时跳过指针来修复错误?
  • 如果你需要在物理上超精确,那么你需要考虑到“重心”的概念对于大多数计算来说是一个很好的近似值,但在现实中没有意义
  • @Hassedev 嗯,你可以,但那在物理上不是很准确,不是吗? ;)
  • @Hassedev 当它们足够接近时,您也可以简单地使粒子死亡(“在大气中燃烧”或其他东西)。
  • @LieRyan 不一定要 100% 真实,但差不多。
【解决方案2】:

非常简单:当粒子与鼠标指针接触时,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}*/;
}

【讨论】:

  • 我现在修好了,但行为还是一样。
  • 仅仅避免除以 0 并没有多大帮助,因为粒子仍然可以几乎任意接近指针。
  • @Desmond Hume 我在问题中编辑了我的代码。看看吧。
  • @Hassedev 也编辑了我的答案。
  • @Hassedev ..now 修改了零容忍度。
【解决方案3】:

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

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

【讨论】:

  • 时间目前是 1。更改它似乎没有什么区别。
  • 您是否尝试过缩短调用 updateParticle 之间的时间?
【解决方案4】:

模拟运动方程涉及在有限间隔内对函数进行积分,因此只能近似该函数。这会导致系统不稳定。一个简单快速的解决方案是使用固定步骤 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-09
    • 1970-01-01
    • 1970-01-01
    • 2011-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多