Перемещение частиц в C и OpenGL
Вопрос
Я хочу иметь возможность перемещать частицу по прямой в трехмерной среде, но не могу придумать, как определить следующее местоположение на основе двух точек в трехмерном пространстве?
Я создал структуру, которая представляет частицу, имеющую местоположение и следующее местоположение?Подойдет ли это для определения следующего места переезда?Я знаю, как изначально установить следующее местоположение, используя следующий метод:
// 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
Решение
Другой ответ немного математический, на самом деле он довольно простой.
Вам нужна «Скорость», с которой вы двигаетесь.Он также имеет координаты x, y и z.
За один период времени для перемещения вы просто добавляете скорость x к вашему положению x, чтобы получить новое положение x, повторите то же самое для y и z.
Кроме того, у вас может быть «Ускорение» (также x,y,z). Например, ваше ускорение Z может быть константой силы тяжести.
Каждый период времени ваша скорость должна пересчитываться таким же образом: Назовите скорость x «vx», поэтому vx должно стать vx + ax, повторите для y и z (снова).
Прошло много времени с математикой, но я ее помню такой, довольно простой, если только вам не нужно следить за единицами, тогда становится немного интереснее (но все равно неплохо)
Другие советы
Я бы предположил, что у частицы должен быть только один член местоположения — текущее местоположение.Кроме того, скорость в идеале сама должна быть вектором из трех компонентов.Создайте функцию (назовите ее 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;
}
Я бы порекомендовал две вещи:
прочитайте пару статей по основам векторной математики для анимации.Например, этот это сайт, на котором объясняются 2D-векторы для Flash.
начните с простого, начните с точки 1d, то есть точки, движущейся только вдоль x.Затем попробуйте добавить второе измерение (двухмерную точку в двухмерном пространстве) и третье измерение.Это может помочь вам лучше понять основную механику.надеюсь это поможет
Подумайте о физике.Объект имеет позицию (x, y, z) и вектор движения (a, b, c).Ваш объект должен существовать на своем месте;с ним связан вектор движения, который описывает его импульс.При отсутствии каких-либо дополнительных сил на объект и предположении, что ваш вектор движения описывает движение за период времени t, положение вашего объекта в момент времени x будет (x + (aт), у + (бt), z + (c*t)).
Суммируя;не сохраняйте текущую позицию и следующую позицию.Сохраните текущую позицию и импульс объекта.Достаточно легко «тикать часы» и обновлять местоположение объекта, просто добавляя импульс к положению.
Сохраните скорость как структуру point3f, и тогда у вас будет что-то вроде этого:
void move(struct particle * p)
{
p->position.x += p->velocity.x;
p->position.y += p->velocity.y;
p->position.z += p->velocity.z;
}
По сути, скорость — это то, насколько вы хотите, чтобы позиция менялась каждую секунду/тик/что угодно.
Вы хотите реализовать векторную математику X_{i+1} = X_{i} + Vt
.Для X
песок 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;
}
}
На самом деле, есть два способа расчета новой позиции.Один, как и другой, объяснил, что нужно использовать явную скорость.Другая возможность — сохранить последнюю и текущую позицию и использовать Интеграция Верлет.Оба пути имеют свои преимущества и недостатки.Вы также можете взглянуть на это интересное страница.
Если вы пытаетесь двигаться по прямой между двумя точками, вы можете использовать формулу интерполяции:
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=0,5 дает вам среднюю точку между P1 и P2, t=0,333333 дает вам точку на 1/3 пути от P1 до P2 и т. д.Значения t вне диапазона [0, 1] экстраполируются на точки вдоль линии за пределами сегмента от P1 до P2.
Использование формулы интерполяции может быть лучше, чем вычисление скорости и повторное ее добавление, если скорость мала по сравнению с расстоянием между точками, поскольку вы ограничиваете ошибку округления.