Движущиеся частицы в C и OpenGL - PullRequest
1 голос
/ 30 апреля 2009

Я хочу иметь возможность перемещать частицу по прямой линии в трехмерной среде, но я не могу придумать, как определить следующее местоположение на основе двух точек в трехмерном пространстве?

Я создал структуру, которая представляет частицу, которая имеет местоположение и следующее местоположение? Будет ли это подходящим для определения следующего места для перемещения? Я знаю, как изначально установить следующее местоположение, используя следующий метод:

// 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 ]

3 голосов
/ 30 апреля 2009

Другой ответ немного математичен, на самом деле он довольно прост.

Вам нужна «Скорость», по которой вы двигаетесь. Он также имеет координаты x, y и z.

За один промежуток времени, чтобы переместиться, просто добавьте скорость x к вашей позиции x, чтобы получить новую позицию x, повторите для y и z.

Кроме того, у вас может быть «Ускорение» (также x, y, z). Например, вашим ускорением z может быть гравитация, постоянная.

Каждый период времени ваша скорость должна пересчитываться одним и тем же способом. Скорость вызова x "vx", так что vx должно стать vx + ax, повторите для y и z (снова).

Прошло много времени с математики, но вот как я это помню, довольно просто, если только вам не нужно отслеживать единицы, тогда становится немного интереснее (но все же неплохо)

3 голосов
/ 30 апреля 2009

Я бы предложил, чтобы частица имела только один элемент местоположения - текущее местоположение. Кроме того, скорость в идеале должна быть вектором из трех компонентов. Создайте функцию (назовите ее move, displace как угодно), которая принимает 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;
}
2 голосов
/ 30 апреля 2009

Я бы порекомендовал две вещи:

  1. прочитайте одну или две статьи по базовой векторной математике для анимации. Например, this - это сайт, который объясняет 2d векторы для flash.

  2. Начните с простого, начните с 1d точки, то есть с точки, движущейся только вдоль x. Затем попробуйте добавить второе измерение (2d точка в 2d пространстве) и третье измерение. Это может помочь вам лучше понять основную механику. надеюсь, это поможет

1 голос
/ 30 апреля 2009

Сохраните скорость как 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;
}

По сути, скорость - это то, насколько вы хотите, чтобы позиция менялась каждую секунду / тик / что угодно.

1 голос
/ 30 апреля 2009

Подумайте о физике. Объект имеет позицию (x, y, z) и вектор движения (a, b, c). Ваш объект должен существовать на своей позиции; с ним связан вектор движения, который описывает его импульс. При отсутствии каких-либо дополнительных сил на объекте и предположении, что ваш вектор движения описывает движение за период времени t, положение вашего объекта в момент времени x будет (x + (a t), y + ( b t), z + (c * t)).

Короче говоря; не сохраняйте текущую позицию и следующую позицию. Сохраните текущую позицию и импульс объекта. Достаточно просто «пометить часы» и обновить местоположение объекта, просто добавив импульс к позиции.

0 голосов
/ 01 мая 2009

Если вы пытаетесь двигаться по прямой линии между двумя точками, вы можете использовать формулу интерполяции:

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 дает вам точку 1/3 пути от P1 до P2 и т. Д. Значения t вне диапазона [0, 1] экстраполируются на точки вдоль линия вне сегмента от P1 до P2.

Использование формулы интерполяции может быть лучше, чем вычисление скорости и ее повторное добавление, если скорость мала по сравнению с расстоянием между точками, поскольку вы ограничиваете ошибку округления.

0 голосов
/ 30 апреля 2009

Афаик, в основном, есть два способа расчета новой позиции. У одного, как у другого, есть объяснение использования явной скорости. Другая возможность - сохранить последнюю и текущую позицию и использовать интеграцию Verlet . Оба способа имеют свои преимущества и недостатки. Вы также можете взглянуть на эту интересную страницу .

0 голосов
/ 30 апреля 2009

Вы хотите реализовать векторную математику X_{i+1} = X_{i} + Vt. Для векторов X s и 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;
  }
}
...