You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Delphi与OpenGL基础应用问题:窗体未显示预期深色背景

Delphi 10.4 OpenGL 2D绘图无显示问题

我用Delphi 10.4开发结合OpenGL的基础应用,要在屏幕上绘制2D图像。代码运行无报错,但窗体始终是灰色,没出现预期的深绿色背景。已在IDE和独立程序测试,Windows 10系统,确认System32里有opengl32.dll。请问问题出在哪?

原代码

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, OpenGL;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormPaint(Sender: TObject);
    procedure FormResize(Sender: TObject);
  private
    { Private declarations }
    GLContext : HGLRC;
    glDC: HDC;
    errorCode: GLenum;
    openGLReady: Boolean;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var
  pfd: TPixelFormatDescriptor;
  FormatIndex: Integer;
begin
  FillChar(pfd,SizeOf(pfd),0);
  with pfd do
  begin
    nSize := SizeOf(pfd);
    nVersion := 1; {The current version of the desccriptor is 1}
    dwFlags := PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL;
    iPixelType := PFD_TYPE_RGBA;
    cColorBits := 24; {support 24-bit color}
    cDepthBits := 32; {depth of z-axis}
    iLayerType := PFD_MAIN_PLANE;
  end;
  glDC := getDC(handle);
  FormatIndex := ChoosePixelFormat(glDC,@pfd);
  SetPixelFormat(glDC,FormatIndex,@pfd);
  GLContext := wglCreateContext(glDC);
  wglMakeCurrent(glDC,GLContext);
  OpenGLReady := true;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  wglMakeCurrent(Canvas.Handle,0);
  wglDeleteContext(GLContext);
end;

procedure TForm1.FormPaint(Sender: TObject);
begin
  if not openGLReady then
    exit;
  {background}
  glClearColor(0.1,0.0,0.1,0.0);
  glClear(GL_COLOR_BUFFER_BIT);
  glLoadIdentity; // Reset The View
  glTranslatef(0.0, 0, 0.0);
  glRotateF (360, 0.0, 0.0, 1.0);
  glBegin( GL_POLYGON ); // start drawing a polygon
    glColor3f( 1.0, 0.0, 0.0);
    glVertex3f( 0.0, 0.5, 0.0 ); // Top
    glColor3f(0.0, 1.0, 0.0);
    glVertex3f( 0.5, -0.5, 0.0 ); // Bottom Right
    glColor3f(0.0, 0.0, 1.0);
    glVertex3f( -0.5, -0.5, 0.0 ); // Bottom Left
  glEnd;
  glFlush;
  {error checking}
  errorCode:=glGetError;
   if errorCode<>GL_NO_ERROR then
      raise Exception.Create('Error in Paint'#13+gluErrorString(errorCode));
  SwapBuffers(wglGetCurrentDC);
  glFlush();
end;

procedure TForm1.FormResize(Sender: TObject);
begin
  if not openGLReady then
  exit;
  glViewPort(0,0,ClientWidth,ClientHeight);
  glOrtho(-1.0,1.0,-1.0,1.0,-1.0,1.0);
  errorCode := glGetError;
  if errorCode<>GL_NO_ERROR then
  raise Exception.Create('FormResize:'+gluErrorString(errorCode));
end;

procedure GLInit;
begin
  // set viewing projection
  glMatrixMode(GL_PROJECTION);
  glFrustum(-0.1, 0.1, -0.1, 0.1, 0.3, 15.0);
  // position viewer
  glMatrixMode(GL_MODELVIEW);
  glEnable(GL_DEPTH_TEST);
end;

end.

问题分析与修正方案

你的代码存在多处细节错误,导致OpenGL绘制内容无法正常显示:

  1. 初始化函数未调用
    定义了GLInit用于设置投影矩阵,但从未在FormCreate中调用,导致OpenGL矩阵状态异常,绘制内容不在可视区域。
    修正:在wglMakeCurrent后添加GLInit;调用。

  2. 销毁上下文时DC错误
    FormDestroy中使用Canvas.Handle作为DC来释放上下文,应该用创建时保存的glDC,否则会导致上下文清理异常。
    修正:

    procedure TForm1.FormDestroy(Sender: TObject);
    begin
      wglMakeCurrent(glDC, 0);
      wglDeleteContext(GLContext);
    end;
    
  3. glViewport拼写错误
    FormResize中的glViewPort是笔误,正确函数名是glViewport(小写p),这个错误会导致视口设置失败,内容无法映射到窗体。
    同时设置glOrtho前需要切换到投影矩阵并重置,否则会叠加之前的矩阵变换:
    修正:

    procedure TForm1.FormResize(Sender: TObject);
    begin
      if not openGLReady then exit;
      glViewport(0,0,ClientWidth,ClientHeight);
      glMatrixMode(GL_PROJECTION);
      glLoadIdentity;
      glOrtho(-1.0,1.0,-1.0,1.0,-1.0,1.0);
      glMatrixMode(GL_MODELVIEW);
      errorCode := glGetError;
      if errorCode<>GL_NO_ERROR then
        raise Exception.Create('FormResize:'+gluErrorString(errorCode));
    end;
    
  4. SwapBuffers与glFlush冗余/错误
    FormPaint中重复调用glFlush,且SwapBuffers使用wglGetCurrentDC不如直接用保存的glDC可靠,应该只在交换缓冲区前或后调用一次glFlush。同时要清空深度缓冲区,避免绘制被遮挡:
    修正:

    procedure TForm1.FormPaint(Sender: TObject);
    begin
      if not openGLReady then exit;
      glClearColor(0.1,0.0,0.1,0.0);
      glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
      glLoadIdentity;
      glTranslatef(0.0, 0, 0.0);
      glRotateF (360, 0.0, 0.0, 1.0);
      glBegin( GL_POLYGON );
        glColor3f( 1.0, 0.0, 0.0);
        glVertex3f( 0.0, 0.5, 0.0 );
        glColor3f(0.0, 1.0, 0.0);
        glVertex3f( 0.5, -0.5, 0.0 );
        glColor3f(0.0, 0.0, 1.0);
        glVertex3f( -0.5, -0.5, 0.0 );
      glEnd;
      errorCode:=glGetError;
      if errorCode<>GL_NO_ERROR then
        raise Exception.Create('Error in Paint'#13+gluErrorString(errorCode));
      glFlush;
      SwapBuffers(glDC);
    end;
    
  5. 深度缓冲区冲突
    你请求了32位深度缓冲区,且GLInit启用了GL_DEPTH_TEST,但2D绘图不需要深度测试,若为纯2D应用,可以在GLInit中去掉glEnable(GL_DEPTH_TEST),减少不必要的性能开销。

额外建议

  • 2D绘图时,GLInit中的glFrustum(透视投影)可以替换为glOrtho(正交投影),更符合2D场景需求。
  • 每次矩阵操作后记得切换回GL_MODELVIEW矩阵,避免后续绘制使用错误的矩阵模式。

内容的提问来源于stack exchange,提问作者brane

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 15:25:34