我的粒子系统的物理更新功能似乎不正确。我的目标是将所有粒子吸引到鼠标上。
粒子像预期的那样向鼠标指针移动,直到它们非常靠近。当它们靠近时,它们会加速,以至于它们飞离指针并且永远不会返回。
这是更新功能:
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为常量时,程序看起来没问题,但我知道它是假的。
那么,我做错了什么?
答案 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。