OpenGL快速闪烁问题 - 现在还没有显示图像

时间:2012-05-24 00:03:15

标签: delphi opengl delphi-xe2 flicker

我在使用OpenGL时遇到了一些麻烦。首先,我有一个自定义控件,我正在构建,封装OpenGL。我有一个问题,它会迅速闪烁,就像它闪烁一样。这里的控件太大而且复杂,因此我制作了一个新的小型演示应用程序来演示和重新创建相同的场景。

现在的问题是:我没有得到任何图片。事情会在我的自定义控件中显示得很好,但是由于我已经复制了代码并在一个小型演示应用程序中将其删除,因此它无法显示图像。所以这里我有两个问题:闪烁(或闪烁),现在图像甚至没有显示。过去没有发生闪烁,但经过一些主要的代码修改后,它开始闪烁。代码改变太多了,无法解释究竟是什么改变了,几乎所有内容。

背景显示,所以我知道它画了一些东西(它是彩色的)。为了演示目的,它应该只绘制一个立方体,但我什么都看不到。我不得不从大约1,000行代码中删除它甚至不到300行。

这不是你通常称之为闪烁的东西,它实际上更像闪烁,或闪烁,想象一下汽车闪光灯闪烁。这肯定与计时器有关,因为我在计时器上放置的间隔越大,它闪烁的越慢。

为什么我什么都没看到?一旦修复了,它为什么会闪烁这么多?

这是一个单一的表格代码,没有必要的DFM:

unit uMain;

interface

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

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure FormResize(Sender: TObject);
  private
    FDrawing: Bool;
    FDC: HDC;
    FRC: HGLRC;
    FDL: glUint;
    FTimer: TTimer;
    procedure Draw;
    procedure SetDC(const Value: HDC);
    procedure SetRC(const Value: HGLRC);
    procedure SetDL(const Value: glUint);
  public
    property DC: HDC read FDC write SetDC;
    property RC: HGLRC read FRC write SetRC;
    property DL: glUint read FDL write SetDL;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var
  PixelFormat: glUint;
  pfd: TPIXELFORMATDESCRIPTOR;
begin
  FDrawing := False;
  FDC := GetDC(Handle);
  with pfd do begin
    nSize := SizeOf(TPIXELFORMATDESCRIPTOR);
    nVersion := 1; // The version of this data structure
    dwFlags := PFD_DRAW_TO_WINDOW // Buffer supports drawing to window
      or PFD_SUPPORT_OPENGL // Buffer supports OpenGL drawing
      or PFD_DOUBLEBUFFER; // Supports double buffering
    iPixelType := PFD_TYPE_RGBA; // RGBA color format
    cColorBits := 32; // OpenGL color depth
    cRedBits := 0; // Number of red bitplanes
    cRedShift := 0; // Shift count for red bitplanes
    cGreenBits := 0; // Number of green bitplanes
    cGreenShift := 0; // Shift count for green bitplanes
    cBlueBits := 0; // Number of blue bitplanes
    cBlueShift := 0; // Shift count for blue bitplanes
    cAlphaBits := 0; // Not supported
    cAlphaShift := 0; // Not supported
    cAccumBits := 0; // No accumulation buffer
    cAccumRedBits := 0; // Number of red bits in a-buffer
    cAccumGreenBits := 0; // Number of green bits in a-buffer
    cAccumBlueBits := 0; // Number of blue bits in a-buffer
    cAccumAlphaBits := 0; // Number of alpha bits in a-buffer
    cDepthBits := 16; // Specifies the depth of the depth buffer
    cStencilBits := 0; // Turn off stencil buffer
    cAuxBuffers := 0; // Not supported
    iLayerType := PFD_MAIN_PLANE; // Ignored
    bReserved := 0; // Number of overlay and underlay planes
    dwLayerMask := 0; // Ignored
    dwVisibleMask := 0; // Transparent color of underlay plane
    dwDamageMask := 0; // Ignored
  end;
  PixelFormat := ChoosePixelFormat(FDC, @pfd);
  SetPixelFormat(FDC, PixelFormat, @pfd);
  FRC := wglCreateContext(FDC);
  wglMakeCurrent(FDC, FRC);
  FormResize(nil);
  wglMakeCurrent(FDC, FRC);
  glClearColor(0.8, 0.8, 0.9, 0.0);
  glShadeModel(GL_FLAT);
  glClearDepth(1.0);
  glEnable(GL_DEPTH_TEST);
  glDepthFunc(GL_LESS);
  glEnable(GL_ALPHA_TEST);
  glAlphaFunc(GL_GREATER, 0.4);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glEnable(GL_BLEND);
  glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
  glEnable(GL_TEXTURE_2D);
  glNewList(FDL, GL_COMPILE);
    glBegin(GL_QUADS);
      // Front Face
      glTexCoord2f(0.0, 0.0);
      glVertex3f(-2.0, -1.0, 1.0);
      glTexCoord2f(2.0, 0.0);
      glVertex3f(2.0, -1.0, 1.0);
      glTexCoord2f(2.0, 1.0);
      glVertex3f(2.0, 1.0, 1.0);
      glTexCoord2f(0.0, 1.0);
      glVertex3f(-2.0, 1.0, 1.0);
      // Back Face
      glTexCoord2f(2.0, 0.0);
      glVertex3f(-2.0, -1.0, -1.0);
      glTexCoord2f(2.0, 1.0);
      glVertex3f(-2.0, 1.0, -1.0);
      glTexCoord2f(0.0, 1.0);
      glVertex3f(2.0, 1.0, -1.0);
      glTexCoord2f(0.0, 0.0);
      glVertex3f(2.0, -1.0, -1.0);
      // Top Face
      glTexCoord2f(0.0, 1.0);
      glVertex3f(-2.0, 1.0, -1.0);
      glTexCoord2f(0.0, 0.0);
      glVertex3f(-2.0, 1.0, 1.0);
      glTexCoord2f(2.0, 0.0);
      glVertex3f(2.0, 1.0, 1.0);
      glTexCoord2f(2.0, 1.0);
      glVertex3f(2.0, 1.0, -1.0);
      // Bottom Face
      glTexCoord2f(2.0, 1.0);
      glVertex3f(-2.0, -1.0, -1.0);
      glTexCoord2f(0.0, 1.0);
      glVertex3f(2.0, -1.0, -1.0);
      glTexCoord2f(0.0, 0.0);
      glVertex3f(2.0, -1.0, 1.0);
      glTexCoord2f(2.0, 0.0);
      glVertex3f(-2.0, -1.0, 1.0);
      // Left Face
      glTexCoord2f(0.0, 0.0);
      glVertex3f(2.0, -1.0, -1.0);
      glTexCoord2f(1.0, 0.0);
      glVertex3f(2.0, -1.0, 1.0);
      glTexCoord2f(1.0, 1.0);
      glVertex3f(2.0, 1.0, 1.0);
      glTexCoord2f(0.0, 1.0);
      glVertex3f(2.0, 1.0, -1.0);
    glEnd();
  glEndList();
  FTimer:= TTimer.Create(nil);
  FTimer.OnTimer:= Timer1Timer;
  FTimer.Interval:= 100;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FTimer.Free;
  if (not wglMakeCurrent(FDC, 0)) then
    MessageBox(0, 'Release of DC and RC failed!', 'Error', MB_OK or MB_ICONERROR);
  if (not wglDeleteContext(FRC)) then begin
    MessageBox(0, 'Release of rendering context failed!', 'Error', MB_OK or MB_ICONERROR);
    FRC := 0;
  end;
  if ((FDC > 0) and (ReleaseDC(Handle, FDC) = 0)) then begin
    MessageBox(0, 'Release of device context failed!', 'Error', MB_OK or MB_ICONERROR);
    FDC := 0;
  end;
end;

procedure TForm1.Draw;
var
  I: Integer;
begin
  if not FDrawing then begin
    FDrawing := TRUE;
    try
      glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
      glEnable(GL_NORMALIZE);
      glShadeModel(GL_FLAT);
      glCullFace(GL_BACK);
      glLoadIdentity;
      glPushMatrix();
      glCallList(DL);
      glPopMatrix();
      SwapBuffers(wglGetCurrentDC);
    finally
      FDrawing := False;
    end;
  end;
end;

procedure TForm1.FormResize(Sender: TObject);
begin
  glViewport(0, 0, Width, Height);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(45.0, Width / Height, 0.1, 500.0);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
end;

procedure TForm1.SetDC(const Value: HDC);
begin
  FDC := Value;
end;

procedure TForm1.SetDL(const Value: glUint);
begin
  FDL := Value;
end;

procedure TForm1.SetRC(const Value: HGLRC);
begin
  FRC := Value;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  Draw;
end;

end.

现在上面的代码与原始代码的工作方式有很大不同。原始Draw过程通过对象列表进行迭代,每个对象包含自己的Draw过程。因此,控制的绘制程序准备整个场景,然后绘制每个项目'一个接一个,像这样:

procedure TGLImage.Draw;
var
  X: Integer;
begin
  if not FDrawing then begin
    FDrawing := TRUE;
    try
      glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
      glEnable(GL_NORMALIZE);
      glShadeModel(GL_FLAT);
      glCullFace(GL_BACK);
      glLoadIdentity();

      glRotatef(FElapsedTime / 70, 0, 0, 1);
      glRotatef(90, 0, 1, 0);
      glTranslatef(-FElapsedTime / 400, 0, 0);

      if FInitialized then begin
        for X := 0 to FItems.Count - 1 do begin
          FItems[X].Draw;
        end;
      end;

      SwapBuffers(wglGetCurrentDC);
    finally
      FDrawing := False;
    end;
  end;
end;

这是它绘制的一个项目......

constructor TGLBeam.Create(AOwner: TGLItems);
begin
  inherited;
  glNewList(DL, GL_COMPILE);
    glBegin(GL_QUADS);
      // Front Face
      glTexCoord2f(0.0, 0.0);
      glVertex3f(-2.0, -1.0, 1.0);
      glTexCoord2f(2.0, 0.0);
      glVertex3f(2.0, -1.0, 1.0);
      glTexCoord2f(2.0, 1.0);
      glVertex3f(2.0, 1.0, 1.0);
      glTexCoord2f(0.0, 1.0);
      glVertex3f(-2.0, 1.0, 1.0);
      // Back Face
      glTexCoord2f(2.0, 0.0);
      glVertex3f(-2.0, -1.0, -1.0);
      glTexCoord2f(2.0, 1.0);
      glVertex3f(-2.0, 1.0, -1.0);
      glTexCoord2f(0.0, 1.0);
      glVertex3f(2.0, 1.0, -1.0);
      glTexCoord2f(0.0, 0.0);
      glVertex3f(2.0, -1.0, -1.0);
      // Top Face
      glTexCoord2f(0.0, 1.0);
      glVertex3f(-2.0, 1.0, -1.0);
      glTexCoord2f(0.0, 0.0);
      glVertex3f(-2.0, 1.0, 1.0);
      glTexCoord2f(2.0, 0.0);
      glVertex3f(2.0, 1.0, 1.0);
      glTexCoord2f(2.0, 1.0);
      glVertex3f(2.0, 1.0, -1.0);
      // Bottom Face
      glTexCoord2f(2.0, 1.0);
      glVertex3f(-2.0, -1.0, -1.0);
      glTexCoord2f(0.0, 1.0);
      glVertex3f(2.0, -1.0, -1.0);
      glTexCoord2f(0.0, 0.0);
      glVertex3f(2.0, -1.0, 1.0);
      glTexCoord2f(2.0, 0.0);
      glVertex3f(-2.0, -1.0, 1.0);
      // Left Face
      glTexCoord2f(0.0, 0.0);
      glVertex3f(2.0, -1.0, -1.0);
      glTexCoord2f(1.0, 0.0);
      glVertex3f(2.0, -1.0, 1.0);
      glTexCoord2f(1.0, 1.0);
      glVertex3f(2.0, 1.0, 1.0);
      glTexCoord2f(0.0, 1.0);
      glVertex3f(2.0, 1.0, -1.0);
    glEnd();
  glEndList();
end;

procedure TGLBeam.Draw;
var
  I: Integer;
begin
  glRotatef(Directions.X, 1.0, 0.0, 0.0);
  glRotatef(Directions.Y, 0.0, 1.0, 0.0);
  glRotatef(Directions.Z, 0.0, 0.0, 1.0);
  for I := 1 to 10 do begin
    //Main Center
    glPushMatrix();
    glTranslatef(I * 4 + Owner.Owner.ClockTime * 4, 0, 0);
    glCallList(DL);
    glPopMatrix();
    //Above
    glPushMatrix();
    glTranslatef(I * 4 + Owner.Owner.ClockTime * 4, 6, 0);
    glCallList(DL);
    glPopMatrix();
  end;
end;

2 个答案:

答案 0 :(得分:1)

glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
glEnable(GL_NORMALIZE);
glShadeModel(GL_FLAT);
glCullFace(GL_BACK);
glLoadIdentity;
glPushMatrix();
glCallList(DL);
glPopMatrix();
SwapBuffers(wglGetCurrentDC);

首先将()添加到您对glLoadIdentity

的调用中

加载单位矩阵然后按下它然后渲染并弹出它而不实际进行任何变换。

删除3行

glLoadIdentity;
glPushMatrix();

glPopMatrix();

或将glPushMatrix()移至glLoadIdentity()

之前的行

我还建议关闭阴影和剔除,以确保它们不会干扰。即使你不希望它们从前面剔除,也会以略微错误的顺序声明四边形,背面剔除它们就会剔除它们。

答案 1 :(得分:0)

闪烁的问题已经被发现,这是一个非常大的错误,我不希望你在没有整个项目的情况下想出来。问题是我正在创建 TWO 这些控件,他们互相干扰/打架。实际上,因为OpenGL在逐个线程的基础上工作(或在一个'上下文'中),有两个不同的控件试图做他们自己的绘图会干扰 - 导致同时在两个控件上发生同样的事情。因此,闪光是因为每个控件都试图轮流进行绘图。我提出的关于将这个绘图放在一个Thread中的新问题将完全解决这个问题。这是一个愚蠢的错误,我很抱歉浪费任何人的时间。