在 Delphi 中使用 OpenGL 進行 3D 繪圖,第一步就是正確建立裝置內容 (DC)、設定像素格式 (PFD) 與繪圖內容 (RC)。本文整理作者從 C++ 轉 Delphi 開發 OpenGL 的實戰筆記,涵蓋多種 DC 取得方式、PFD 參數設定細節、RC 建立與釋放、跨平台 (NT/9x) 差異排查等關鍵知識點。
// 方式 1:直接使用 Canvas.Handle (最簡單,適用於 TForm/TPaintBox)
DC := Canvas.Handle;
// 方式 2:API GetDC (需配對 ReleaseDC)
DC := GetDC(Handle);
// 方式 3:CreateCompatibleDC (離屏繪圖/列印)
// 方式 4:BeginPaint/EndPaint (WM_PAINT 中)
注意:非 Canvas.Handle 方式取得的 DC,用畢必須 ReleaseDC 或 DeleteDC 釋放,否則洩漏 GDI 物件。
function SetupPixelFormat(var DC: HDC): Boolean;
var
ppfd: PIXELFORMATDESCRIPTOR;
nPixelFormat: Integer;
begin
FillChar(ppfd, SizeOf(ppfd), 0);
ppfd.nSize := SizeOf(PIXELFORMATDESCRIPTOR);
ppfd.nVersion := 1;
ppfd.dwFlags := PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER;
ppfd.iPixelType := PFD_TYPE_COLORINDEX; // 或 PFD_TYPE_RGBA
ppfd.cColorBits := 8;
ppfd.cDepthBits := 16;
ppfd.cAccumBits := 0;
ppfd.cStencilBits := 0;
ppfd.iLayerType := PFD_MAIN_PLANE;
nPixelFormat := ChoosePixelFormat(DC, @ppfd);
if nPixelFormat = 0 then begin Result := False; Exit; end;
if not SetPixelFormat(DC, nPixelFormat, @ppfd) then begin Result := False; Exit; end;
Result := True;
end;
var
pfd: PIXELFORMATDESCRIPTOR;
nPixelFormat: Integer;
begin
FillChar(pfd, SizeOf(pfd), 0);
with pfd do
begin
nSize := SizeOf(pfd);
nVersion := 1;
dwFlags := PFD_SUPPORT_OPENGL or PFD_DRAW_TO_BITMAP or PFD_DOUBLEBUFFER;
iPixelType := PFD_TYPE_RGBA;
cColorBits := 32;
cDepthBits := 32;
iLayerType := PFD_MAIN_PLANE;
end;
nPixelFormat := ChoosePixelFormat(DC, @pfd);
SetPixelFormat(DC, nPixelFormat, @pfd);
// 可選:DescribePixelFormat 檢查是否需調色盤
end;
| 旗標 | 用途 |
|---|---|
| PFD_DRAW_TO_WINDOW | 繪製到視窗 (螢幕) |
| PFD_DRAW_TO_BITMAP | 繪製到記憶體位圖 (離屏/列印) |
| PFD_SUPPORT_OPENGL | 支援 OpenGL 呼叫 |
| PFD_DOUBLEBUFFER | 雙緩衝 (動畫必備) |
| PFD_STEREO | 立體視覺 (專業顯示卡) |
RC := wglCreateContext(DC);
wglMakeCurrent(DC, RC);
wglMakeCurrent(0, 0); // 解除當前 RC
if RC <> 0 then wglDeleteContext(RC);
if DC <> 0 then ReleaseDC(Handle, DC); // 若用 GetDC 取得
// 若用 Canvas.Handle 則無需釋放 DC,由 VCL 管理
作者發現相同程式在 Windows NT 上 ChoosePixelFormat 回傳 >0,但在 Win9x 回傳 0。然而 NT 編譯的 EXE 在 9x 上卻能正常執行。推測為驅動程式對 PFD 旗標組合支援度不同。建議:
PFD_TYPE_RGBA + 32 位元色彩 + 32 位元深度,相容性最佳。ChoosePixelFormat 失敗,嘗試移除 PFD_DOUBLEBUFFER 或降低色彩位數。Delphi 內建 OpenGL.pas (或 dglOpenGL.pas 第三方更新版) 已宣告所有 gl*、glu*、wgl* 函數,直接 uses OpenGL 即可呼叫,參數型別對應:GLfloat=Single, GLint=Integer, GLenum=Cardinal 等。
Delphi 開發 OpenGL 的核心難點不在 OpenGL 本身,而在於正確建立與管理 Windows 圖形子系統資源 (DC/PFD/RC)。掌握 Canvas.Handle 簡化 DC 管理、PFD 旗標組合對相容性的影響、RC 生命週期綁定視窗生命週期,即可避開 90% 的初始化坑,專心投入 3D 場景開發。