OPENGLによるオフスクリーンレンダリング

解決


よっち  2009-01-10 01:13:07  No: 33073

Delphi7/WinXP  です。

表題の通りOPENGLによるオフスクリーンレンダリングを試みています。
pfd_draw_to_bitmapを設定した上で、Tbitmap(BID)を使っているのですが、
wglMakeCurrentがどうしてもtrueになりません。
解決法をご存知の方いらっしゃいませんか?

procedure TForm1.SetPixelFormatDescriptor;
var
    pfd: TPixelFormatDescriptor;
begin
    with pfd do begin
        nSize := sizeof(TPixelFormatDescriptor);
        nVersion := 1;
        dwFlags := PFD_DRAW_TO_BITMAP or
            PFD_SUPPORT_OPENGL or
            PFD_DOUBLEBUFFER
            ;
        iPixelType := PFD_TYPE_RGBA;
        cColorBits := 24;
        cRedBits := 0;
        cRedShift := 0;
        cGreenBits := 0;
        cGreenShift := 0;
        cBlueBits := 0;
        cBlueShift := 0;
        cAlphaBits := 0;
        cAlphaShift := 0;
        cAccumBits := 0;
        cAccumRedBits := 0;
        cAccumGreenBits := 0;
        cAccumBlueBits := 0;
        cAccumAlphaBits := 0;
        cDepthBits := 32;
        cStencilBits := 0;
        cAuxBuffers := 0;
        iLayerType := PFD_MAIN_PLANE;
        bReserved := 0;
        dwLayerMask := 0;
        dwVisibleMask := 0;
        dwDamageMask := 0;
    end;

    nPixelFormat := ChoosePixelFormat(hdc, @pfd);
    SetPixelFormat(hdc, nPixelFormat, @pfd);
end;

/////////////

    GLCanvas := TBitmap.Create;
    GLCanvas.HandleType := bmDIB;
    GLCanvas.Width := Panel5.Width;
    GLCanvas.Height := Panel5.Height;
    GLCanvas.PixelFormat := pf24bit;
    hdc := GetDC(GLCanvas.Handle);  //hdc は HDC型

    SetPixelFormatDescriptor;

    hrc := wglCreateContext(hdc); //hrc は HGLRC型

    if (wglMakeCurrent(hdc, hrc) = false) then begin //ここがTrueになりません
        GLCanvas.Free;
    end;


みんみん  2009-01-12 23:57:50  No: 33074

OpenGLは知らないけど、怪しいところを一つ指摘。

hdc := GetDC(GLCanvas.Handle);
            ↓
hdc := GLCanvas.Canvas.Handle;

だと思う。

GetDCの引数はウィンドウハンドルであって、
ビットマップハンドルではないのでは?

TBitmapのデバイスコンテキストはCanvas.Handleで参照します。


よっち  2009-01-13 22:55:30  No: 33075

>みんみんさん
レスありがとうございます。

hdc := GetDC(GLCanvas.Handle);
            ↓
hdc := GLCanvas.Canvas.Handle;

試してみましたが、やはり同じでした。
wglMakeCurrentがfalseのままです。
調べてみたところどうやらTbitmap.canvas.handleが随時更新される
Delphi版TCanvasの仕様が原因らしいです。
しかし具体的な対応策は見つかっていません。

引き続き回答をお待ちしています。


うんと  2009-01-14 00:29:47  No: 33076

やはり OpenGLは知らないけど、

hdc := GetDC(GLCanvas.Handle);
            ↓
hdc := GetDC(Panel5.Handle);

ではどうでしょうか?


にしの  2009-01-14 01:33:22  No: 33077

> hdc := GetDC(GLCanvas.Handle);
>             ↓
> hdc := GetDC(Panel5.Handle);
単純なダブルバッファリングであれば、Panel5のDCとればOKですが、
オフスクリーンレンダリングの場合はHBITMAPを作ってやるのが正しいかと。

C++ですが、
http://son-son.sakura.ne.jp/programming/opengl_avi.html
にありました。
DelphiのTBitmapが使えないのであれば、APIで作るしかないかと思います。


みんみん  2009-01-14 02:58:54  No: 33078

>調べてみたところどうやらTbitmap.canvas.handleが随時更新される
>Delphi版TCanvasの仕様が原因らしいです。
>しかし具体的な対応策は見つかっていません。

TCanvasの仕様が原因でしたら、
中村拓男さんのところで紹介されているCanvas.Lockの方法を
試してみてはいかがでしょう?

http://www.asahi-net.or.jp/~ha3t-nkmr/DGS/more_secrets.htm#Secret3


よっち  2009-01-14 08:04:16  No: 33079

>うんとさん
レスありがとうございます。
現在Panel5.Handleで処理をしているのですが、
これのオフスクリーン化を目論んでいて、
さし当たってまず下処理の方法を考えています。

>にしのさん
レスありがとうございます。
APIで作る・・・なんだか難しそうですが、
少し調べてみたいと思います。

>みんみんさん
再度のレスありがとうございます。
Canvas.Lockを試してみたのですが、やはり結果は変わりません。
Lockの使い方が間違ってる気もするのですが・・・

    GLCanvas := TBitmap.Create;
    GLCanvas.Lock; //追加しました。
    GLCanvas.HandleType := bmDIB;
    GLCanvas.Width := Panel5.Width;
    GLCanvas.Height := Panel5.Height;
    GLCanvas.PixelFormat := pf24bit;
    hdc := GetDC(GLCanvas.Handle);  //hdc は HDC型

    SetPixelFormatDescriptor;

    hrc := wglCreateContext(hdc); //hrc は HGLRC型

    if (wglMakeCurrent(hdc, hrc) = false) then begin //ここがTrueになりません
        GLCanvas.Free;
    end;


watch  2009-01-14 08:35:29  No: 33080

同じくOpenGLには詳しくありませんが……
みんみんさんが最初に指摘した点(GetDCは間違い)は元に戻しちゃダメでしょう。明らかにおかしいですから。
念のため、hdcが有効なハンドルかどうかちゃんとチェックするようにした方がいいですね。
あと、にしのさんが引用したページにある注意事項(PFD_GDI_SUPPORTが必要)は入れてみましたか?

> Lockの使い方が間違ってる気もするのですが・・・
TBitmapにLockメソッドはないはずだから確かにおかしいですね……
GLCanvas.Canvas.Lockでは? あとUnlockも忘れずに。


よっち  2009-01-15 01:27:18  No: 33081

>watchさん
レスありがとうございます。
確かに間違ってました。
すいません。
PFD_GDI_SUPPORTも追加しています。
ただ、結果は変わらないです。
なにかもっと根本的な問題かもしれないですね…

 GLCanvas := TBitmap.Create;
    GLCanvas.canvas.Lock; //追加しました。
    GLCanvas.HandleType := bmDIB;
    GLCanvas.Width := Panel5.Width;
    GLCanvas.Height := Panel5.Height;
    GLCanvas.PixelFormat := pf24bit;
    hdc := GetDC(GLCanvas.canvas.Handle);  //hdc は HDC型

    SetPixelFormatDescriptor;

    hrc := wglCreateContext(hdc); //hrc は HGLRC型

    if (wglMakeCurrent(hdc, hrc) = false) then begin //ここがTrueになりません
        GLCanvas.Free;
    end;


watch  2009-01-15 01:54:56  No: 33082

いや、だからGetDCはいりません。結果を確認すればおかしいことはわかるでしょう?
GetDCがとるのはあくまで「ウィンドウハンドル」であって「ビットマップハンドル」でも「デバイスコンテキストハンドル」でもないです。
あなたがやっていることは、同じ「カード」だからとクレジットカードで自動改札を通ろうとしているようなものです。

この場合、あなたが欲しいものはデバイスコンテキストハンドル(HDC)で、
TBitmap.Canvas.Handle=HDCなんだからその時点で必要なものは得られているでしょう?

とりあえずwglMakeCurrentだけでなく、そこに至るまでの関数もちゃんと成功しているのか
一つ一つ結果をチェックして、悪いところを切り分けてください。


みんみん  2009-01-15 08:00:31  No: 33083

>PFD_GDI_SUPPORTも追加しています。

正しくはPFD_SUPPOR_GDIです。(OPENGL.pas参照)

私の環境(del7+WinXPsp2)では

hdc := GLCanvas.Canvas.Handle;
の部分の修正と

上記のPFD_SUPPOR_GDIフラグの追加で
判定部分の  wglMakeCurrent(hdc, hrc)が、
Trueを返すようになるようです。

ここの判定のみでしたらCanvas.Lockは無くても
いいようでした。

よっちさんどうでしょうか?


よっち  2009-01-15 08:29:53  No: 33084

>みんみんさん
わざわざ検証していただきありがとうございます。
ただ現在出先で、再度確認できるのが1週間後になってしまいます。
申し訳ありません。
ただ、必ず報告させていただきますね。


みんみん  2009-01-20 02:49:39  No: 33085

訂正(^ ^)m

>正しくはPFD_SUPPOR_GDIです。(OPENGL.pas参照)
       ↓
正しくは PFD_SUPPORT_GDIです。(Windows.pas参照)

です。


よっち  2009-01-22 01:14:50  No: 33086

無事解決したので報告です。
最終的に、みんみんさんの

>hdc := GLCanvas.Canvas.Handle;
>の部分の修正と

>上記のPFD_SUPPOR_GDIフラグの追加で
>判定部分の  wglMakeCurrent(hdc, hrc)が、
>Trueを返すようになるようです。

これで問題がなくなりました。
皆様回答していただきありがとうございました。


よっち  2009-01-22 04:49:14  No: 33087

解決しましたので


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加