3D関係

先日、3DRPGプログラミングとかスクリプトエンジン プログラミングを執筆されている 坂本千尋 氏とお会いする機会がありました。
3Dレンダリング技術の将来など聞かせていただいたのですが、寡黙で、そして温和な方という印象でした。
当初はご本人だと気付かず、色々失礼なことを訊いてしまった気がo(`ω´;)o
3DRPGプログラミング (C magazine) スクリプトエンジン プログラミング

有名なプログラマの方と実際にお話をしたのは初めてで、とてもドキドキしました。
また業界でばりばりお仕事されるようなので、いつの日かまたお会いしたいなo(`ω´*)o

c_dfDIKeyboard c_dfDIMouse の中身を調べる話

久しぶりの普通の更新ですヽ(・ω・*)ノ
この話のきっかけは、GDKライブラリをVC++2008用にインポートした時でした。
DirectX9SDKに dinput.lib が存在せず、ビルドができなかったのです。


DirectXはCOMで実装されているので、本来はlibファイルをリンクする必要はありません。
が、困ったことにDirectInputだけ「c_dfDIKeyboard」「c_dfDIMouse」というlibに実体がある定数が定義されているのです。


定数の中身をgoogle先生に聞いたのですが、お茶を濁された感じに。
仕方がないので、自分で解析してみました。


    // キーボードフォーマットの準備(c_dfDIKeyboardの中身はコレだ!)
    DIOBJECTDATAFORMAT obj[256];
    DIDATAFORMAT format;
    format.dwSize       = sizeof(DIDATAFORMAT);
    format.dwObjSize    = sizeof(DIOBJECTDATAFORMAT);
    format.dwFlags      = DIDF_RELAXIS;
    format.dwDataSize   = 256;
    format.dwNumObjs    = 256;
    format.rgodf        = obj;

    for(int i=0; i<256; ++i) {
        obj[i].dwOfs    = i;
        obj[i].dwType   = DIDFT_OPTIONAL | DIDFT_BUTTON | (i << 8);
        obj[i].dwFlags  = 0;
        obj[i].pguid    = &GUID_Key;
    }


    // マウスフォーマットの準備(c_dfDIMouseの中身はコレだ!)
    DIOBJECTDATAFORMAT obj[7];
    DIDATAFORMAT format;
    format.dwSize       = sizeof(DIDATAFORMAT);
    format.dwObjSize    = sizeof(DIOBJECTDATAFORMAT);
    format.dwFlags      = DIDF_RELAXIS;
    format.dwDataSize   = 16;
    format.dwNumObjs    = 7;
    format.rgodf        = obj;

    obj[0].dwOfs        = 0;
    obj[0].pguid        = &GUID_XAxis;
    obj[0].dwType       = DIDFT_ANYINSTANCE | DIDFT_AXIS;
    obj[0].dwFlags      = 0;
    obj[1].dwOfs        = 4;
    obj[1].pguid        = &GUID_YAxis;
    obj[1].dwType       = DIDFT_ANYINSTANCE | DIDFT_AXIS;
    obj[1].dwFlags      = 0;
    obj[2].dwOfs        = 8;
    obj[2].pguid        = &GUID_ZAxis;
    obj[2].dwType       = DIDFT_ANYINSTANCE | DIDFT_OPTIONAL | DIDFT_AXIS;
    obj[2].dwFlags      = 0;
    obj[3].dwOfs        = 12;
    obj[3].pguid        = NULL;
    obj[3].dwType       = DIDFT_ANYINSTANCE | DIDFT_BUTTON;
    obj[3].dwFlags      = 0;
    obj[4].dwOfs        = 13;
    obj[4].pguid        = NULL;
    obj[4].dwType       = DIDFT_ANYINSTANCE | DIDFT_BUTTON;
    obj[4].dwFlags      = 0;
    obj[5].dwOfs        = 14;
    obj[5].pguid        = NULL;
    obj[5].dwType       = DIDFT_ANYINSTANCE | DIDFT_OPTIONAL | DIDFT_BUTTON;
    obj[5].dwFlags      = 0;
    obj[6].dwOfs        = 15;
    obj[6].pguid        = NULL;
    obj[6].dwType       = DIDFT_ANYINSTANCE | DIDFT_OPTIONAL | DIDFT_BUTTON;
    obj[6].dwFlags      = 0;

「c_dfDIKeyboard」「c_dfDIMouse」の代わりに上で定義したformatをDirectInputDevice::SetDataFormatに渡します。
古いSDKの場合 DIDFT_OPTIONAL が定義されていない場合があるので、0x80000000で#defineしてくださいo(`ω´*)o

数学をとらなかった人の為の3D数学 その4:概要2

行列(Matrix)

前回、行列とはベクトルを座標変換するものであると書いたが、具体的にどうか。


ある数nと分数1/mを考える。
分数1/mは、そのまま1/mという数を表現するものであるが、nを1/mする数でもある。
ここで、ある数nを1Dベクトルとして見れば、分数1/mは行列と同じ作用(座標変換)をしていないだろうか。
そう考えると、分数1/mは行列なのである。


N次元ベクトルの座標変換に必要な情報はNの2乗個なので、分数1/mは1x1行列ということになる。



逆に考えると、行列は算数で学んだ分数と、何ら変わらないものなのである。
分数とは数であり、数を座標変換するものである。
行列とはベクトルであり、ベクトルを座標変換するものである。


4Dプログラミング(4x4行列を使う理由)

続きを読む

3Dプログラミングあるある話

描画順で悩んだら

ZバッファやZソートの前にまずカリングをONにして法線の向きの確認を。
その三角形は思った通りに展開されていないかもしれません。

オブジェクトが真っ黒

ディスプレイモード変更時にオブジェクトが真っ黒になってしまった時は、レンダリングステートの確認を。
ライティングオフしていた場合、新しいデバイスではオンに戻ってるかもしれません。というか戻ってます。

描画順で悩んだら2 (2010/07/23 更新)

Zバッファがちゃんと機能してない?
それはきっとバッファあふれを起こしています。


プロジェクション行列のnear値とfar値をチェックしてください。
0.001f〜10000.0fとか無茶な指定していませんか。
今日びのZバッファは16bit(0〜65535)なので、far値を大きくとりたいなら 1.0f〜6553.5fとか10.0f〜65535.0fくらいに勘弁してあげましょう。

他のマシンで正常に描画されない (2010/07/24 更新)

ビデオカードによる制限という場合もあります。が。
DrawPrimitive等に渡す頂点数、プリミティブ数がおかしいのかもしれません。
ビデオカードはものによっていい加減だったり厳格だったり、いろいろ性格がありますが、いい加減な場合、適当に頂点数を指定しても描画されたりします。


一度描画メソッド(頂点バッファ、インデックスバッファ)を点検してみましょう。


他のマシンで正常に描画されない2 (2010/08/30 更新)

今回はテクスチャ関係でデバイスコンテキストを使った場合です。
昔のWindows(もしくはビデオカードに依存するかもしれませんが)では、αサーフェースのデバイスコンテキストが取れませんでした。
多分GDIがパワーアップしたXP以降で可能になったと思うのですが、そんな感じでデバイスコンテキスト経由でファイルからテクスチャのサーフェースに書き込んだりもできます。


が。


このデバイスコンテキストを経由、つまりXRGB8888やRGB888からARGB8888サーフェースに転送するとα値が全て0に設定されてしまいます。
なんで0?COLORREFで比較できるように?
ともかくデバイスコンテキスト経由で読み込んだ場合は、全てのピクセルのα値を255に設定しなおすようにしましょう。