OpenGL mini tips

ひとつのページとして書くほどの量はないけど、
引っかかって悩みやすいポイントとか、
注意しておきたいこととか、
いろいろ。


glScale*とライティング

glScalef または glscaled 関数を使用すると、
法線ベクトルまでスケーリングされてしまう。

つまり、
ライティングが有効な場合、
glNormal* で、長さが1の規格化された法線ベクトルを指定しても、
スケーリングされて長さが1でなくなってしまうので、
正しいライティングの効果が得られなくなってしまう。
(妙に暗くなったり、明るくなったりする。)

解決策としては、
glEnable( GL_NORMALIZE );
として、
自動的に法線ベクトルの規格化を行うように指定すればOK。
ただし、OpenGLのほうに余計な計算(法線ベクトルの規格化)をさせることになってしまう。


アンマネージ関数に関数ポインタを渡す

GLUを利用する際に、
特にテセレーションなどで、
コールバック関数への関数ポインタを渡す必要がある場合がある。
しかし、C#では「関数ポインタ」の役割をしているのは「デリゲート」であり、
かといって、アンマネージ関数に直接デリゲートを渡すことは出来ない。

で、どうするのか、と。

早い話、
実は、デリゲートから関数ポインタを取得するメソッドなんてのがありまして。
System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate
です。
このメソッドの引数にデリゲートを渡してやれば、IntPtr型として関数ポインタを返してくれる。

つまり、手順としては、
コールバック関数のデリゲートを上記の関数に渡して、
返されたIntPtr型のポインタを、コールバック関数へのポインタとして
アンマネージ関数に渡してやればよい。

ただし。
関数ポインタの取得に使ったデリゲートは、
コールバック関数が呼ばれなくなるまではプログラム内で保持されていなければない。
(ポインタから参照されているのはデリゲートなので、当たり前なのだが。)
でないと、
いつの間にかガベージコレクト(ゴミとして回収・破棄)されて、
参照されるべきものが無くなってしまう場合がある。
(こうなってしまうと、当然、実行中にエラーが発生する。コンパイル時ではエラーにならない。)
関数ポインタだけ取得して、参照されているデリゲートは捨ててしまった、
なんてことの無いように、注意されたし。


マネージオブジェクトとポインタ

GLUの関数とか、
アンマネージ関数の引数にマネージオブジェクトのポインタを渡さなければならない場合があったりする。
はっきり言って、あまりC#でポインタを扱いたくはない(し、扱うべきではない)のだが、
やむを得ず使わなければならない場合の対処法。

つまり、
マネージオブジェクトのポインタを取得したり、
ポインタからマネージオブジェクトを取得したりする方法。

unsafeキーワードとコンパイラオプションの指定で、
直接ポインタを扱うこともできなくはないのだが、
ここでは、IntPtr型としてポインタを扱う方法を説明する。

たとえば、
MyClass myClass = new MyClass();
というのがあって、このmyClassのポインタを取得したい、とする。

どうするか、というと、

IntPtr ptr = System.Runtime.InteropServices.GCHandle.ToIntPtr( GCHandle.Alloc( myClass, GCHandleType.Pinned ) );

これで、ポインタを取得できる。

ポインタから再びマネージオブジェクトを取得するには、

MyClass myClass2 = (MyClass)GCHandle.FromIntPtr( ptr ).Target;

これでOK。


<back to OpenGL menu>