「 プログラミング 」一覧

C++/CLIでの実行時エラー


C++/CLIとC++ネイティブのlibをリンクさせて、Windowsフォームアプリケーションを作ったときに、
よくわからないエラーが発生してしまうことがある。

どうやらCRT初期化の順序に問題があるのか。
これを解決するには、エントリポイントの修正を行えば解決する模様。
次のエントリポイントに設定させてあげれば問題解決できた。

ずいぶんと前にわかっていて、日記に書いたと思ったのに忘れていたので、
今更ながら追加。

上記の発生条件

どうやらグローバルなコンストラクタが実行されるときに何かがあるらしい。
C++のclassメンバにstaticなデータがある場合に発生する。
また、それが組み込み型(プリミティブ型)ならば問題なく動くが、
自分で作成したクラス型だと実行時エラーの引き金となる。

追記1

コンストラクタやデストラクタを備えるクラスだとアウトっぽい。
そのクラスがプリミティブ型しか保持していないとしても。

追記2

どうやらコンストラクタがあることが問題ではないらしい。
デストラクタがあることが問題のようだ.
デストラクタのあるクラス型で、クラスstaticメンバを持つと、このエラーが発生する。

こういったクラス構造をどこかで持ってしまうと、C++/CLIで実行時エラーとなる.


DirectXのテクスチャについて


メモリ管理やUSAGEの組み合わせで気になったので調査.

生成時フラグ

D3DPOOL D3DUSAGE 結果
Default 0 OK
Default WRITEONLY NG
Default DYNAMIC OK
Managed DYNAMIC NG
SystemMem DYNAMIC OK
Default DYNAMIC RENDERTARGET OK
Default RENDERTARGET OK

ロック時フラグ

タイプ ロック手法 結果
Default&Dynamic&&RenderTarget 0 NG
Default&RenderTarget 0 NG
Default&RenderTarget D3DLOCK_READONLY NG
Default&Dynamic&&RenderTarget D3DLOCK_DISCARD NG
Default&RenderTarget D3DLOCK_DISCARD NG
Default&Dynamic D3DLOCK_READONLY OK
Default&Dynamic D3DLOCK_DISCARD OK
SystemMem&Dynamic D3DLOCK_READONLY OK
SystemMem&Dynamic D3DLOCK_DISCARD OK

感想

意外だったのは SystemMemでDynamicタイプを作れること。

それでもSystemMemでRenderTargetは無理でしたが(当たり前)。


インターフェース変更


DirectXのヘッダを見ていて気付いたこと。
同名のIIDで、値だけ違うってまずいんじゃないだろうか。

DEFINE_GUID(IID_ID3DXEffect,
0xd165ccb1, 0x62b0, 0x4a33, 0xb3, 0xfa, 0xa9, 0x23, 0x0, 0x30, 0x5a, 0x11);

DEFINE_GUID(IID_ID3DXEffect,
0xf6ceb4b3, 0x4e4c, 0x40dd, 0xb8, 0x83, 0x8d, 0x8d, 0xe5, 0xea, 0xc, 0xd5);

確かにメソッドの数が違うから新しいIIDにするのは納得がいくのだけども、こんなことして、平気なのかな?と思う。もしや、こういう強引なことを出来るようになったのも、対応するd3dx_**.dllが分かっているから、なのか?

だれか情報知っていたら教えて欲しいです。

 


D3DXCreateEffectについて – CompileEffect


マクロで有効・無効のブロックを切り替えるにはどうしたらいいんだーということで調べてました。
ピクセルシェーダーコードでは、以下のようにして挙動をチェックしていました。

[code lang=”cpp”]
#ifdef _TEST_
return float4(1,1,1,1);
#else
return float4(0,0,1,1);
#endif
[/code]

これをEffectでやるのにネックだったのは、マクロ定義変数の部分でした。

解決策はこう。

[code lang=”cpp”]
D3DXMACRO d3dxMacros[2] = { //マクロ マクロ名
"_TEST_","", <– ここで定義する部分を設定して
0, 0 <– ここで終端を示すようにヌルターミネートしておく
};
[/code]

通りでマクロの設定長を示す引数がないわけだ。

探してみてもこの辺でつまずく人はいないのか、記述が見あたらず。
また、ほとんどの場合このマクロ設定部分NULLにしちゃうし、使う状況ってないのかなぁ。

自分では多用していこうと思っていますが。


動かないコード


最近は動かないコードばかり書いてます。コンパイルを通してニヤリ、として終了です。
コンパイル時にすでに判定や計算が終わっている、とか、プリプロセッサ終了時に状態確定とか、そんなことばっかりやってました。

ふと、覗いてみるとどうやらBoostのPreprocessorが分野的に近い。そして、templateで色々とごちゃごちゃやったことは、メタプログラミング、という分野にいるっぽいことがわかりました。

こうやってできたコード、少なくとも人に読ませられるコードじゃないなぁと実感してます。数ヶ月後の自分でも怪しい・・・。

 


昨日の答え。


意外にも日を変えて再度悩んでみると思いつくものである。
とりあえず下記コードでやりたいことはできた。
しかし、T,Sなど1文字の型引数にしておくと、次みたときに相当わからないなぁ…

しかしこのコード、少なくとも今年一番イケてると自負してます

 


スキニング問題


前からやっていたスキニング、前回までの結果ではうまくできないことが判明し、もがいてます。

出来ないのは下記の理由により。

  •  SkinedMeshサンプルではマトリックスパレットに設定している値そのものがワールドになっている。
  •  結果、ライト位置をモデル空間に変換しただけではNG (全てをワールドでやればOKでしょうが…)

というわけで、スキンメッシュの表示方法そのものを変更しようかと。
点光源にチャレンジしていなかったら、上記の問題点に気付かずに放置していただろうなーと思うと運が良かったのかな。

 


描画システムのMultiThread対応


スキニングメッシュもかろうじて表示できたので、諸々の部分をダブルバッファリングにして、描画とメインの実行ループの分離を行ってみました。文章にするとこれだけのことなのに苦戦しましたよ…。

  • DirectXのリソース作成・破棄はメインスレッドでやらなくてはいけない
  • アプリケーションの実行はサブスレッドになる。
  • DirectXは、WndProcが実行されるスレッドで初期化されなくてはならない。また基本的にこのスレッドで実行されるべきである。
  • 当然、描画要求を出してタイミングがきたら描画。このためバッファリング必要

色々と書き換えてようやく、ポイントライトなシェーダーを実行させるところまでは出来ました。しかしスキキングメッシュ関連で、マルチスレッド化に伴いフォルスシェアリングが起こりそうだったので、またスキニングメッシュは表示できない状態へ戻りました…


DirectXのロックの謎


DirectX9のLockについて、調べてみたことをメモしておきます。

Textureのロックには、範囲指定があるが、Lockは複数回できるのか?

まずは推測から。
範囲指定がわざわざあるということは、部分1でLockし、部分2でLockしても問題なさそうである。また、領域が重なった場合は多重ロックになりNGとなる。と予想。

結果は・・・領域が被っていようが、別部分であろうがNGでした。どうやら、範囲指定はパフォーマンスをあげるためのダーティー判断くらいでしかなさそう。ただし、異なるミップマップについては同時Lockは可能のようです。

 

VertexBufferのロックはどうだろうか?

テクスチャが上記のような結果になったのだから、やはり多重ロックは失敗するだろうと予想。あるいはNO_OVERWRITEフラグなんかあるし、領域さえ違えば成功するのかも知れない。

結果は・・・領域が被っていようが、別であろうが、多重ロックは成功する。多重ロック後は、正しくUnlock呼ばないといけないそうです。

このロックの挙動の違いは問題になりそう…。そもそも多重ロックを許可しない方針でプログラムを作っていくべきかも知れません。

上記を試したのは、DirectX9.0cで、GeForce7600GT on Vista(x64)です。他のメーカーのカードでは異なる結果となるかも知れません。 次は、OpenGLのMapBufferとか調べてみる?!

 


XSI ModToolからスキニングメッシュ出力


スキニングメッシュとして、円柱にボーンを仕込んだものを作ってみました。

適当に曲げてみて、それを独自形式変換して表示できるかやってみたのですが、失敗してしまい、 tiny.xからの作った場合には正常に表示できているのですが。

うまく出す方法判明

いくつか試してようやく解法がわかりました。
DirectXのエクスポーターの設定で CompressMeshにチェックが入っているとダメのようです。

また、Trianglateにチェックを入れても豪快に崩れました。
このことから、素直に .xを作り、やるならその後最適化をするという流れをとった方が良さそうです。