03/06/27どうもOggVorbis開発陣営の動きが鈍くなっている感じがします。盛り上がりに欠けるのは仕方の無い所でしょうか。いえライセンスフリーというのは開発者としては美味しいので、頑張ってほしいなぁと西の方角(なんとなく)に向かって念を送る毎日です。今回は微力ながらOggVorbis普及に努めましょうというネタ。以前書いて放置しっぱなしのVoxドライバをHSPに対応させてみました。要はC言語仕様のラッパー関数を被せたのと、引数をintオンリーにしただけなんですけどね。以前のようにC++からの呼び出しも可能です。以前のバージョンを使われている方にもご利益があるかもしれません。ネットで調べるとDelphiから呼び出そうとして挫折している例がありましたが、そういった場合にも今回のC言語用インタフェースを使えば何とかなるかもしれません。HSPに話を絞ります。ゲーム製作に向いたスクリプト言語として有名なHSPですが、私は使ったことがないので正直どんな言語か良く知りません。C関数なら外部DLLから呼び出せるということが分かりました。HSPの仕様として浮動小数点が使えないというものがあるらしく、かなりショックを受けましたが、とりあえず引数をintにしたラッパー関数を用意すれば解決する話です。以上を踏まえた新バージョンVoxです。HSPから使用するサンプルスクリプトはこんな感じです。hDLLHSPコミュニティーの皆様のご利用をお待ちしています(≒バグ出してね)。ソースをver0.60に更新、めんどくさくなったので(?)vorbisfileを使うことにしました。05/03/09世間には3Dを表現するファイルフォーマットが山のようにあります。それぞれ一長一短があり、これぞ最高というものはなかなかありません。必要に応じて独自のフォーマットを作る事もままあります。今回は一から作るのは面倒なので、Xファイルにユーザーが定義したデータを追加してみる事にします。Xファイルではデータ構造をtemplateで定義します。Radius;}といった感じで定義することができます。<>でくくられている怪しげな数字はWindowsで言う所のGUIDになります。自分で定義したテンプレートを作成する時もこの数字を用意しなければなりません。.NET\Common7\Toolsにguidgen.exeというツールがあるので、これを使えば良いですし、フリーウェアでも色々ツールが出ています。BoundingSpheres[Number];}このようにtemplate中で別のtemplateによって定義されたデータ構造を用いる事もできます。templateのフォーマットについてはヘルプに詳細が出ているのでそちらを参照してください。続いて、実際にデータをXファイルに追加します。追加できる場所は3箇所で、TopLevel、Frame、Meshのいずれかになります。階層構造で言えばTopLevelの下がFrameで、その下がMeshになります。{...のように、Frameの中に書き加えるだけです。最後に、追加したデータをプログラムから読み出します。DirectX9ではD3DXLoadMeshHierarchyFromXという便利な関数でXファイルを読み下せます。この関数の第5引数でユーザー定義データを解析する関数を設定できます。引数はID3DXLoadUserDataのアドレスを要求します。このインターフェースにはTopLevel、Frame、Meshのそれぞれに追加されたデータが読み込まれた時に呼び出されるLoadTopLevelData、LoadFrameChildData、LoadMeshChildDataの3つの関数が定義されています。要はID3DXLoadUserDataを継承したクラスを作り、以上の3つの関数を実装して、適宜データを読み出すだけです。データはIDirectXFileDataを使って渡されるので、メンバ関数のGetTypeによりGUIDを取得し、GetDataによりデータへのポインタを取得します。ポインタはvoid*になっているのでGUIDでデータの種類を判定してキャストしながら読み出す必要があります。以上の方法でテキスト形式のXファイルにユーザー定義データを追加できるのですが、バイナリ形式だとtemplateをファイル内に定義できないので、プログラム中でIDirectXFile::RegisterTemplatesを使ってテンプレートを定義する必要があります(未確認)。余談ですが、DirectX9になってもバイナリ形式は挙動不審です。Viewerでテキスト形式のXファイルを読み込んで、バイナリ形式で書き出すと、できたファイルが読み込めない事がありました。読み込み速度を上げたい場合以外はテキスト形式を使うのが無難でしょう。いうわけで、今回のソースです。キャラクタにバウンディング球のデータを追加しています。外部依存ファイルに対するパスは自分で直してください。毎度のことですが、エラーチェックは最低限であり、このサンプルの使用によるいかなる不幸も当方では責任を負いかねます。--/--/--野村XXはNetscapeを愛しています。いうかNetscapeのブックマークを、です。使い勝手の良い更新チェッカが見当たりません。作ってしまえというのが今回のネタ。・更新されていたら自動でブラウザを立ち上げるとりあえずこんな所でしょう。あとはどれだけ手抜きして完成させるかだけです。HREF="http://...で始まるリンク先を切り出さなければなりません。strstrとか使って地道にやってもいいんですが、ここはさくっと正規表現に頼ってしまいましょう。使ったことのない方は、こことかこことか参照。MS万歳な人はATLとかでお茶を濁すのもありでしょう。役に立つのでHDDにboostを転がしておくと幸せになれます。続いて必要はないのですが、せっかくなのでサイト名も切り出します。Netscape7は文字コードがUTF-8になっているのでs-jisに変換しなければなりません。思い込んでしまって大混乱してしまいました。分かってしまうと大したことではなく、MultiByteToWideChar->WideCharToMultiByteの順でAPIを呼び出してあげるだけで解決。いえばboostの正規表現ってUTF-8に対応しているかどうか謎です。動いているので良しとしておきましょう。http接続は、ここを参考にWinInetAPIにお任せします。InternetOpenUrlを使って、ついでにInternetSetOptionでタイムアウト値をセットしておくのもありでしょう(タイムアウト設定なしだと固まる可能性がある)。あとはざくざくhtmlを読み込んでファイルに吐き出します。過去の履歴と比較して更新されていたり、新規リンク先だったりした場合はブラウザを立ち上げます。これはShellExecuteでできます。複数のブラウザを立ち上げることができない(ひとつのブラウザの表示内容が切り替わるだけ)ので3番目の引数に実行ファイル名を直接入れて呼び出します。以上で完成です、んー簡単ですね。簡単なのでソースをそのまま張っておきます。なんとなく今日はC++の気分なので、C++色の強いコードになってます。作ってみたもののカウンタや、バナーのちょっとした変更とかでも敏感に反応して更新判定されてしまうので、いまいち使いづらいです。ブラウザを立ち上げるのではなく、一度ユーザーに聞いてあげる方が親切かもしれません。実用性は?ですが更新チェッカとしては最短コードの部類ではないかと。使い方は実行ファイルがある場所にdataというディレクトリを掘ってから、コマンドラインで引数にブックマークファイル名を指定して起動するだけです。いうかリンク先の入ったhtmlなら何でもOKです。IEのお気に入りをエクスポートしたファイルでは必要ありませんが、Netscapeの場合は引数に-UTF8を付けてください。03/04/12さて今回のネタはDirectX9のXファイル関係での変更点の目玉と思われるID3DXAnimationControllerです。こいつの登場により、DirectX8以前では自分で実装しなければならなかったXファイルのアニメーション関係のコードが一切要らなくなってしまいました。良い時代になったものです。困ったことに、ヘルプの記述がそっけない事甚だしい。良いフレームワークを提供してくれているんだから積極的に情報をくれてもいいもんなんですけどね。こちらに素晴らしい資料があるのでありがたく拝見しましょう。いつも通りSkinnedMeshサンプルをソフトウェアスキニングの部分だけにして読みやすく整形する所からはじめましょう。これです外部依存ファイルに対するパスは自分で直してください。スペースキーを押すとモーションブレンドしながら動作が切り替わります。毎度のことですが、エラーチェックは最低限であり、このサンプルの使用によるいかなる不幸も当方では責任を負いかねます。こ、これは笑ってしまうほど簡単。全体的にCOMの匂いが強いので馴染みづらいですが、実にシンプルなコードです。D3DXLoadMeshHierarchyFromXの引数で指定されるID3DXAllocateHierarchyがXファイルを勝手に読み下してくれるので、こちらはFrameとMeshをどのように作成、破棄するかを指示するだけで済みます。読み込みが終わると親FrameとAnimationControllerへのポインタを返してくれます。親子付けのアニメーションならこれで準備完了です。ワンスキンの場合はMeshがどのFrame(ボーン)に属しているのか設定を行います。これだけで読み込み終了。後はAnimationControllerを使ってアニメーションの設定をして描画するだけです。描画部分は自分でやらなければなりません。いうかここを隠蔽されるとさすがに不便なので当然といえば当然です。問題のID3DXAnimationControllerを眺めてみましょう。気が付いたことを適当に整理します。:アニメーションの時間(姿勢)の設定と複数のアニメーションセットをブレンド、いわゆるモーションブレンディングができるだけです。実際それ以上の機能は要らないので必要にして十分です。Xファイルにアニメーションが含まれていない場合はD3DXLoadMeshHierarchyFromXはID3DXAllocateHierarchyへのポインタにNULLを返すので注意。CloneAnimationControllerはアニメーションコントローラのコピーを作ってくれますが、ここで指定する各種設定値の最大数については元のコントローラの最大値を下回ることはできません。逆に上回る分には構いません。前記のこちらのサイトを見る限り、安全性に疑問が残ります。:走る、歩く、跳ぶといった動作データひとつずつがアニメーションセット。アニメーションセット部分をカット&ペーストするという涙ぐましい方法でXファイルに複数のアニメーションセットを持たせることができます。D3DXLoadMeshHierarchyFromXを使った場合、Xファイル中のアニメーションセットを全て読み込んでくれます。複数のトラックにアニメーションセットを読み込むにはGetAnimationSet、SetTrackAnimationSetを使って手動で設定する必要があります。GetAnimationSetで指定するアニメーションセットのインデックスはXファイル中に書かれている順番と逆順になる模様。手動で読み込んだトラックのD3DXTRACK_DESCには値が設定されていないのでSetTrackDescで設定しないといけません。いくつかのXファイルで試した所、我が家の環境ではGetMaxNumEventsの返値は常に30を返してくるので、これがデフォルト値らしい。:ボックスを20個親子付けしたXファイルを作ってGetMaxNumMatricesの返値を見るとroot+frame数の21を返してきました。D3DXLoadMeshHierarchyFromXを使った場合Xファイル中に登場する名前付き行列がID3DXAnimationControllerに登録されます。現在のXファイル仕様にはFrameTransformMatrix以外の行列が存在しないので結局FrameTransformMatrixの数がセットされたということのようです。要はこのFrameTransformMatrixのような名前付き行列を変更するためのものです。その際のNameにはFrameの名前を指定することになります。:複数のトラックをどのように混ぜるかコントロールするもの。トラックにしろミキサにしろ音楽用語のイメージでOKかと。グローバルアニメーションタイム:マスタクロックとでも言うべきものです。デフォルト状態ではここで設定した時間通りにアニメーションが進みます。トラック毎に時間を設定することもできます。ヘルプにはトラック速度の設定関数にSetTrackAnimationTimeがあると書いてありますが、SetTrackAnimTimeの誤植のようです。:まず複数のトラックにアニメーショントラックをセットしておきます。あとはKeyTrackEnableを使ってブレンドしたいトラックを全て有効にするだけです。フェードアウトするモーションとフェードインするモーションの各トラックのウェイトをSetTrackWeightで徐々に変化させれば滑らかにモーション間をつなぐことが出来ます。:謎、トラック間に優先順位があるらしいのですが、その優先順位を設定するパラメータが見当たりません。固定されている可能性が高いですが不明です。いじった感じではこんな所です。KeyPriorityBlend辺りは結構便利そうな雰囲気が漂うもののPriorityについて良く分からないので、もう少し情報を集めないと正しい使い方が分かりませんね。あと問題点としては、D3DXLoadMeshHierarchyFromXがデフォルトで提供してくれるアニメーションコントローラがトラックを2つしか持っていない点です。現状ではコントローラで使えるトラック数を増やすにはCloneAnimationControllerを使うしかありません。バグがあるかも知れないCloneAnimationControllerをどきどきしながら使う羽目になります。実際のゲーム製作においては、ブレンド数が瞬間的に2つを超えることがあるので、ちょっと困りモノです。サンプルソースにリソースのリリース忘れがあったので修正あと、アニメーションの時間の単位が謎ですが、Xファイル中に以下のテンプレートを定義すると設定することができるようです。02/11/17ちょっとお役立ち情報ということで、LightWaveでDirectX用のワンスキンモデルを作るための覚書です。悩まされたので公開しておきます。いっても重要なのは7番目の項目だけです。ポリゴンモデルを作る黙々とポリゴンをこねくり回します。頂点数を減らした方が後のウェイトマップ設定が楽になります。処理も軽くなるのでここは腕の見せ所です。4角ポリゴン主体に組んでいくのですが、関節部分は3角ポリゴンにしておいた方が曲がったときの破綻が少なくなります。テクスチャを貼るマテリアルが増えると処理が重くので、なるべくUVマップを利用してサーフェースを増やし過ぎないようにテクスチャを貼っていきます。ちなみにどれくらい重くなるかというと、同じポリゴンモデルで1マテリアル+UVが700FPS、30マテリアル+UVが70FPSと実に10倍も差が付いてしまいました。モデルの頂点を結合しなおせばOKです。スケルゴンを仕込むモデラー上でスケルゴンを配置していきます。続いて親子付け&名前付けをスケルゴンツリーで行います。LW7.5使っている場合はD-StormのHPに落ちているSkelgonEditorを使う方が少し楽です。当然ですがスケルゴンの総数が少ない方が処理が軽くなるので、無駄なスケルゴンはなるべく作らない方が吉です。ここでCalsium2というプラグインを利用させてもらいます。LW標準では全てのスケルゴンは強制的につながってしまうのに対し、これを利用する事で親子付けされていながらも位置の離れたスケルゴン(浮動ボーン)を作れるようになるので、スケルゴン削減に一役買ってくれます。ウェイトマップを行う全てのボーンにウェイトマップを付けます。Calsium2を利用する場合は、ダミーのスケルゴンについては後で削除されるのでウェイトマップは必要ありません。全ての頂点はいずれかのウェイトマップの影響を受けていなければなりません。頂点を選択してからエアブラシを使って確実にウェイト設定する方が良いかもしれません。MirrorWeightsとかanon_WSheetといったプラグインが重宝します。レイヤーをまとめるレイアウトに持っていくときに一つのレイヤーにまとまっていないとスケルゴンがまともに変換されないので、まとめてからセーブします。非常に不便なので改良してほしいですね。スケルゴンをボーンに変換するここからはレイアウトで作業です。Boneを使うのがLW標準ですが、ここではCalsium2を利用してボーンに変換します。理由は浮動ボーンが使える事と、ボーン変換後のバンク角がまともであるという事の2点です。一般オプションの『その場でペアレント』を有効にしてからCalsium2のオプションを『Skelgonを処理』、『_Fで終わるBone名は浮動ボーンのダミー』にして変換します。キャラクターアニメーション』という本で紹介されているのでそちらを参照してください。ボーンのオプションを変更するこれが最重要です。全てのボーンのオプションで『ウェイトのみ使用』を選択、『ウェイト常態化』は選択をはずします。スプレッドシートを利用して一気に設定するのもありでしょう。LWのボーンには色々設定項目がありますが、最終的に.X形式で出力したときに反映されるのはウェイトマップの値だけと思って間違いありません。この状態でまともに見えるように、スケルゴンの位置と頂点のウェイト値を調節します。モデラーとレイアウトを行ったり来たりで大変ですが頑張りましょう。X形式で出力するD-StormのHPに落ちている最新版のDirectXExporterを使ってX形式のファイルを作ります。SkinWeights/Vertex』を選択。SkinWeights/Face』はケチって小さな値にすると思い通りの出力が得られません。DirectX8形式でバイナリ出力したXファイルはまともに読み込めないので避けましょう。ちなみにLWの両面ポリゴンは片面になって出力されてしまうので要注意です。