UpDate:--/--/--時間がある今のうちにゲーム用のライブラリをバージョンアップしようとぴこぴこキーボードを叩いてます。ライブラリを育てるのは楽しいですね〜今使ってるのはとびちよん用に急造した奴なんで、結構妖しいコードが混ざってます。昨日まで3D周りをいじってたんですがビュー行列の作成で大ボケをかましてました。Y軸周り以外の回転がまともに動作してね〜、ぐすん。感じでやってるんですが、今回の目玉はライブラリ全体をアーカイブファイルからの読み込みに対応させること。サウンド周りの挙動がおかしくなってしまいました。DirectMusic使ってるんですが、データをファイルから読み込むLoadObjectFromFileを使ったときには大丈夫なのに、メモリから読み込むGetObjectを使うとうまく動きません(アーカイブされたファイルはメモリ上に展開される)。複数のサウンドを再生しようとすると、前に再生したサウンドが後で再生しようとしているサウンドに影響をあたえるんですね。Waveを再生した後にMIDIを再生しようとすると、MIDIの代わりに前に再生したWaveが再生されるといった次第。半日原因を調べてやっとこさ理由が分かりました(多分)。pData;とまぁこんな感じです。それぞれ単体ではちゃんと鳴るのに、続けて鳴らそうとすると前のサウンドがでしゃばってくる。pData;こんな感じでゼロクリアしても変化ありません。元のデータがこの世に存在してないのに、そのデータが鳴るというのは恐怖です。pData_A;としてやるとちゃんと動くんですね〜大体読めてきました。先ほどデータを消したのに鳴ったということは、どこかにキャッシュされてるからでしょう。pData;再生としてもちゃんとサウンドが鳴るということは、どっかにメモリが確保されているはずです。そのメモリをキャッシュするのはDirectMusic君しかいません。確かに奴はキャッシュ機構を備えてます。そのキャッシュの検索方法は『データの先頭アドレス』に違いありません。馬鹿だ・・・つまり前のデータをdeleteすると次のデータは前のデータの先頭位置からnewするんで(もちろん次のデータを読み込む前に別のメモリ確保が行われていなければの話)せっかく読み込んだ次のデータは実際には読み込まれずにキャッシュから全然違う奴が読み込まれているんでしょう。みたいな配列を読み込み用のバッファに使った日には、永遠に新しいサウンドを鳴らすことができないと思われます。毎回新しく読み込みにいってパフォーマンスが落ちるのも面白くありません。すると別のサウンドを鳴らすときは確実に先頭アドレスの異なるデータを食わせなければいけません。ぐぁ〜、めんどくせー。わけでMSさん反省して修正してください。Exportに乗り換えの最中です。lws2xはすんげーソフトですがバージョンアップが止まってしまっているので、そろそろかな〜といった所。いじって見たところテキスト形式でExportすると動くのにバイナリ形式だと動かないんで困ってしまったわけです。調べてみるとなにやらX8バイナリ形式で出力するとだめで、X7バイナリ形式ならOKな模様。何が違うんですかいなと比べてみるとテンプレートが増えているようです。strlen(szTemplates));こんな感じでX8で増えた3つのテンプレートを登録してやるとOKです。UpDate:01/09/13えー、ブラーです。〜、ぶら〜、ぶらぶら、んじゃそういうことで、以上。いや、話が終ってしまっちゃよろしくありません。ここの所DirectX8上で2Dエフェクトをどうやってやろうかと考えてます。確かに便利なX8君なのではありますが、いかんせん3D寄り過ぎる設計思想がちょっといただけません。サーフェースを直接操作するということにあまり向いていないようです。Lock関係のコマンドやCopyRects関係のコマンドが妙に遅くて困りものです。レンダリングパイプラインのフラッシュとVRAM->SYSTEMMEMORY間での転送速度が足を引っ張っているようですが、リアルタイムにピクセル単位の操作をするのがかなり困難です。そこを何とかしようと実験中な訳ですが、いまいちうまくいかないのが実情です。わけで、その過程でブラーを作ったので紹介しとこうというのが今回の主旨。世間ではモーションブラーと残像とごっちゃになってるきらいがあります。そこらへんの説明はこちらに譲ります。適当を旨とする、当サイトでは細かいことは気にしません。なんとなく移動物体の後ろに移動軌跡が残っていればOKということにしときます。本物のモーションブラーというのは計算コストが非常にかかります。LightWaveで試してみると少しずつ時間を進めて複数回レンダリングしている様が良く分かるのですが、そりゃ時間がかかって仕方ないわけです。3DCGの世界ではAfterEffectなんかを使って後付けで2D的にブラー効果をつけることもやってます。しないと延々とレンダリングしつづけて終らないシーンがあるからなんですね。そこで、いかに手抜きしてブラー効果を出せばいいのかということなんですが、種を明かせば簡単。『前フレームで描画した画像を今回描画したフレームに半透明で重ねる』だけです。フレームを半透明で重ねていくと時間がたつにつれそのフレームはどんどん色が薄くなっていきます。これがブラーに見えるわけです。D3DCLEAR_ZBUFFERフラグを指定してサーフェースをきれいにしてから描画するところをD3DCLEAR_ZBUFFERだけで実行します。次に背景色のポリゴンを半透明で画面いっぱいに描画します。あとはいつも通りポリゴンオブジェクトなり何なり描いてあげるだけです。半透明ポリゴンで前フレームを上書きすることで薄くしてから、今回のフレームを上書きするわけです。Zバッファーだけはクリアしておかないと今回のフレームがちゃんと描画できないのでClearだけは気をつけなければなりません。非常に低コストな処理なんで、余裕でリアルタイムに動かすことができます。以下すべて32Bitカラーモード用プログラムです。それっぽく見えるんじゃないでしょうか。この方法は重大な欠点があります。一目瞭然なので、サンプルソース(NG版)をご覧下さい。先ほどの操作は言い換えると、半透明の前フレームを最も奥(Z=1.0)の位置に描画して、その手前に今回のフレームのオブジェクトを描画していることになります。後ろ側にあるオブジェクトが手前側のオブジェクトのブラーとして見えるはずの部分を上書きして消してしまうんですね。背景などで画面いっぱいにオブジェクトが描画されるとまったくブラーの効果が得られないことになります。これは、ちょっと困ります。宇宙空間に浮かぶ戦闘機とかならともかく、普通背景に多数のオブジェクトが存在します。手前(Z=0.0)の位置に描画することができればよいのです。これは前フレームの画像をテクスチャとして手前にポリゴン描画すれば可能です。サーフェースをテクスチャにコピーするにはLockしてmemcpyするとかCopyRectsをつかうとかしなければならず、これが前述の通りえらい時間を食います。実はIDirect3DTexture8は内部的にIDirect3DSurface8を持っているらしくCreateTextureを使ってテクスチャを作るときにD3DUSAGE_RENDERTARGETフラグを指定しておくと、レンダリングサーフェースとして使うことができます。複数のテクスチャをレンダリングターゲットとしてSetRenderTargetで切り替えて使うことができます。そこで、2枚のテクスチャを用意して交互にレンダリングサーフェースとして使用します。することで一つ前のフレームがどちらか一方のテクスチャ上に常に残ることになります。テクスチャAに現在のフレームを描画->その上にテクスチャBの内容を半透明で上書き->レンダリングターゲットをプライマリサーフェースに変更->テクスチャAの内容をプライマリサーフェースに描画->テクスチャBに現在のフレームを描画->その上にテクスチャAの内容を半透明で上書き->レンダリングターゲットをプライマリサーフェースに変更->テクスチャBの内容をプライマリサーフェースに描画->...(繰り返し)こんな感じですね。トリッキーですがたいしたことはしていません。プライマリサーフェースと同じサイズのテクスチャが2枚必要になるので結構VRAMを食いますが...。2.5Mバイト位になります。ワークエリアを取られるとしても、せいぜい4Mもあれば十分じゃないでしょうか。一昔前なら論外なこのサイズですが、すでに3世代前になるTNT2あたりのグラフィックカードですら16MのVRAMをつんでることを考えれば問題ナッシング。わけで、サンプルソースです。さっきのサンプルに比べ少し見え方が異なります。前フレームを今フレームの上に半透明描画しているので、オブジェクトの端の方が透けて見えます。適当に流してしまうのが大人の態度ってもんでしょう。いつも通りですが、エラーチェックは最低限であり、このサンプルの使用によるいかなる不幸も当方では責任を負いかねます(^^;今回のはいつものに輪をかけて適当です。UpDate:01/07/02うだうだやっていてオブジェクト全体に対する操作と衝突判定用のバウンディングボックス生成部分が出来ました。あいかわらず親切なDirectX8君にはD3DXComputeBoundingSphere,D3DXComputeBoundingBoxなる関数があって一発でバウンディングボックスを生成できます。問題は当たり判定を球でやるか直方体でやるかですが、こっちのニーズとしては直方体の方が精度が良いんですが、なんせ直方体同士の判定なんてめんどくさいものやってられません。調べてみましたが、解答ずばりというものも見当たりませんでした。自分の頭で考えるのは論外です(笑)そんなわけで球の半径を小さめにして利用することに決定。計算量的にもお得ですしね。DirectX9で直方体同士の衝突判定関数が出来ることを祈ってます。そこらへんは余談で、今回はプロファイラの挙動について覚書を書いておこうというのが本題です。プロファイラ使ってプログラムの解析するのは常套手段ですが、VC++の奴はボケてます。[プロジェクト]->[設定]->[リンク]の中の[プロファイルを行う]チェックボックスにうまくチェックを入れられないという訳のわからんバグがあります。回避策は[プロジェクトオプションに]手作業で/profileを書いてあげること。あとは[ビルド]->[プロファイル]でプロファイリングが出来ます。あと、実行時に使用するデータファイルなんかをプログラム中で相対パスで書いてあるとヤバイです。通常プログラムをVC++上で実行する場合プロジェクトのあるディレクトリがルートになってますが、プロファイル時には実行ファイルのある場所(Debugディレクトリ等)がルートになっているようです。うまく動かないんで悩んでしまいました、むぅ。>これって「プロジェクト」->「設定」の部分でルートを指定できるはずっすよ。いうナイス突込みをいただきました。プロファイル時にはちゃんと指定しましょうね、うふ。UpDate:01/10/06世の中、しちゃいけない発言というものがいくつかあります。先日某社の飲み会でうっかりその会社の製品と思い込んで別のところの製品を誉めてしまいました。いや場が凍ること凍ること、つらかったですね。この手のことを年に何回かやって、さらに年に何回か思い出しては夜中に布団の中でもだえています。DirectXに関して言えば、このしちゃいけない質問のひとつに『IMでアニメーションしたいんですけど』って奴があります。DirectXBBSなんかでしょっちゅう質問が出ては『うぜぇ、ボケ、自分で何とかしろ(意訳)』ってな回答が繰り広げられています。はいっても、分からんもんは分からんし、めんどくさいもんはめんどくさい。ご多分に漏れず、私も自分でやるのがめんどくさかったんで、広大なネットに適当なソースを探す旅に出たんですよ。DirectX7以前で使えそうなのではここのソースが最高(モーションブレンドまでOK)ではないかと思うんですが、DirectX8用が見当たらないんですね。ワンスキンなモデルを使う気も無いし、作る技量もありません。結局、親子付けモーションの再生ルーチンを書くことにしました。Xファイルについて適当な解析。モデルFrameってのが一番大きな入れ物で、その中にTransformMatrix,Mesh,MeshMaterialList,MeshNormalsなんかが入っている。Frameの中にFrameを入れ子にできて、これが親子関係を表している。TransformMatrixはアニメーションの無いモデルのときは各フレームの位置関係を指定するために使用。アニメーションするときはPosition行列があるので使う必要がないっぽい。アニメAnimationSetってのが一番大きな入れ物で、その中にAnimationが入っている。AnimationSetを複数持てるのかは不明だが、ニーズはありそうなんできっとできるんでしょう。今回は1個のAnimationSetだけを考える。Animationは一つのフレームに対して一つずつあるようで、その中にフレーム名とAnimationKeyが入っている。AnimationKeyは頭2つのデータがキーの種類(回転、移動、スケール、行列キー(前3つの行列の合成))とキーの数を表している。手持ちのXファイルを眺めたところ、こんな感じではないかと思われます。アニメーションをループをさせる時には最終キーから最初のキーにつなげなきゃならないんですが、LightWave->lws2xでXファイルを作ると最終キーと最初のキーの間に1フレーム存在するようです。いや、そんな気がするだけで単に私のモーションの作り方が悪いだけかもしれません。他の3Dツールでは違うかもしれないですし・・・。ここらへんを踏まえてコーディング開始です。最低単位がメッシュなのでこいつをクラスにします。次にメッシュを幾つか集めたものがフレームなのでこいつもクラスにします。フレームは親子付けされているので親フレームへのポインタを保持します。最後にフレームを幾つか集めたものがアニメーションオブジェクトになるのでこいつもクラスにしましょう。使えそうなソースはSkinnedMeshサンプルからかっぱらってきて使用します。Xファイルによってメッシュクラスやらフレームクラスやらがいくつ必要になるか分からないので、STLを使ってお手軽に動的配列を実装します。こんな感じであっという間に出来てしまいます。)を読んであげないと駄目らしいこと。{}{FrameName}}のようにキーの後に書いてある場合(SkinnedMeshサンプルで使っているTiny.x)があるみたいです。一度アニメーションを仮のフレームに読み込んでおいてから改めてそれぞれのフレームにコピーすることにしました。アニメーションの拡大、回転、移動の各行列の掛け順は拡大はともかく回転、移動はこの順で。親子付けされているので、子供のフレームには親のフレームの行列も掛けてあげる必要があります。以上、一応動くらしいのでサンプルソース。外部依存ファイルに対するパスは自分で直してください。昔作ったロボットに適当なテクスチャ張っときました。テキスト形式、バイナリ形式どちらのXファイルでも読めるはずです。LightWave->lws2x以外の方法で作ったXファイルの挙動は謎です。暇な方は動作報告してくれるとうれしかったり。叩き台のソースなのでオブジェクト全体に対する操作(移動や回転、マテリアル変更)なんかは全然実装してません。数日ででっち上げるソースなんてそんなもんです。アニメーションしないオブジェクトの表示でTransformMatrixの扱いをミスっていました。親フレームのマトリクスかけ忘れてました、馬鹿ですね。ついでに変数名のミスも直しときました。このプログラムはメッシュがフレームに乗っかってることが前提になっています。よってLightWaveのlwoファイルに対してLws2Xをかけて出来るフレームの無いメッシュだけのXファイルを読み込むことは出来ません。一度lwsでセーブしてからLws2Xして下さい。暇なときに直しておきます。気が向いたので01/07/22追記分の修正とDirectX8用のテンプレートが含まれたXファイルに対応しときました。これでメッシュ単体のXファイルも読み込めるはずです。ばらして、もしアニメーションオブジェクトに対応するキーがない場合はかけてやらなきゃ駄目ですね。