プロフィール

Na-7

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


アクセスカウンター


最新記事


最新コメント


最新トラックバック


月別アーカイブ


カテゴリ


DATE: CATEGORY:スポンサー広告
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
DATE: CATEGORY:三国志軍記開発
8方向ビルボード対応
試行中の画面
ポリゴンの角度によって絵を切り替えることにより、ユニットの向きを再現した。しかし8方向切り替えは粗くて不自然らしい。



◎ビルボードとユニットの向き

ビルボードを実装すると、モデルが常にカメラの方を向きます。見た目には良いのですが、これでは部隊ユニットが実際にどちらを向いているかわからなくなってしまいます。

この問題に対処するため、ポリゴンの角度とユニットの向きによって絵を切り替えるという手法を試してみます。



◎クォータニオン?

板ポリゴンの向き(回転角度)はビルボードメソッドで設定しているので、その回転角度をMatrix.Decomposeメソッドで取得します。

問題は、このメソッドで返される回転角度はクォータニオンだという点です。
…クォータニオンって何?(汗)

こちらの記事によると、回転行列のようなものらしいですね。

記事内の行列図で、3×3の部分がR(回転)、4行目がT(移動)を表しているのはわかりますが、S(拡大縮小)が図示されてないのは何故なんでしょうか?
…って、疑問を全て調べていたらキリが無いので、今回は軽く触れる程度にします。


円柱状ビルボードメソッドで取得したクォータニオンの値を確認しました。

Vector3 scale2;
Quaternion rot2;
Vector3 pos2;
world.Decompose(out scale2, out rot2, out pos2);
Console.WriteLine("rot2 = " + rot2.ToString());


rot2 = {X:0 Y:0.9363021 Z:0 W:0.3511957}
rot2 = {X:0 Y:0.8923917 Z:0 W:-0.4512616}
rot2 = {X:0 Y:0.9186879 Z:0 W:-0.3949843}
rot2 = {X:0 Y:0.9905549 Z:0 W:-0.1371164}
rot2 = {X:0 Y:0.9555428 Z:0 W:0.2948525}


ふぅ~ん…Y軸を基準に回転してるのでXとZが0というのは分かりますが、Yの値は常に1.0というわけじゃないんですね。



◎オイラー角?

クォータニオンが回転を表すツールであることは理解しました。

これをY軸を回転軸とした角度に変換したい(XNA的に言うと、Matrix.CreateRotationY()の逆をしたい)わけですが、クォータニオンにはそれらしいメソッドが見当たりません。ネットで検索しようと思いましたが、そもそも目的の角度は何と言うのでしょうか?

先の記事でオイラー角という単語が出ていたので、「クォータニオンからオイラー角に変換する」とヤマをはって検索したら、どの記事も予想以上にややこしい雰囲気。

どうもこれは違うかなと思い、オイラー角について確認すると、こちらの記事で「本によって書いてあることが微妙に異なります。」とあるように、定義が曖昧なようです。

中にはロール・ピッチ・ヨー角もオイラー角の一種として書かれた本もあるようですが、通常はオイラー角は2軸、ロール・ピッチ・ヨー角は3軸として扱われるようですね。



◎頂点変換

クォータニオンや回転行列からオイラー角やロール・ピッチ・ヨー角にまともに変換しようとすると、ややこしい数式を理解しなければならないようです。

今回は1軸のみの回転なので、最終的には簡素な数式にできそうな気がしますが、それを私の頭でまともに導き出そうとしたら、恐ろしく時間がかかりそうです。

結局、角度を求めるのは諦めて、クォータニオンを利用した頂点変換を行い、頂点の位置から向きを判定するようにしました。



◎座標系がおかしい?

判定した向きが正しいか確認すると、見た目とずれている様子。なんか変だな~?

内部数値をいろいろ出力して確認すると、そもそもマップ系とユニット系の座標比率が2対1で異なってました。それでマップの端の方だと角度がずれる感じがしたのか…。

しかしこの座標比率の違いがどこで生じているのか、ソースを全部見直してもわかりませんでした。そもそもXNAのワールド座標比率は常に固定じゃないの??



◎原因はビルボード

半日がかりでようやく原因が判明しました。

前回記事で、ビルボード作成メソッドを
Matrix world = Matrix.CreateScale(10.0f)
  * Matrix.CreateConstrainedBillboard(pos, mainMap.MapViewPos, Vector3.Up, null, null)
  * Matrix.CreateTranslation(pos);

このように記述しましたが、最後の座標指定が余計でした。ビルボードメソッドは、回転だけでなく位置も作成することに気付いてなかったわけです。

「ヘルプではそんなこと一切触れてないじゃん!」と思って見直したら、ありました。

指定されたオブジェクト位置の周囲を回転する球面のビルボードを作成します。

このヘンな日本語は「座標も変換しますよ」という意味だったんですね。直訳系の日本語にハメられた気分です(苦笑)



◎さらにバグ修正

ビルボード関連でもう1つバグがありました。カメラを移動するとユニットの位置が微妙にズレてました。

高さ修正前モデル左上   高さ修正前モデル右上

画面を左にスクロールすると、槍兵が画面左上から右上に移動していきます。スクロール中は気付きにくいのですが、静止画を見ると、槍兵の立ち位置が(道の右側から左側に)微妙にズレてますね?これは、板ポリゴンの中心を原点として回転したからです。

足元を中心に回転するよう修正しました。

// 板ポリゴンのスケール
float scale = 10.0f;

// 板ポリゴンの原点を、中央から足下に移動する
Vector3 billPos = new Vector3(pos.X, pos.Y + scale / 2, pos.Z);

// 円柱状のビルボードを作成する
Matrix world = Matrix.CreateScale(scale)
* Matrix.CreateConstrainedBillboard(billPos, mainMap.MapViewPos, Vector3.Up, null, null);


高さ修正後モデル左上   高さ修正後モデル右上



◎ユニットの向きの再現

ビルボードが直ったところで、本題に戻ります。

判定した向きが正しいか確認すると…OKです。ビルボードの向きに応じて、8方向を示す値が取得できました。

この値と、ユニット本来の向きを比較して、表示すべき絵のパターンを判定しました。(冒頭図参照)


えーと…動画にすべきところですが、あえて静止画のみとさせて頂きます…。

プログラムは狙い通りに動きました。しかし絵の切り替わりは不自然でした。以前の簡易デモ動画は向きの切り替わりが不自然でしたが、あれと同じです。

ちなみに、まだ新しいアニメパターンを用意してないので、8方向中3方向しか再現されてません。



◎次回予告

8方向じゃダメですね。今度は16方向でやってみます。

…ということは、アニメパターンをあと13方向分用意しなくちゃいけないのか。左右反転させるとしても、あと7パターン。うへ~メンドクサイ。でも仕方ないですね。

10月になったので、次回は「9月の総括と10月の目標」です。

スポンサーサイト

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

コメント

うっ…

ここ数日、デュアルクォータニオン補間で悪夢を彷徨っていました。まさかこちらでクォータニオンの説明をすることになるとは…(汗)。

行列図でRとTしか書いていないのは、単に『ひにけにXNA』のクォータニオンスキンでスケーリングをやっていないからです。もう少し後ろの記事でシェーダの解説がありますが、シェーダそのものにスケーリング定数がないです。

クォータニオンについては差し当たり
・w = cosθ(θは回転角度)
・(x,y,z)は回転の軸を表すベクトルで、長さはsinθ。とだけ言っておきます。なので少しでも傾いている場合、全ての要素の絶対値は1未満となります。


…ただ、クォータニオンが必要になるのはフライトシミュレータのようなバリバリの3Dゲームか滑らかなスキンモデリングを実装したい場合です。今回のようにビルボードの向きによって絵を変えるだけなら、RPYの3軸どころかYaw1軸回転で十分なんじゃないかな?

恐らく内部的には各ユニット毎にワールド座標上での地表に沿った“絶対的な”向きを持っていると思うんですが、それとカメラの視線ベクトル(の、地上平面成分)との角度差を取れば十分なんじゃないかと。例えばカメラの平面角度がθ、ユニットの向きがφとして、16分割で31/32π<(θ-φ)33/32πなら真正面の絵、という具合です。

わざわざ表示用に作成したビルボード行列から逆算する必要はないと思いますよ。

ご教授ありがとうございます!

>スケーリングをやっていないからです。
そういうことでしたか。ちょっと疑問に思っていましたが、お陰さまでスッキリしました。

>・w = cosθ(θは回転角度)
>・(x,y,z)は回転の軸を表すベクトルで、長さはsinθ
これを知っているとクォータニオンの理解が早まりそうですね。いずれ本格的に扱う際の参考とさせて頂きます。

>31/32π<(θ-φ)33/32πなら真正面の絵
…なるほど、そのとおりですね!

>わざわざ表示用に作成したビルボード行列から逆算する必要はないと思いますよ。
ありがとうございます。ご教授頂いた式を参考に、プログラムを作り直してみます。

コメントの投稿


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

トラックバック


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



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