はじめに
良い一日。 私はここで初めて記事を書いていますが、私の目標は非常に単純です。骨格アニメーションのビジョンを共有したいので、批判と助けをもらいたいと強く望んでいます。 このシステムの作成全体は試行錯誤によって行われました。これを行う方法、実際の仕組み、および使用方法に関する書籍は見つかりませんでした。 しかし今、私は行き止まりに達したので、ここからこの方法を見つけたいと思います。
何を使用しましたか?
- MSVS 2013 Professionalは私の主要なIDEです
- Qt Creator-これで、アニメーション編集プログラムを書きました
- Qt 5.1-アニメーションエディターのGUIとして
- SDL 2-最終プログラムでのコマンドとグラフィックの入力/出力(アニメーションが行われる場所)
- OpenGL 2.1-グラフィックスの表示用
- GLEW -OpenGL拡張機能の接続用
- ブースト -タイマーを使用する
- Protobuf Google-アニメーションファイルに保存するには
- C ++ -私がすべてをしたPL
どこから始めますか?
私は最初に構造を定義する必要があると決めました。そして、それがどのように機能するかを理解することは私にとって非常に簡単になるでしょう。
まず、#definesを表示します。
#define M_PI 3.1415926535 #define M_PI_2 M_PI/2 #define M_PI_3 M_PI/3 #define M_PI_4 M_PI/4 #define RAD1 M_PI/180.0f #define DEG1 180.0f/M_PI #define RAD2DEG(rad) rad*DEG1 #define DEG2RAD(deg) deg*RAD1 #define MAX_CHILDREN_COUNT 10 #define MAX_KEYFRAME_COUNT 20
そして、私は最終的にそのような構造に来ました:
ジョイントはジョイントです
typedef struct _Joint {
dX、dY、dAngle-これらはデフォルト値です。 0〜6.28の角度をラジアンで保存することにしました。 そして、これには多くの問題がありました。 しかし、それについては後で。
aX、aY、aAngle-これらはアニメーションオプションです。 これらは、フレームがすでに補間されている量を示します。 つまり、過去のアニメーションが記録されます。 たとえば、アニメーションの持続時間は900ミリ秒(
TIME )、450ミリ秒(
NOW )ですが、ミリ秒ごとにアニメーションを更新することはできません。したがって、前に400ミリ秒、450 = 50(
KEY1 )、2番目の100(
KEY2 )では、
Xの最終値は次のとおりです。
_Joint.x += (KEY2 - KEY1) / TIME * NOW - _Joint.aX;
_Joint.aX = (KEY2 - KEY1) / TIME * NOW;
22,3 += (100-50) / 900 * 450 - 22,3
22.3-これはXサイコロです。時間(
NOW )が0の場合、
Xもゼロであったことを考慮してください
KeyDataとKeyframeはアニメーションの構造です
typedef struct _KeyData { float x, y, angle; } S_KeyData; typedef struct _Keyframe { S_KeyData data; uint16_t time; uint16_t index; _Keyframe* parent; uint8_t childCount; _Keyframe* child[MAX_CHILDREN_COUNT]; } S_Keyframe;
補間のためにボーンの検索を整理する方法を長い間考えていました。 私の意見では、ツリー内での検索はアニメーションのかなり曖昧なプロセスです。 私は頭の中で2つの決定をしました。 最初の解決策は、インデックスを使用してブランチを示すことです。これにより、検索が少し高速化されます。 それは通常のアドレス指定です。 しかし、私は2番目のソリューションを選択しました。 私の意見では、ツリー全体の更新は、ツリーのどの部分よりもはるかに簡単で高速です。 非常に簡単です。メインボーンにはそれぞれ10個の子があり、さらに5個のボーンがあるとします。その結果、51個のボーンしかありません(ところで、ルートジョイントはまったく表示されません。オブジェクト全体の位置)。
5反復の10サイクル、つまり50反復のみが必要です。 そして最後に、ツリー全体を更新するときに51の補間を取得します。 それ以外の場合、ボーン検索を使用する場合、イテレーションでは最後に追加されたボーンを検索するために50回、最後から2番目のボーンを検索するために49回が必要になります。 インデックス
0の _Keyframeは、このアニメーション化の時間を格納します。彼のすべての子には0の時間パラメーターがあります。
アニメーション-キーのリストを保存します
typedef struct _Animation { uint8_t keyNumber; uint8_t keyCount; S_Keyframe* key[MAX_KEYFRAME_COUNT]; } S_Animation;
keyNumberは再生するアニメーションのインデックスで、デフォルトはゼロです。 すべてのアニメーションキーは、時系列で
キー配列に格納されます。 実装のすべての方法、構造の削除の作成、およびそれらへの新しいオブジェクトの追加は、ここで多くのコードを積み重ねないように非表示にします。 ただし、アニメーション自体の機能は表示します。
bool doAnimation(S_Joint *root, S_Animation *anim, uint16_t time) { if (!root) return false; if (!anim) return false; bool timeOut = true; for (int i = 0; i < anim->keyCount; i++) { if (time < anim->key[i]->time)
関数がtrueを返すと、タイマーはゼロにリセットされます(Boost :: timer)
そして最後の機能:
void doInterpolate(S_Joint* root, S_Keyframe* key1, S_Keyframe* key2, uint16_t time, uint16_t nowTime) { if (root->index != key2->index) return; float x = (key2->data.x - key1->data.x) / time * nowTime;
ここにそのような骨格アニメーションがあり、それはかなりうまく機能します。 Qtでプログラムを作成する段階で多くの問題が発生しました。最初の問題は、マウスによる骨の動き、そして実際には骨の動きです。 6.28の円内の骨の回転長、つまり2 * Piまたは360度。 しかし、結果の動きは一方向にのみ発生します。 取得した場合、計算4.47で、反対方向に移動したい場合、原則としてこれを行うことができます。
4,47-6.28=-1,81
逆方向に動くようです。 しかし、それはあまり便利ではありません。 また、回転ターゲットへの最適なパスを検索しようとしました。 位置が1.57(A)であると想像すると、目標は5.57(B)になります。
negAngle = BA; posAngle = (B-6.28)-A; if(fabs(posAngle) > fabs(negAngle)) { }
ただし、最適なパスが常に必要なわけではありません。 したがって、これも完全には適合しません。 これらの問題を解決するための2つのオプションについて考えます。 最初のオプションは、厳密な補間を計算することです。 つまり、アニメーションのキーはボーンになります。 2番目の方法は、キーのみの動きを求めることです。 しかし、実際には、私は行き詰まっており、次に何をすべきかわかりません。 Qtプログラムは比較的成功しますが、アニメーション自体は悪くないようですが、GUIエディターを書いている間、その非効率性と煩わしさを理解しました。 骨格アニメーションを一般的な物理学に制限する方法(私はBox2dに参加したいという欲求に燃えています)が、これを行う方法がわかりません。 移植性のあるものすべてをやり直すことにしましたが、アドバイス、何をどのように間違ったかについての批判を聞きたいと思います。 繰り返しますが、これは私のシステムであり、例に従っていませんが、これは骨格アニメーションの私の見解です。厳密に判断しないでください。 ご清聴ありがとうございました!