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

Delphi中OpenGL绘制Quad时窗体其余区域变黑的解决求助

解决方案:保留VCL窗体背景,仅在指定区域绘制OpenGL内容

核心问题分析

  • glClear 全清缓冲区:初始代码直接执行全窗口清除操作,覆盖了VCL绘制的窗体背景。
  • OpenGL与GDI不兼容:创建上下文时未启用GDI支持,导致VCL的GDI绘制(如背景图)无法与OpenGL内容共存。
  • Scissor Test 顺序错误:全清操作在裁剪测试启用前执行,无法保留非绘制区域的背景。

分步解决

1. 修改OpenGL上下文创建参数

添加PFD_SUPPORT_GDI标志,允许OpenGL与VCL的GDI绘制共享窗口:

procedure TForm1.FormCreate(Sender: TObject);
var
  pfd: TPixelFormatDescriptor;
  PixelFormat: Integer;
begin
  DC := GetDC(Handle);

  ZeroMemory(@pfd, SizeOf(pfd));
  pfd.nSize := SizeOf(pfd);
  pfd.nVersion := 1;
  // 新增PFD_SUPPORT_GDI启用GDI兼容
  pfd.dwFlags := PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER or PFD_SUPPORT_GDI;
  pfd.iPixelType := PFD_TYPE_RGBA;
  pfd.cColorBits := 24;
  pfd.cDepthBits := 16;
  pfd.iLayerType := PFD_MAIN_PLANE;

  PixelFormat := ChoosePixelFormat(DC, @pfd);
  SetPixelFormat(DC, PixelFormat, @pfd);

  RC := wglCreateContext(DC);
  wglMakeCurrent(DC, RC);
end;

2. 调整FormPaint逻辑,保留VCL背景

先让VCL完成背景绘制,再仅清除并绘制指定OpenGL区域,同时修正坐标匹配(VCL原点在左上角,OpenGL默认在左下角):

procedure TForm1.FormPaint(Sender: TObject);
var
  QuadX, QuadY, QuadSize: Integer;
begin
  // 优先让VCL绘制窗体背景(含自定义背景图)
  inherited;

  // 切换到OpenGL上下文
  wglMakeCurrent(DC, RC);

  // 定义中心Quad的位置与尺寸
  QuadSize := 100;
  QuadX := (ClientWidth - QuadSize) div 2;
  QuadY := (ClientHeight - QuadSize) div 2;

  // 启用裁剪测试,仅操作目标区域
  glEnable(GL_SCISSOR_TEST);
  // 转换OpenGL y轴坐标(匹配VCL左上角原点)
  glScissor(QuadX, ClientHeight - QuadY - QuadSize, QuadSize, QuadSize);

  // 仅清除裁剪区域的颜色缓冲区
  glClear(GL_COLOR_BUFFER_BIT);

  // 设置投影矩阵,对齐VCL坐标系统
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(0, ClientWidth, ClientHeight, 0, -1, 1);

  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();

  // 绘制红色Quad
  glColor3f(1.0, 0.0, 0.0);
  glBegin(GL_QUADS);
    glVertex2i(QuadX, QuadY);
    glVertex2i(QuadX, QuadY + QuadSize);
    glVertex2i(QuadX + QuadSize, QuadY + QuadSize);
    glVertex2i(QuadX + QuadSize, QuadY);
  glEnd();

  glDisable(GL_SCISSOR_TEST);

  // 交换缓冲区显示OpenGL内容
  SwapBuffers(DC);
end;

3. 全屏与背景设置

在DFM中配置窗体属性:

  • BorderStyle = bsNone
  • WindowState = wsMaximized
  • 通过Brush.Bitmap设置自定义背景图

4. 多帧率动画实现建议

使用两个独立TTimer分别控制不同区域的帧率:

  • 中心动画Timer:Interval = 16(约60FPS),仅清除并更新中心Quad区域
  • 顶部动画Timer:Interval = 50(约20FPS),通过Scissor Test限制绘制范围为顶部区域

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 01:18:04