【问题标题】:Moving particles in C and OpenGL在 C 和 OpenGL 中移动粒子
【发布时间】:2009-04-29 21:05:13
【问题描述】:

我希望能够在 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

【问题讨论】:

    标签: c opengl 3d particles


    【解决方案1】:

    另一个答案有点数学,实际上很简单。

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

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

    除此之外,您还可以有一个“加速度”(也可以是 x,y,z)例如,您的 z 加速度可以是重力,一个常数。

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

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

    【讨论】:

    • 棘手的部分是找出正确的移动方向。之后它应该是蛋糕。
    • 实际上,棘手的部分是实际上存在一个漏洞,因为这是在有限的“步骤”中完成的。要获得真实世界的运动,您必须使这些步骤非常接近。当你让它们无限接近时,你就有了一个真正的模型。有一个完整的数学分支基于使步骤完全连续的想法(微积分),但是像这样在有限的步骤中执行它是一个很好的近似值,并且可以大大简化公式。
    【解决方案2】:

    我建议一个粒子应该只有一个位置成员——当前位置。此外,理想情况下,速度本身应该是 3 个分量的向量。创建一个需要particle 和持续时间t 的函数(称为movedisplace 等等)。这将在 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;
    }
    

    【讨论】:

      【解决方案3】:

      我会推荐两件事:

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

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

      【讨论】:

        【解决方案4】:

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

        简而言之;不要存储当前位置和下一个位置。存储当前位置和对象的动量。只需将动量添加到位置,就可以很容易地“计时”并更新对象的位置。

        【讨论】:

          【解决方案5】:

          将velocity存储为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;
          }
          

          本质上,速度是您希望位置每秒/滴答声/随便改变多少。

          【讨论】:

            【解决方案6】:

            您想要实现向量数学X_{i+1} = X_{i} + Vt。对于Xs 和V 向量分别表示位置和速度,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;
              }
            }
            

            【讨论】:

            • 您愿意更详细地解释一下吗?我不确定你到底是什么意思。
            【解决方案7】:

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

            【讨论】:

              【解决方案8】:

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

              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 的线段外的线。

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多