在C和OpenGL中移动粒子

时间:2009-04-29 21:05:13

标签: c opengl 3d particles

我希望能够在3D环境中以直线移动粒子,但我想不出如何基于3D空间中的两个点来计算下一个位置?

我创建了一个结构,它表示一个具有位置和下一个位置的粒子?这是否适合制定下一个移动位置?我知道如何使用以下方法初始设置下一个位置:

// Set particle's direction to a random direction
void setDirection(struct particle *p)
{
    float xnm = (p->location.x * -1) - p->velocity;
    float xnp = p->location.x + p->velocity;
    float ynm = (p->location.y * -1) - p->velocity;
    float ynp = p->location.y + p->velocity;
    float znm = (p->location.z * -1) - p->velocity;
    float znp = p->location.z + p->velocity;

    struct point3f nextLocation = { randFloat(xnm, xnp), randFloat(ynm, ynp), randFloat(znm, znp) };
    p->nextLocation = nextLocation;
}

我使用的结构是:

// Represents a 3D point
struct point3f
{
    float x;
    float y;
    float z;
};

// Represents a particle
struct particle
{
    enum TYPES type;
    float radius;
    float velocity;
    struct point3f location;
    struct point3f nextLocation;
    struct point3f colour;
};

我是否完全以错误的方式解决这个问题?

这是我的所有代码http://pastebin.com/m469f73c2

8 个答案:

答案 0 :(得分:3)

我建议粒子应该只有一个位置成员 - 当前位置。而且,理想情况下,速度应该是3个分量本身的矢量。创建一个函数(称之为movedisplace无论如何),该函数需要particle和持续时间t。这将计算t个时间单位过去后的最终位置:

struct point3f move(struct *particle, int time) {
    particle->location->x = particle->velocity->x * t;
    /* and so on for the other 2 dimensions */
    return particle->location;
}

答案 1 :(得分:3)

另一个答案是有点麻烦,实际上非常直接。

你需要一个你正在移动的“速度”。它还有x,y和z坐标。

在一个时间段内,移动你只需将x速度添加到x位置以获得新的x位置,重复y和z。

最重要的是,你可以有一个“加速度”(也就是x,y,z)例如,你的z加速度可能是重力,一个常数。

每个时间段你的速度都应该以相同的方式重新计算,调用速度x“vx”,所以vx应该变成vx + ax,重复y和z(再次)。

从数学开始已经有一段时间了,但这就是我记忆中的方式,非常直接,除非你需要跟踪单位,然后它会变得更有趣(但仍然不错)

答案 2 :(得分:2)

我会推荐两件事:

  1. 阅读有关动画基本矢量数学的一两篇文章。例如,this是一个解释闪存的2d向量的站点。

  2. 从简单开始,以1d点开始,即仅沿x移动的点。然后尝试添加第二个维度(在2d空间中的2d点)和第三维度。这可能有助于您更好地理解底层机制。 希望这有帮助

答案 3 :(得分:1)

想想物理学。对象具有位置(x,y,z)和运动矢量(a,b,c)。你的对象应该存在于它的位置;它有一个与之相关的运动矢量来描述它的动量。在物体上没有任何额外的力,并假设你的运动矢量描述了一段时间t内的运动,你的物体在时间x的位置将是(x +(a t),y +( b t),z +(c * t))。

总之;不存储当前位置和下一个位置。存储当前位置和对象的动量。通过简单地将动量添加到该位置,“点击时钟”并更新对象的位置就足够了。

答案 4 :(得分:1)

将速度存储为struct point3f,然后你有这样的东西:

void move(struct particle * p)
{
  p->position.x += p->velocity.x;
  p->position.y += p->velocity.y;
  p->position.z += p->velocity.z;
}

基本上,速度是你想要每秒改变位置/嘀嗒/等等多少。

答案 5 :(得分:0)

您想要实现向量数学X_{i+1} = X_{i} + Vt。对于分别代表位置和速度的XV向量,以及代表时间的t。我已经按时间参数化了沿着轨道的距离,因为我是一名物理学家,但这确实是很自然的事情。如果要提供轨道距离(即缩放V,使V.x*V.x + V.y*V.y + V.z*V.z = 1),请对速度矢量进行标准化。

使用上面的struct可以很自然地访问元素,但不太方便进行添加:数组更适合。像这样:

double X[3];
double V[3];

// initialize

for (int i=0; i<3 ++1){
  X[i] = X[i] + V[i]*t;
}

通过联盟,您可以获得两者的优势:

struct vector_s{
  double x;
  double y;
  double z;
}
typedef
union vector_u {
  struct vector_s s; // s for struct
  double a[3];       // a for array
} vector;

如果你想将粒子的位置和速度联系起来(这是一件非常合理的事情),你可以构建一个支持两个向量的结构

typedef
struct particle_s {
  vector position;
  vector velocity;
  //...
} particle_t;

并运行一个看起来大致如下的更新例程:

void update(particle *p, double dt){
  for (int i=0; i<3 ++i){
    p->position.a[i] += p->velocity.a[i]*dt;
  }
}

答案 6 :(得分:0)

Afaik,主要有两种方法可以计算新的位置。一个是像另一个有解释使用显式速度。另一种可能性是存储最后一个和当前位置并使用Verlet integration。两种方式各有利弊。你也可以看看这个有趣的page

答案 7 :(得分:0)

如果您尝试沿两点之间的直线移动,可以使用插值公式:

P(t) = P1*(1-t) + P2*t

P(t)是点的计算位置,t是0到1的标量,P1和P2是端点,上面的加法是向量加法(所以你将这个公式分别应用于你的点的x,y和z分量)。当t = 0时,你得到P1;当t = 1时,得到P2,对于中间值,你得到P1和P2之间的一条点。所以t = .5给出了P1和P2之间的中点,t = .333333给出了从P1到P2等的1/3点。等于[0,1]范围外的t的值外推到了从P1到P2的段外线。

使用插值公式可能比计算速度更好,并且如果速度与点之间的距离相比较小,则重复添加速度,因为您限制了舍入误差。