プロフィール

Na-7

Author:Na-7
SE(システムエンジニア)として約15年間システム系ソフト会社を勤めあげ、2008年3月退社。現在、ゲーム制作会社設立を目指して活動中。


アクセスカウンター


最新記事


最新コメント


最新トラックバック


月別アーカイブ


カテゴリ


DATE: CATEGORY:スポンサー広告
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
DATE: CATEGORY:三国志軍記開発

試行中のデモ画面
画像取得ツールで16方向×4枚=64枚の画像を出力し、プログラムに組み込んだ画面。16方向分の画像数の場合、向きの切り替えのカクカクが目立つ。



◎画像取得の準備

今回は、3Dアニメ画像自動取得ツールを作成し、槍騎兵部隊ユニットの全方向アニメ画像を取得します。槍騎兵はまだSoftimageに移行してないので、RokDeBone2で作成したモデルをACLで動かします。

しかし普通にアニメさせると、皆同じタイミングで動いてしまいます。

同じタイミングで走る槍騎兵

馬のランニングモーションが同じタイミングだと凄く不自然です。そこで、

controller.ElapsedTime = startTime;

こんな感じでモーションをずらそうとしたのですが、ずれません。

モデル、アニメーター、コントローラーのいずれかのインスタンスがコピーされてないのかと思い、半日ほど試行錯誤してしまいましたが、結局インスタンス等は何の問題もなく、ACLのElapsedTimeを勘違いしてただけでした。



◎ACLのElapsedTime

XNAの GameTime.ElapsedGameTime プロパティは「前回の更新から経過したゲーム時間」です。私はよく

timeCounter += (float)gameTime.ElapsedGameTime.TotalMilliseconds;

こんな感じでゲーム経過時間をミリ秒で取得しています。

一方、ACLの AnimationController.ElapsedTime は、アニメーション時間を表します。getだけでなくsetも可能なので、

controller.ElapsedTime = 300;

などとすると、その時間に該当するコマ(アニメフレーム)が表示されます。

私が勘違いしていたのは単位で、ミリセコンドよりもさらに小さい単位でした(マイクロセコンド?)。
だから300や3000程度ではほぼ同じ画像が表示されてしまうので、「個別に動かしているつもりなのに皆同じタイミングで動いてる」という状態になってました。

controller.ElapsedTime = (int)startTime * 100000;

こんな感じで値を十万単位で設定すると、別々のタイミングで動くようになりました。
…今までこれを知らずに余計な苦労してましたよ(笑)

個別のタイミングで走る槍騎兵



◎ライトのオン/オフ

任意のポーズがとれるようになったので、被写体を中心にカメラを16段階で回転するようにしました。

ライトオン正面   ライトオン背面

正面からは普通に表示されますが、背面から見ると真っ黒です。ライトが逆光だからです。

デフォルトライトをオフにするとこうなります。

ライトオフ正面   ライトオフ背面

いくら何でもこれはちょっとねぇ…。

というわけで、カメラに合わせてライトも回転させる必要がありそうです。



◎ライトの回転

BasicEffectのデフォルトライトはディレクショナルライトで、1方向に進むだけのシンプルなライトです。

しかし私はこれを思い通りに制御することができず、3Dテストプログラムの時は逆光のために幾つかのアイデアを諦めました。その後もずっと逆光を避けてモデルやカメラを配置してきましたが、いい加減まともに制御できるようにならないといけません。

ディレクショナルライトはVector3一つだけで方向を示しているので、恐らく原点からその座標に向かうベクトルを示しているのでしょう。だとすると、原点を中心に16段階で回転するように座標値を変換すれば良さそうです。最初はカメラと同様に回転させようとしましたが、もっと簡単な方法があることに気付きました。

先日、クォータニオンやMatrixの回転行列を調べた時に、MatrixやVector3のTransformと組み合わせて回転できることを知りました。その方法でやってみましょう。

Vector3 ret = Vector3.Transform(defaultDir[lightNo], Matrix.CreateRotationY(rot));

ライト回転正面   ライト回転背面

おお、できましたね!
Transformや回転行列をまともに使ったのは初めてですが、こんなに簡単になるとは…ちょっと感動かも(笑)

その後、カメラもこのやり方に改めました。ゴチャゴチャした計算式がスッキリして分かりやすくなりました。



◎ACLの画像をファイルに出力する

ようやく目的の画像が表示できるようになったので、前回確立した手法で画像ファイルを取得したら…空っぽでした。

空の画像

ACLは自動描画モードがデフォルトですが、これは多分Draw()実行後に描画しています。レンダーターゲット変更中に描画する必要があるため、手動描画コードを追加しました。

animator.Draw(gameTime);

手動描画深度バッファ無効

モデルが写るようになりましたが、モデルの足が鎧よりも手前に見えたりして、なんかヘンです。

これはレンダーターゲット先のデバイスが初期化された時に深度バッファがオフになっているからです。デバイスクリア後に深度バッファを有効にします。

graphics.GraphicsDevice.RenderState.DepthBufferEnable = true;

手動描画深度バッファ有効

ちゃんとした画像が取得できました!



◎連続画像の取得

画像枚数を指定すると均等間隔で画像ファイルを出力するようにしたいのですが、そのためにはモーション全体の再生時間を把握する必要があります。

騎兵モデルのループ時間を調べて割り出そうとしたのですが、これはAnimationController.Durationに格納されてました。これを利用して出力画像枚数を任意で指定できるようにしました。

ちなみに槍騎兵の場合「Duration = 3833333」でした。総フレーム数24枚、再生時間23/60秒ですので、ElapsedTimeの単位はやはりマイクロセコンドですね。


最後の仕上げとして、背景初期化時にアルファ値を指定して半透明とし、PNGファイルで保存するようにしました。

実行すると、64枚のPNGファイルが約20秒で出力されます。
手間暇かけていた画像取得作業が一気にラクになりました!(^^)



◎実装

取得した画像をメインプログラムに組み込みました。16方向だとやはりカクカクするので(冒頭参照)、32方向でも試してみました。



32方向×6枚=192枚(15MB)です。16方向と比べると、向きの切り替えが少しスムーズになりました。

こういうテストが気軽にできるのがいいですね。折角なので当面32方向でやります。



◎次回予告

今回は技術的に目新しいことは無いと思っていたのですが、新事実が意外とありましたね。これまで闇雲にやったり避けたりしてたことが改めて理解できました。

次回は、もうちょっと汎用的に使えるように細かい部分を手直ししつつ、槍兵と城の画像を取得します。できれば地形の立体化も試してみたいですね。

スポンサーサイト

テーマ : ゲーム製作 関連 - ジャンル : ゲーム

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック


この記事にトラックバックする(FC2ブログユーザー)



copyright © ゲーム制作の舞台裏 all rights reserved.Powered by FC2ブログ
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。