WPF/日記6
サイズに調整・画面設計
昨日コード上から動的に追加されたはずの3Dモデル(アバタ)がなぜか画面に表示されなかった件について追跡調査を行ったところ、アバタのサイズが巨大すぎたため両足がカメラをまたいでいたことが判明しました。船に乗って橋の下を通過するときは上を見上げなければ橋は見えないってことですね。そこでカキワリ(背景画像)よりもずっと巨大なアバタを適切なサイズに縮め、ついでにカメラとカキワリの中間ぐらいに移動してやることにしました。
Transform3DGroupタグ
<Transform3DGroup x:Key="Transform_Character_man_Character_0" >
<TranslateTransform3D OffsetX="0" OffsetY="0" OffsetZ="0"/>
<ScaleTransform3D ScaleX="1" ScaleY="1" ScaleZ="1"/>
<RotateTransform3D CenterX="0" CenterY="0" CenterZ="0">
<RotateTransform3D.Rotation>
<AxisAngleRotation3D Angle="0" Axis="0 1 0"/>
</RotateTransform3D.Rotation>
</RotateTransform3D>
<TranslateTransform3D OffsetX="0" OffsetY="0" OffsetZ="0"/>
</Transform3DGroup>
上記のコードはman.xaml(アバタの定義ファイル)のうちのアバタ全体のTransformを定義している部分です。Transformは直訳すると「変形」という通り、3Dモデルの拡大・縮小・回転・移動に関する情報です。Transform3DGroupタグの中で変形情報を定義しておくと、モデル情報からそれを呼び出すことで変形が適用されるということのようです。
TranslateTransform3Dタグ
まず、カメラの位置(Z座標)が10、カキワリの位置(Z座標)が-5となっています。そしてカメラはZ軸のマイナス方向を向いています。モデリングの段階でアバタは原点の上に作っていたので、追加されたアバタの位置(Z座標)は0となります。ということは、アバタの位置は特に問題はなかったようです。でもせっかくなので、X座標上で少しアバタを移動させてみました。
Identityで書き出されたTransform3DGroupタグの中にはTranslateTransform3D要素が二つ含まれていました。どうやら変形は先頭から順に行われていくようですので、回転や縮小の後に移動させたい場合は二つ目のTranslateTransform3D要素に手を加えてあげるとよいようです。
<TranslateTransform3D OffsetX="2" OffsetY="0" OffsetZ="0"/>
OffsetX属性を「0」から「2」に変更しました。これで、初期位置からX座標軸プラス方向に「2」移動したことになります。
ScaleTransform3Dタグ
カキワリよりアバタのサイズを小さくしないといけないので、アバタを100分の1ぐらいに設定します。
<ScaleTransform3D ScaleX="0.01" ScaleY="0.01" ScaleZ="0.01"/>
ScaleTransform3Dの各属性を「1」から「0.01」に変更すればアバタは随分と小さくなってくれました。以下、結果の画像です。
この後カキワリのサイズやカメラの位置などの細かいところを調整しました。
キー入力を受け付ける
続いてキーボードをつかってアバタを動かしてみます。マウスを使って動かすのとどっちがいいか悩んだのですが、一応3Dチャットを目指しているのでキーボードで操作を完結させることにします。
KeyDown属性、KeyUp属性
3D空間を表示するViewport3Dにフォーカスがあるときにアバタが操作できればいいので、Viewport3DタグにKeyDown属性とKeyUp属性を追加します。
<Viewport3D x:Name="ChatWorld" KeyDown="moveAvatar" KeyUp="stopAvatar" Focusable="True">
キーが押されたときはmoveAvatar関数を、キーが離されたときはstopAvatar関数を呼び出すということにしました。記入した関数名の上で右クリックして、「イベント ハンドラへ移動」を選択するだけで関数の定義部を勝手に作ってくれるのでありがたいですね。普段テキストエディタでプログラミングしているので、たまに統合開発環境を使うと感動してしまいます。インテリセンスはしばしば自分がいなくても勝手にプログラムを書いてくれるのではないかと錯覚させるほど、上手く動いてくれることがあります。
ついでにFocusable属性を追加しておきました。キーフォーカスを設定するオブジェクトにはつけないといけないみたいです。
それでは実際にmoveAvatar関数とstopAvatar関数を実装していこうと思います。と、その前にコード上でアニメーション関連を扱うので・・・
using System.Windows.Media.Animation;
を加えておきました。Stroyboard(アニメーション情報)を扱う場合はこれが必要だそうです。で、コーディングを進めていこうとしたらここで一つ躓きました。Identityが生成したアニメーション付きの3Dモデル情報で「どの部位」を「どんな風にアニメーション」させるかを関連付けるために各パーツ(頭、胴体、右足、左足)にx:Name属性で名前をつけていたのですね。ですが、ResourceDictionaryにこのモデル情報を入れたときにx:Name属性は全部削ってしまったのです。(辞書の中身に名前はつけられないのでした。)そのため、アニメーションさせようにも「どの部位」を動かせばいいのかがうまく関連付けられていないもようです。安易な考えでx:Name属性の変わりにx:Key属性を加えてみましたが、エラーになってしまいます。(識別キーはResourceDictionary直下のタグにしかつけられないのだと思われます。)パッと解決策が思い浮かばなかったので、今日はもう寝ることにしました。