質問
3D環境内で粒子を直線で移動できるようにしたいのですが、3D空間内の2点に基づいて次の位置を計算する方法が考えられませんか?
位置と次の位置を持つ粒子を表す構造体を作成しましたか?これは次の場所を移動するのにも適していますか?次の方法を使用して最初に次の場所を設定する方法を知っています:
// 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
解決
もう1つの答えは少し数学的なもので、実際には非常に単純です。
「速度」が必要です。あなたは動いています。また、x、y、z座標もあります。
ある期間内に移動するには、x位置にx速度を追加して新しいx位置を取得し、yとzについて繰り返します。
さらに、「加速」を使用できます。 (x、y、zも)たとえば、z加速度は重力、定数である可能性があります。
速度を毎回同じ方法で再計算する必要があるたびに、呼び出し速度x" vx"で、vxはvx + axになり、yとzについて繰り返します(再び)。
数学からしばらく経ちましたが、それは私が覚えている方法です。ユニットを追跡する必要がない限り、かなり簡単です。それからもう少し面白くなります(それでも悪くはありません)
他のヒント
パーティクルには、1つのロケーションメンバー、つまり現在のロケーションのみを含めることをお勧めします。また、速度は理想的には3つのコンポーネント自体のベクトルでなければなりません。 particle
と継続時間 t
をとる関数( move
、 displace
と呼びます)を作成します。これにより、 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つのことをお勧めします:
-
アニメーションの基本的なベクトル計算に関する記事を読んでください。たとえば、 this は、フラッシュ用の2Dベクトルを説明するサイトです。
-
単純に開始し、1dポイント、つまりxに沿ってのみ移動するポイントから開始します。次に、2番目の次元(2次元空間の2次元の点)と3次元を追加してみてください。これは、基礎となるメカニクスの理解を深めるのに役立ちます。 これがお役に立てば幸いです
物理学を考えてください。オブジェクトには、位置(x、y、z)と移動ベクトル(a、b、c)があります。オブジェクトはその位置に存在する必要があります。運動量を表す動きベクトルが関連付けられています。オブジェクトに追加の力がなく、運動ベクトルが期間tにわたる運動を記述すると仮定すると、時間xでのオブジェクトの位置は(x +(a t)、y +( b 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;
}
速度は、本質的には、位置を1秒/ティック/何でも変更したい量です。
ベクトル演算 X_ {i + 1} = X_ {i} + Vt
を実装します。 X
sおよび V
のベクトルは、それぞれ位置と速度を表し、 t
は時間を表します。私は物理学者であるため、トラックに沿った距離を時間でパラメーター化してきましたが、それは本当に自然なことです。トラック距離を指定する場合は、速度ベクトルを正規化します(つまり、 V.x * V.x + V.y * V.y + V.z * V.z = 1
のように V
をスケーリングします)。
上記の 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;
位置と速度の両方をパーティクルに関連付ける場合(非常に合理的なこと)、2つのベクトルをサポートする構造を構築します
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;
}
}
2点間の直線に沿って移動しようとしている場合、補間式を使用できます:
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へのセグメントの外側の線
補間式を使用すると、速度が計算され、速度がポイント間の距離に比べて小さい場合、丸め誤差を制限するため、繰り返し加算するよりも優れている場合があります。