Movendo-se partículas em C e OpenGL
Pergunta
Eu quero ser capaz de se mover uma partícula em uma linha reta dentro de um ambiente 3D, mas eu não posso pensar como trabalhar a próxima localização com base em dois pontos dentro de um espaço 3D?
Eu criei uma estrutura que representa uma partícula que tem uma localização e uma localização próxima? Será que isso é adequado para trabalhar fora o próximo local para mover também? Eu sei como configurar inicialmente o próximo local usando o seguinte método:
// 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;
}
As estruturas que tenho usado são:
// 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;
};
Am I lidando com isso de forma completamente errada?
aqui está todo o meu código http://pastebin.com/m469f73c2
Solução
A outra resposta é um pouco mathish, é realmente bastante simples.
Você precisa de um "Velocity", que você está se movendo. Ele também tem x, y e z coordenadas.
Em um período de tempo, para movê-lo basta adicionar a velocidade x de sua posição x para obter a sua nova posição x, repita para y e z.
Além disso, você pode ter uma "aceleração" (também x, y, z), por exemplo, a sua aceleração z poderia ser a gravidade, uma constante.
Cada período de tempo a sua velocidade deve ser recalcualted da mesma forma, Call velocidade x "vx", de modo vx deve tornar-se vx + machado, repita para Y e Z (de novo).
Tem sido um tempo desde matemática, mas é assim que eu me lembro, muito para a frente, a menos que você precisa para manter o controle de unidades, então fica um pouco mais interessante (mas ainda não é mau)
Outras dicas
Eu sugiro que uma partícula deve ter apenas um membro do local - a localização atual. Além disso, a velocidade deve, idealmente, ser um vector de 3 componentes em si. Crie uma função (chamemos-lhe move
, displace
qualquer outro) que leva um particle
e uma duração t
tempo. Isto irá calcular a posição final depois unidades t
de tempo decorrido:
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;
}
Eu recomendaria duas coisas:
-
ler um artigo ou dois em matemática básica vetor para a animação. Por exemplo, este é um site que explica vetores 2D para o flash.
-
começar simples, comece com um ponto 1d, ou seja, um único ponto se movendo ao longo x. Tente adicionar uma segunda dimensão (um ponto 2d num espaço 2d) e terceira dimensão. Esta ajuda lhe possam obter uma melhor compreensão dos mecanismos subjacentes. espero que isso ajude
Pense da física. Um objecto tem uma posição (x, y, z) e um vector de movimento (a, b, c). Seu objeto deve existir em sua posição; ele tem um vector de movimento associado a ele que descreve o seu dinamismo. Na falta de quaisquer forças adicionais no objeto, e assumindo que o seu vector movimento descreve o movimento ao longo de um período de tempo t, a posição do seu objeto em tempo de x será (x + (a t), y + ( b t), Z + (c * t)).
Em suma; não guarde a posição atual e a próxima posição. Armazenar a posição atual e dinâmica do objeto. É fácil o suficiente para "tick do relógio" e atualizar a localização do objeto simplesmente adicionando o impulso para a posição.
velocidade de loja como um point3f struct, e então você tem algo como isto:
void move(struct particle * p)
{
p->position.x += p->velocity.x;
p->position.y += p->velocity.y;
p->position.z += p->velocity.z;
}
Essencialmente, a velocidade é o quanto você quer a posição de mudar a cada segundo / carrapato / whatever.
Você deseja implementar o X_{i+1} = X_{i} + Vt
vector de matemática. Para os X
s e vectores que representam V
posição e de velocidade, respectivamente, e representam t
tempo. Eu parametrizado a distância ao longo da pista por vez, porque eu sou um físico, mas é realmente a coisa natural a fazer. Normalizar o vetor velocidade se você quer dar a pista de distância (ou seja, escala V
tal que V.x*V.x + V.y*V.y + V.z*V.z = 1
).
Usando o struct
acima torna natural para acessar os elementos, mas não tão conveniente para fazer a adição: matrizes são melhores para isso. Como esta:
double X[3];
double V[3];
// initialize
for (int i=0; i<3 ++1){
X[i] = X[i] + V[i]*t;
}
Com a união, você pode obter as vantagens de ambos:
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;
Se você deseja associar tanto a posição ea velocidade de com a partícula (uma coisa muito razoável para fazer) você construir uma estrutura que suporte dois vetores
typedef
struct particle_s {
vector position;
vector velocity;
//...
} particle_t;
e executar uma rotina de atualização que parece mais ou menos como:
void update(particle *p, double dt){
for (int i=0; i<3 ++i){
p->position.a[i] += p->velocity.a[i]*dt;
}
}
AFAIK, existem essencialmente duas maneiras de como você pode calcular a nova posição. Um deles é como o outro têm explaint usar uma velocidade explícito. A outra possibilidade é armazenar a última e a posição atual e usar o Verlet integração . Ambas as formas têm suas vantagens e desvantagens. Você também pode dar uma olhada neste interresting página .
Se você está tentando se mover ao longo de uma linha reta entre dois pontos, você pode usar a fórmula de interpolação:
P(t) = P1*(1-t) + P2*t
P (t) é a posição calculado do ponto, t é um escalar que varia de 0 a 1, P1 e P2 são os pontos de extremidade, e a adição na acima é a adição de vectores (modo de aplicar esta fórmula separadamente para o x, y e componentes z dos seus pontos). Quando t = 0, você começa P1; quando t = 1, você começa P2, e para valores intermediários, você tem uma maneira da parte ponto ao longo da linha entre P1 e P2. Assim, t = 0,5 lhe dá o ponto médio entre P1 e P2, t = 0,333333 lhe dá o ponto de 1/3 do percurso de P1 a P2, etc. valores de T fora do intervalo [0, 1] extrapolar para os pontos ao longo a linha de fora do segmento de P1 a P2.
Usando a fórmula de interpolação pode ser melhor do que computar uma velocidade e repetidamente adicionando-se a velocidade é pequena em comparação com a distância entre os pontos, porque você limitar o erro de arredondamento.